зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to central, a=merge
UPGRADE_NSS_RELEASE MozReview-Commit-ID: 9BuuGYyJ3RJ --HG-- extra : amend_source : 57de84460e0ace13892ff1623451b9b9be8eaeeb
This commit is contained in:
Коммит
0a5ec26ac6
|
@ -157,7 +157,7 @@ browser.jar:
|
|||
* content/browser/hiddenWindow.xul (content/hiddenWindow.xul)
|
||||
#ifdef XP_MACOSX
|
||||
* content/browser/macBrowserOverlay.xul (content/macBrowserOverlay.xul)
|
||||
* content/browser/softwareUpdateOverlay.xul (content/softwareUpdateOverlay.xul)
|
||||
* content/browser/softwareUpdateOverlay.xul (content/softwareUpdateOverlay.xul)
|
||||
#endif
|
||||
* content/browser/viewSourceOverlay.xul (content/viewSourceOverlay.xul)
|
||||
#ifndef XP_MACOSX
|
||||
|
|
|
@ -7,3 +7,4 @@ support-files =
|
|||
[browser_disabled_cleanup.js]
|
||||
[browser_button_state.js]
|
||||
[browser_report_site_issue.js]
|
||||
skip-if = !e10s && (os == "linux" && (debug || asan))
|
||||
|
|
|
@ -268,7 +268,7 @@ menuitem.bookmark-item {
|
|||
#main-window {
|
||||
--urlbar-border-color: ThreeDShadow;
|
||||
--urlbar-border-color-hover: var(--urlbar-border-color);
|
||||
--urlbar-background-color: moz-field;
|
||||
--urlbar-background-color: -moz-field;
|
||||
}
|
||||
|
||||
#navigator-toolbox:-moz-lwtheme {
|
||||
|
|
|
@ -14,9 +14,17 @@
|
|||
margin: 0 2px;
|
||||
}
|
||||
|
||||
#urlbar:-moz-lwtheme:not(:hover):not([focused="true"]),
|
||||
.searchbar-textbox:-moz-lwtheme:not(:hover):not([focused="true"]) {
|
||||
background-color: hsla(0, 100%, 100%, .8);
|
||||
#urlbar:-moz-lwtheme,
|
||||
.searchbar-textbox:-moz-lwtheme {
|
||||
background-color: hsla(0,0%,100%,.8);
|
||||
color: black;
|
||||
}
|
||||
|
||||
#urlbar:-moz-lwtheme:hover,
|
||||
#urlbar:-moz-lwtheme[focused="true"],
|
||||
.searchbar-textbox:-moz-lwtheme:hover,
|
||||
.searchbar-textbox:-moz-lwtheme[focused="true"] {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#urlbar:hover,
|
||||
|
|
|
@ -104,6 +104,8 @@ def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell,
|
|||
shell, autoconf,
|
||||
'--localdir=%s' % os.path.dirname(old_configure),
|
||||
old_configure + '.in'])
|
||||
if not script:
|
||||
die('Generated old-configure is empty! Check that your autoconf 2.13 program works!')
|
||||
|
||||
# Make old-configure append to config.log, where we put our own log.
|
||||
# This could be done with a m4 macro, but it's way easier this way
|
||||
|
|
|
@ -64,6 +64,8 @@ included_inclnames_to_ignore = set([
|
|||
'double-conversion.h', # strange MFBT case
|
||||
'javascript-trace.h', # generated in $OBJDIR if HAVE_DTRACE is defined
|
||||
'frontend/ReservedWordsGenerated.h', # generated in $OBJDIR
|
||||
'gc/StatsPhasesGenerated.h', # generated in $OBJDIR
|
||||
'gc/StatsPhasesGenerated.cpp', # generated in $OBJDIR
|
||||
'jscustomallocator.h', # provided by embedders; allowed to be missing
|
||||
'js-config.h', # generated in $OBJDIR
|
||||
'fdlibm.h', # fdlibm
|
||||
|
@ -104,6 +106,8 @@ included_inclnames_to_ignore = set([
|
|||
oddly_ordered_inclnames = set([
|
||||
'ctypes/typedefs.h', # Included multiple times in the body of ctypes/CTypes.h
|
||||
'frontend/ReservedWordsGenerated.h', # Included in the body of frontend/TokenStream.h
|
||||
'gc/StatsPhasesGenerated.h', # Included in the body of gc/Statistics.h
|
||||
'gc/StatsPhasesGenerated.cpp', # Included in the body of gc/Statistics.cpp
|
||||
'jswin.h', # Must be #included before <psapi.h>
|
||||
'machine/endian.h', # Must be included after <sys/types.h> on BSD
|
||||
'winbase.h', # Must precede other system headers(?)
|
||||
|
|
|
@ -31,5 +31,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
|||
[browser_jsonview_invalid_json.js]
|
||||
[browser_jsonview_valid_json.js]
|
||||
[browser_jsonview_save_json.js]
|
||||
support-files =
|
||||
!/toolkit/content/tests/browser/common/mockTransfer.js
|
||||
[browser_jsonview_manifest.js]
|
||||
[browser_json_refresh.js]
|
||||
|
|
|
@ -1,38 +1,143 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* eslint-disable no-unused-vars, no-undef */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_JSON_URL = URL_ROOT + "valid_json.json";
|
||||
const JSON_FILE = "simple_json.json";
|
||||
const TEST_JSON_URL = URL_ROOT + JSON_FILE;
|
||||
const rawdataTab = ".rawdata > a";
|
||||
const saveButton = "button.save";
|
||||
const prettifyButton = "button.prettyprint";
|
||||
|
||||
let { MockFilePicker } = SpecialPowers;
|
||||
|
||||
MockFilePicker.init(window);
|
||||
MockFilePicker.returnValue = MockFilePicker.returnCancel;
|
||||
MockFilePicker.returnValue = MockFilePicker.returnOK;
|
||||
|
||||
Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
|
||||
this);
|
||||
|
||||
function click(selector) {
|
||||
return BrowserTestUtils.synthesizeMouseAtCenter(selector, {}, gBrowser.selectedBrowser);
|
||||
}
|
||||
|
||||
function rightClick(selector) {
|
||||
return BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
selector,
|
||||
{type: "contextmenu", button: 2},
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
}
|
||||
|
||||
function awaitFileSave() {
|
||||
return new Promise((resolve) => {
|
||||
MockFilePicker.showCallback = (fp) => {
|
||||
ok(true, "File picker was opened");
|
||||
let fileName = fp.defaultString;
|
||||
is(fileName, JSON_FILE, "File picker should provide the correct default filename.");
|
||||
let destFile = destDir.clone();
|
||||
destFile.append(fileName);
|
||||
MockFilePicker.setFiles([destFile]);
|
||||
MockFilePicker.showCallback = null;
|
||||
mockTransferCallback = function (downloadSuccess) {
|
||||
ok(downloadSuccess, "JSON should have been downloaded successfully");
|
||||
ok(destFile.exists(), "The downloaded file should exist.");
|
||||
resolve(destFile);
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getFileContents(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
NetUtil.asyncFetch(file, function (inputStream, status) {
|
||||
if (Components.isSuccessCode(status)) {
|
||||
info("Fetched downloaded contents.");
|
||||
resolve(NetUtil.readInputStreamToString(inputStream, inputStream.available()));
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createTemporarySaveDirectory() {
|
||||
let saveDir = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties)
|
||||
.get("TmpD", Ci.nsIFile);
|
||||
saveDir.append("jsonview-testsavedir");
|
||||
if (!saveDir.exists()) {
|
||||
info("Creating temporary save directory.");
|
||||
saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
|
||||
}
|
||||
info("Temporary save directory: " + saveDir.path);
|
||||
return saveDir;
|
||||
}
|
||||
|
||||
let destDir = createTemporarySaveDirectory();
|
||||
mockTransferRegisterer.register();
|
||||
MockFilePicker.displayDirectory = destDir;
|
||||
registerCleanupFunction(function () {
|
||||
mockTransferRegisterer.unregister();
|
||||
MockFilePicker.cleanup();
|
||||
destDir.remove(true);
|
||||
ok(!destDir.exists(), "Destination dir should be removed");
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
info("Test save JSON started");
|
||||
|
||||
yield addJsonViewTab(TEST_JSON_URL);
|
||||
|
||||
let promise = new Promise((resolve) => {
|
||||
MockFilePicker.showCallback = () => {
|
||||
MockFilePicker.showCallback = null;
|
||||
ok(true, "File picker was opened");
|
||||
let promise, rawJSON, prettyJSON;
|
||||
yield fetch(new Request(TEST_JSON_URL))
|
||||
.then(response => response.text())
|
||||
.then(function (data) {
|
||||
info("Fetched JSON contents.");
|
||||
rawJSON = data;
|
||||
prettyJSON = JSON.stringify(JSON.parse(data), null, " ");
|
||||
});
|
||||
|
||||
// Attempt to save original JSON via "Save As" command
|
||||
promise = awaitFileSave();
|
||||
yield new Promise((resolve) => {
|
||||
info("Register to handle popupshown.");
|
||||
document.addEventListener("popupshown", function (event) {
|
||||
info("Context menu opened.");
|
||||
let savePageCommand = document.getElementById("context-savepage");
|
||||
savePageCommand.doCommand();
|
||||
info("SavePage command done.");
|
||||
event.target.hidePopup();
|
||||
info("Context menu hidden.");
|
||||
resolve();
|
||||
};
|
||||
}, {once: true});
|
||||
rightClick("body");
|
||||
info("Right clicked.");
|
||||
});
|
||||
yield promise.then(getFileContents).then(function (data) {
|
||||
is(data, rawJSON, "Original JSON contents should have been saved.");
|
||||
});
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
".jsonPanelBox button.save",
|
||||
{}, browser);
|
||||
// Attempt to save original JSON via "Save" button
|
||||
promise = awaitFileSave();
|
||||
yield click(saveButton);
|
||||
info("Clicked Save button.");
|
||||
yield promise.then(getFileContents).then(function (data) {
|
||||
is(data, rawJSON, "Original JSON contents should have been saved.");
|
||||
});
|
||||
|
||||
yield promise;
|
||||
// Attempt to save prettified JSON via "Save" button
|
||||
yield click(rawdataTab);
|
||||
info("Switched to Raw Data tab.");
|
||||
yield click(prettifyButton);
|
||||
info("Clicked Pretty Print button.");
|
||||
promise = awaitFileSave();
|
||||
yield click(saveButton);
|
||||
info("Clicked Save button.");
|
||||
yield promise.then(getFileContents).then(function (data) {
|
||||
is(data, prettyJSON, "Prettified JSON contents should have been saved.");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,6 +7,8 @@ support-files =
|
|||
[test_notification_box_01.html]
|
||||
[test_notification_box_02.html]
|
||||
[test_notification_box_03.html]
|
||||
[test_searchbox.html]
|
||||
[test_searchbox-with-autocomplete.html]
|
||||
[test_sidebar_toggle.html]
|
||||
[test_stack-trace.html]
|
||||
[test_tabs_accessibility.html]
|
||||
|
|
|
@ -211,3 +211,25 @@ function shallowRenderComponent(component, props) {
|
|||
renderer.render(el, {});
|
||||
return renderer.getRenderOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a React Component for testing
|
||||
*
|
||||
* @param {string} factory - factory object of the component to be created
|
||||
* @param {object} props - React props for the component
|
||||
* @returns {object} - container Node, Object with React component
|
||||
* and querySelector function with $ as name.
|
||||
*/
|
||||
async function createComponentTest(factory, props) {
|
||||
const container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
|
||||
const component = ReactDOM.render(factory(props), container);
|
||||
await forceRender(component);
|
||||
|
||||
return {
|
||||
container,
|
||||
component,
|
||||
$: (s) => container.querySelector(s),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
<!-- 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/. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Test the searchbox and autocomplete-popup components
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SearchBox component test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script src="head.js"></script>
|
||||
<script>
|
||||
/* import-globals-from head.js */
|
||||
"use strict";
|
||||
window.onload = async function () {
|
||||
/**
|
||||
* Takes a DOMNode with its children as list items,
|
||||
* Typically UL > LI and each item's text value is
|
||||
* compared with the reference item's value as a test
|
||||
*
|
||||
* @params {Node} - Node to be compared
|
||||
* @reference {array} - Reference array for comparison
|
||||
*/
|
||||
function compareAutocompleteList(list, reference) {
|
||||
let items = [...list.children].map(el => el.textContent);
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let item = items[i];
|
||||
let ref = reference[i];
|
||||
is(item, ref, `Item ${i} in list is correct`);
|
||||
}
|
||||
}
|
||||
|
||||
let React = browserRequire("devtools/client/shared/vendor/react");
|
||||
let SearchBox = React.createFactory(
|
||||
browserRequire("devtools/client/shared/components/search-box")
|
||||
);
|
||||
const { component, $ } = await createComponentTest(SearchBox, {
|
||||
type: "search",
|
||||
autocompleteList: [
|
||||
"foo",
|
||||
"BAR",
|
||||
"baZ",
|
||||
"abc",
|
||||
"pqr",
|
||||
"xyz",
|
||||
"ABC",
|
||||
],
|
||||
onChange: () => null,
|
||||
});
|
||||
const { refs } = component;
|
||||
|
||||
async function testSearchBoxWithAutocomplete() {
|
||||
ok(!$(".devtools-autocomplete-popup"), "Autocomplete list not visible");
|
||||
|
||||
$(".devtools-searchinput").focus();
|
||||
await forceRender(component); // Wait for state update
|
||||
|
||||
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
||||
"ABC",
|
||||
"BAR",
|
||||
"abc",
|
||||
"baZ",
|
||||
"foo",
|
||||
"pqr",
|
||||
"xyz",
|
||||
]);
|
||||
|
||||
is(refs.autocomplete.state.selectedIndex, -1, "Initialised selectedIndex is -1");
|
||||
|
||||
// Blur event
|
||||
$(".devtools-searchinput").blur();
|
||||
await forceRender(component);
|
||||
ok(!component.state.focused, "focused state was properly set");
|
||||
ok(!$(".devtools-autocomplete-popup"), "Autocomplete list removed from DOM");
|
||||
}
|
||||
|
||||
async function testKeyEventsWithAutocomplete() {
|
||||
// Filtering of list
|
||||
$(".devtools-searchinput").focus();
|
||||
await forceRender(component);
|
||||
sendString("aB");
|
||||
await forceRender(component);
|
||||
compareAutocompleteList($(".devtools-autocomplete-listbox"), ["ABC", "abc"]);
|
||||
|
||||
// Clear the initial input
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
|
||||
// ArrowDown
|
||||
synthesizeKey("VK_DOWN", {});
|
||||
await forceRender(component);
|
||||
is(refs.autocomplete.state.selectedIndex, 0, "selectedIndex is 0");
|
||||
ok($(".devtools-autocomplete-listbox .autocomplete-item:nth-child(1)")
|
||||
.className.includes("autocomplete-selected"),
|
||||
"Selection class applied");
|
||||
|
||||
// ArrowUp should roll back to the bottom of the list
|
||||
synthesizeKey("VK_UP", {});
|
||||
await forceRender(component);
|
||||
is(refs.autocomplete.state.selectedIndex, 6, "ArrowUp works");
|
||||
|
||||
// PageDown should take -5 places up
|
||||
synthesizeKey("VK_PAGE_UP", {});
|
||||
await forceRender(component);
|
||||
is(refs.autocomplete.state.selectedIndex, 1, "PageUp works");
|
||||
|
||||
// PageDown should take +5 places down
|
||||
synthesizeKey("VK_PAGE_DOWN", {});
|
||||
await forceRender(component);
|
||||
is(refs.autocomplete.state.selectedIndex, 6, "PageDown works");
|
||||
|
||||
// Home should take to the top of the list
|
||||
synthesizeKey("VK_HOME", {});
|
||||
await forceRender(component);
|
||||
is(refs.autocomplete.state.selectedIndex, 0, "Home works");
|
||||
|
||||
// End should take to the bottom of the list
|
||||
synthesizeKey("VK_END", {});
|
||||
await forceRender(component);
|
||||
is(refs.autocomplete.state.selectedIndex, 6, "End works");
|
||||
|
||||
// Key down in existing state should rollover to the top
|
||||
synthesizeKey("VK_DOWN", {});
|
||||
await forceRender(component);
|
||||
// Tab should select the component and hide popup
|
||||
synthesizeKey("VK_TAB", {});
|
||||
await forceRender(component);
|
||||
is(component.state.value, "ABC", "Tab hit selects the item");
|
||||
ok(!$(".devtools-autocomplete-popup"), "Tab hit hides the popup");
|
||||
|
||||
// Activate popup by removing a key
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
await forceRender(component);
|
||||
ok($(".devtools-autocomplete-popup"), "Popup is up");
|
||||
compareAutocompleteList($(".devtools-autocomplete-listbox"), ["ABC", "abc"]);
|
||||
|
||||
// Enter key selection
|
||||
synthesizeKey("VK_UP", {});
|
||||
await forceRender(component);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
is(component.state.value, "abc", "Enter selection");
|
||||
ok(!$(".devtools-autocomplete-popup"), "Enter/Return hides the popup");
|
||||
|
||||
// Escape should remove the autocomplete component
|
||||
synthesizeKey("VK_ESCAPE", {});
|
||||
await forceRender(component);
|
||||
ok(!$(".devtools-autocomplete-popup"),
|
||||
"Autocomplete list removed from DOM on Escape");
|
||||
}
|
||||
|
||||
async function testMouseEventsWithAutocomplete() {
|
||||
$(".devtools-searchinput").focus();
|
||||
await setState(component, {
|
||||
value: "",
|
||||
focused: true,
|
||||
});
|
||||
await forceRender(component);
|
||||
|
||||
// ArrowDown
|
||||
synthesizeKey("VK_DOWN", {});
|
||||
await forceRender(component);
|
||||
synthesizeMouseAtCenter($(".devtools-searchinput"), {}, window);
|
||||
await forceRender(component);
|
||||
is(component.state.focused, true, "Component should now be focused");
|
||||
|
||||
sendString("pq");
|
||||
await forceRender(component);
|
||||
synthesizeMouseAtCenter(
|
||||
$(".devtools-autocomplete-listbox .autocomplete-item:nth-child(1)"),
|
||||
{}, window
|
||||
);
|
||||
await forceRender(component);
|
||||
is(component.state.value, "pqr", "Mouse click selects the item.");
|
||||
ok(!$(".devtools-autocomplete-popup"), "Mouse click on item hides the popup");
|
||||
}
|
||||
|
||||
add_task(async function () {
|
||||
await testSearchBoxWithAutocomplete();
|
||||
await testKeyEventsWithAutocomplete();
|
||||
await testMouseEventsWithAutocomplete();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,76 @@
|
|||
<!-- 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/. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Test the searchbox component
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SearchBox component test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script src="head.js"></script>
|
||||
<script>
|
||||
/* import-globals-from head.js */
|
||||
"use strict";
|
||||
window.onload = function () {
|
||||
let React = browserRequire("devtools/client/shared/vendor/react");
|
||||
let SearchBox = React.createFactory(
|
||||
browserRequire("devtools/client/shared/components/search-box")
|
||||
);
|
||||
ok(SearchBox, "Got the SearchBox factory");
|
||||
|
||||
async function testSimpleSearchBox() {
|
||||
// Test initial state
|
||||
const { component, $ } = await createComponentTest(SearchBox, {
|
||||
type: "search",
|
||||
keyShortcut: "CmdOrCtrl+F",
|
||||
placeholder: "crazy placeholder",
|
||||
});
|
||||
|
||||
is(component.state.value, "", "Initial value is blank");
|
||||
ok(!component.state.focused, "Input isn't initially focused");
|
||||
ok($(".devtools-searchinput-clear").hidden, "Clear button hidden");
|
||||
is($(".devtools-searchinput").placeholder, "crazy placeholder",
|
||||
"Placeholder is properly set");
|
||||
|
||||
synthesizeKey("f", { accelKey: true });
|
||||
await forceRender(component); // Wait for state update
|
||||
ok(component.state.focused, "Shortcut key focused the input box");
|
||||
|
||||
$(".devtools-searchinput").blur();
|
||||
await forceRender(component);
|
||||
ok(!component.state.focused, "`focused` state set to false after blur");
|
||||
|
||||
// Test changing value in state
|
||||
await setState(component, {
|
||||
value: "foo",
|
||||
});
|
||||
|
||||
is(component.state.value, "foo", "value was properly set on state");
|
||||
is($(".devtools-searchinput").value, "foo", "value was properly set on element");
|
||||
|
||||
// Filling input should show clear button
|
||||
ok(!$(".devtools-searchinput-clear").hidden, "Clear button shown");
|
||||
|
||||
// Clearing value should hide clear button
|
||||
await setState(component, {
|
||||
value: "",
|
||||
});
|
||||
await forceRender(component);
|
||||
ok($(".devtools-searchinput-clear").hidden, "Clear button was hidden");
|
||||
}
|
||||
|
||||
add_task(async function () {
|
||||
await testSimpleSearchBox();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -966,6 +966,9 @@ nsSHEntry::SetLastTouched(uint32_t aLastTouched)
|
|||
NS_IMETHODIMP
|
||||
nsSHEntry::SetSHistory(nsISHistory* aSHistory)
|
||||
{
|
||||
mShared->mSHistory = do_GetWeakReference(aSHistory);
|
||||
nsWeakPtr shistory = do_GetWeakReference(aSHistory);
|
||||
// mSHistory can not be changed once it's set
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mShared->mSHistory || (mShared->mSHistory == shistory));
|
||||
mShared->mSHistory = shistory;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -134,6 +134,10 @@ nsSHEntryShared::SetContentViewer(nsIContentViewer* aViewer)
|
|||
DropPresentationState();
|
||||
}
|
||||
|
||||
// If we're setting mContentViewer to null, state should already be cleared
|
||||
// in the DropPresentationState() call above; If we're setting it to a
|
||||
// non-null content viewer, the entry shouldn't have been tracked either.
|
||||
MOZ_DIAGNOSTIC_ASSERT(!GetExpirationState()->IsTracked());
|
||||
mContentViewer = aViewer;
|
||||
|
||||
if (mContentViewer) {
|
||||
|
|
|
@ -1320,6 +1320,7 @@ NS_IMETHODIMP
|
|||
nsSHistory::RemoveFromExpirationTracker(nsIBFCacheEntry* aEntry)
|
||||
{
|
||||
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aEntry);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mHistoryTracker && !mHistoryTracker->IsEmpty());
|
||||
if (!mHistoryTracker || !entry) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -1927,6 +1928,7 @@ nsSHistory::InitiateLoad(nsISHEntry* aFrameEntry, nsIDocShell* aFrameDS,
|
|||
NS_IMETHODIMP
|
||||
nsSHistory::SetRootDocShell(nsIDocShell* aDocShell)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aDocShell || !mRootDocShell);
|
||||
mRootDocShell = aDocShell;
|
||||
|
||||
// Init mHistoryTracker on setting mRootDocShell so we can bind its event
|
||||
|
@ -1937,6 +1939,8 @@ nsSHistory::SetRootDocShell(nsIDocShell* aDocShell)
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// mHistroyTracker can only be set once.
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mHistoryTracker);
|
||||
RefPtr<mozilla::dom::TabGroup> tabGroup = win->TabGroup();
|
||||
mHistoryTracker = mozilla::MakeUnique<HistoryTracker>(
|
||||
this,
|
||||
|
|
|
@ -843,6 +843,36 @@ function createPseudo(test, element, type) {
|
|||
|
||||
}, "set_iterationComposite");
|
||||
|
||||
test(t => {
|
||||
var div = addDiv(t);
|
||||
var observer =
|
||||
setupSynchronousObserver(t,
|
||||
aOptions.subtree ? div.parentNode : div,
|
||||
aOptions.subtree);
|
||||
|
||||
var anim = div.animate({ opacity: [ 0, 1 ] },
|
||||
{ duration: 100 * MS_PER_SEC });
|
||||
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation is added");
|
||||
|
||||
anim.effect.setKeyframes({ opacity: 0.1 });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [anim], removed: [] }],
|
||||
"records after keyframes are changed");
|
||||
|
||||
anim.effect.setKeyframes({ opacity: 0.1 });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "no record after setting the same keyframes");
|
||||
|
||||
anim.effect.setKeyframes(null);
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [anim], removed: [] }],
|
||||
"records after keyframes are set to empty");
|
||||
|
||||
}, "set_keyframes");
|
||||
|
||||
});
|
||||
|
||||
test(t => {
|
||||
|
|
|
@ -1211,12 +1211,6 @@ Navigator::SendBeaconInternal(const nsAString& aUrl,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (aType == eBeaconTypeArrayBuffer) {
|
||||
MOZ_ASSERT(contentTypeWithCharset.IsEmpty());
|
||||
MOZ_ASSERT(charset.IsEmpty());
|
||||
contentTypeWithCharset.Assign("application/octet-stream");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
|
||||
if (!uploadChannel) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
|
|
|
@ -138,12 +138,21 @@ RemoteDecoderModule::Supports(const TrackInfo& aTrackInfo,
|
|||
return mWrapped->Supports(aTrackInfo, aDiagnostics);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsRemoteAcceleratedCompositor(KnowsCompositor* aKnows)
|
||||
{
|
||||
TextureFactoryIdentifier ident = aKnows->GetTextureFactoryIdentifier();
|
||||
return ident.mParentBackend != LayersBackend::LAYERS_BASIC &&
|
||||
ident.mParentProcessType == GeckoProcessType_GPU;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
RemoteDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
||||
{
|
||||
if (!MediaPrefs::PDMUseGPUDecoder() ||
|
||||
!aParams.mKnowsCompositor ||
|
||||
aParams.mKnowsCompositor->GetTextureFactoryIdentifier().mParentProcessType != GeckoProcessType_GPU) {
|
||||
!IsRemoteAcceleratedCompositor(aParams.mKnowsCompositor))
|
||||
{
|
||||
return mWrapped->CreateVideoDecoder(aParams);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,10 @@ function handleRequest(request, response) {
|
|||
data += charcode;
|
||||
}
|
||||
|
||||
var mimetype = request.getHeader("Content-Type");
|
||||
var mimetype = "";
|
||||
if (request.hasHeader("Content-Type")) {
|
||||
mimetype = request.getHeader("Content-Type");
|
||||
}
|
||||
|
||||
// check to see if this is form data.
|
||||
if (mimetype.indexOf("multipart/form-data") != -1) {
|
||||
|
|
|
@ -105,7 +105,7 @@ function identity(data) {
|
|||
|
||||
var tests = [
|
||||
function() { createIframeWithData("hi!", "text/plain;charset=UTF-8", identity); },
|
||||
function() { createIframeWithData("123", "application/octet-stream", stringToArrayBuffer); },
|
||||
function() { createIframeWithData("123", "", stringToArrayBuffer); },
|
||||
function() { createIframeWithData("abc", "text/html", stringToBlob); },
|
||||
function() { createIframeWithData("qwerty", "multipart/form-data", stringToFormData); },
|
||||
function() { SimpleTest.finish(); },
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
[Global=(Worker,DedicatedWorker),
|
||||
Exposed=DedicatedWorker]
|
||||
interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
|
||||
readonly attribute DOMString name;
|
||||
|
||||
[Throws]
|
||||
void postMessage(any message, optional sequence<object> transfer = []);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[Constructor(DOMString scriptURL, optional DOMString name)]
|
||||
[Constructor(USVString scriptURL, optional (DOMString or WorkerOptions) options)]
|
||||
interface SharedWorker : EventTarget {
|
||||
readonly attribute MessagePort port;
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* this document.
|
||||
*/
|
||||
|
||||
[Constructor(DOMString scriptURL),
|
||||
[Constructor(USVString scriptURL, optional WorkerOptions options),
|
||||
Func="mozilla::dom::workers::WorkerPrivate::WorkerAvailable",
|
||||
Exposed=(Window,DedicatedWorker,SharedWorker,System)]
|
||||
interface Worker : EventTarget {
|
||||
|
@ -26,7 +26,13 @@ interface Worker : EventTarget {
|
|||
|
||||
Worker implements AbstractWorker;
|
||||
|
||||
[Constructor(DOMString scriptURL),
|
||||
dictionary WorkerOptions {
|
||||
// WorkerType type = "classic"; TODO: Bug 1247687
|
||||
// RequestCredentials credentials = "omit"; // credentials is only used if type is "module" TODO: Bug 1247687
|
||||
DOMString name = "";
|
||||
};
|
||||
|
||||
[Constructor(USVString scriptURL),
|
||||
Func="mozilla::dom::workers::ChromeWorkerPrivate::WorkerAvailable",
|
||||
Exposed=(Window,DedicatedWorker,SharedWorker,System)]
|
||||
interface ChromeWorker : Worker {
|
||||
|
|
|
@ -256,7 +256,7 @@ GetWorkerPref(const nsACString& aPref,
|
|||
// "name|scriptSpec^key1=val1&key2=val2&key3=val3"
|
||||
void
|
||||
GenerateSharedWorkerKey(const nsACString& aScriptSpec,
|
||||
const nsACString& aName,
|
||||
const nsAString& aName,
|
||||
const OriginAttributes& aAttrs,
|
||||
nsCString& aKey)
|
||||
{
|
||||
|
@ -265,7 +265,7 @@ GenerateSharedWorkerKey(const nsACString& aScriptSpec,
|
|||
|
||||
aKey.Truncate();
|
||||
aKey.SetCapacity(aName.Length() + aScriptSpec.Length() + suffix.Length() + 2);
|
||||
aKey.Append(aName);
|
||||
aKey.Append(NS_ConvertUTF16toUTF8(aName));
|
||||
aKey.Append('|');
|
||||
aKey.Append(aScriptSpec);
|
||||
aKey.Append(suffix);
|
||||
|
@ -1685,7 +1685,7 @@ RuntimeService::RegisterWorker(WorkerPrivate* aWorkerPrivate)
|
|||
}
|
||||
|
||||
if (isSharedWorker) {
|
||||
const nsCString& sharedWorkerName = aWorkerPrivate->WorkerName();
|
||||
const nsString& sharedWorkerName(aWorkerPrivate->WorkerName());
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(sharedWorkerScriptSpec, sharedWorkerName,
|
||||
aWorkerPrivate->GetOriginAttributes(), key);
|
||||
|
@ -2432,7 +2432,7 @@ RuntimeService::ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow)
|
|||
nsresult
|
||||
RuntimeService::CreateSharedWorker(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
const nsAString& aName,
|
||||
SharedWorker** aSharedWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
@ -2457,7 +2457,7 @@ nsresult
|
|||
RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
WorkerLoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
const nsAString& aName,
|
||||
SharedWorker** aSharedWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
@ -2502,7 +2502,8 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
|||
if (!workerPrivate) {
|
||||
workerPrivate =
|
||||
WorkerPrivate::Constructor(aCx, aScriptURL, false,
|
||||
WorkerTypeShared, aName, aLoadInfo, rv);
|
||||
WorkerTypeShared, aName, NullCString(),
|
||||
aLoadInfo, rv);
|
||||
NS_ENSURE_TRUE(workerPrivate, rv.StealNSResult());
|
||||
|
||||
created = true;
|
||||
|
|
|
@ -30,11 +30,11 @@ class RuntimeService final : public nsIObserver
|
|||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsCString mScriptSpec;
|
||||
nsCString mName;
|
||||
nsString mName;
|
||||
|
||||
SharedWorkerInfo(WorkerPrivate* aWorkerPrivate,
|
||||
const nsACString& aScriptSpec,
|
||||
const nsACString& aName)
|
||||
const nsAString& aName)
|
||||
: mWorkerPrivate(aWorkerPrivate), mScriptSpec(aScriptSpec), mName(aName)
|
||||
{ }
|
||||
};
|
||||
|
@ -151,7 +151,7 @@ public:
|
|||
nsresult
|
||||
CreateSharedWorker(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
const nsAString& aName,
|
||||
SharedWorker** aSharedWorker);
|
||||
|
||||
void
|
||||
|
@ -275,7 +275,7 @@ private:
|
|||
CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
WorkerLoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
const nsAString& aName,
|
||||
SharedWorker** aSharedWorker);
|
||||
};
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ CancelChannelRunnable::Run()
|
|||
// TODO: When bug 1204254 is implemented, this time marker should be moved to
|
||||
// the point where the body of the network request is complete.
|
||||
mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
|
||||
mChannel->SaveTimeStampsToUnderlyingChannel();
|
||||
mChannel->SaveTimeStamps();
|
||||
|
||||
mChannel->Cancel(mStatus);
|
||||
mRegistration->MaybeScheduleUpdate();
|
||||
|
@ -237,8 +237,10 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
|
||||
mChannel->SaveTimeStampsToUnderlyingChannel();
|
||||
TimeStamp timeStamp = TimeStamp::Now();
|
||||
mChannel->SetHandleFetchEventEnd(timeStamp);
|
||||
mChannel->SetFinishSynthesizedResponseEnd(timeStamp);
|
||||
mChannel->SaveTimeStamps();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
|
||||
if (obsService) {
|
||||
|
@ -554,6 +556,7 @@ void
|
|||
RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
AutoCancel autoCancel(this, mRequestURL);
|
||||
mInterceptedChannel->SetFinishResponseStart(TimeStamp::Now());
|
||||
|
||||
if (!aValue.isObject()) {
|
||||
NS_WARNING("FetchEvent::RespondWith was passed a promise resolved to a non-Object value");
|
||||
|
@ -720,6 +723,8 @@ RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
|||
uint32_t column = mRespondWithColumnNumber;
|
||||
nsString valueString;
|
||||
|
||||
mInterceptedChannel->SetFinishResponseStart(TimeStamp::Now());
|
||||
|
||||
ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString);
|
||||
|
||||
::AsyncLog(mInterceptedChannel, sourceSpec, line, column,
|
||||
|
|
|
@ -1507,14 +1507,17 @@ private:
|
|||
explicit ResumeRequest(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mChannel(aChannel)
|
||||
{
|
||||
mChannel->SetFinishResponseStart(TimeStamp::Now());
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
|
||||
mChannel->SaveTimeStampsToUnderlyingChannel();
|
||||
TimeStamp timeStamp = TimeStamp::Now();
|
||||
mChannel->SetHandleFetchEventEnd(timeStamp);
|
||||
mChannel->SetChannelResetEnd(timeStamp);
|
||||
mChannel->SaveTimeStamps();
|
||||
|
||||
nsresult rv = mChannel->ResetInterception();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
|
@ -1828,7 +1831,9 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
|
|||
mWorkerPrivate = WorkerPrivate::Constructor(jsapi.cx(),
|
||||
scriptSpec,
|
||||
false, WorkerTypeService,
|
||||
mInfo->Scope(), &info, error);
|
||||
NullString(),
|
||||
mInfo->Scope(),
|
||||
&info, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
#include "mozilla/dom/SharedWorkerBinding.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
|
@ -49,7 +50,7 @@ SharedWorker::~SharedWorker()
|
|||
already_AddRefed<SharedWorker>
|
||||
SharedWorker::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
const mozilla::dom::Optional<nsAString>& aName,
|
||||
const StringOrWorkerOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
@ -60,9 +61,12 @@ SharedWorker::Constructor(const GlobalObject& aGlobal,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsCString name;
|
||||
if (aName.WasPassed()) {
|
||||
name = NS_ConvertUTF16toUTF8(aName.Value());
|
||||
nsAutoString name;
|
||||
if (aOptions.IsString()) {
|
||||
name = aOptions.GetAsString();
|
||||
} else {
|
||||
MOZ_ASSERT(aOptions.IsWorkerOptions());
|
||||
name = aOptions.GetAsWorkerOptions().mName;
|
||||
}
|
||||
|
||||
RefPtr<SharedWorker> sharedWorker;
|
||||
|
|
|
@ -20,6 +20,7 @@ class EventChainPreVisitor;
|
|||
|
||||
namespace dom {
|
||||
class MessagePort;
|
||||
class StringOrWorkerOptions;
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -43,7 +44,7 @@ class SharedWorker final : public DOMEventTargetHelper
|
|||
public:
|
||||
static already_AddRefed<SharedWorker>
|
||||
Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
|
||||
const Optional<nsAString>& aName, ErrorResult& aRv);
|
||||
const StringOrWorkerOptions& aOptions, ErrorResult& aRv);
|
||||
|
||||
MessagePort*
|
||||
Port();
|
||||
|
|
|
@ -2726,22 +2726,21 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
|||
const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker,
|
||||
WorkerType aWorkerType,
|
||||
const nsACString& aWorkerName,
|
||||
const nsAString& aWorkerName,
|
||||
const nsACString& aServiceWorkerScope,
|
||||
WorkerLoadInfo& aLoadInfo)
|
||||
: mMutex("WorkerPrivateParent Mutex"),
|
||||
mCondVar(mMutex, "WorkerPrivateParent CondVar"),
|
||||
mParent(aParent), mScriptURL(aScriptURL),
|
||||
mWorkerName(aWorkerName), mLoadingWorkerScript(false),
|
||||
mBusyCount(0), mParentWindowPausedDepth(0), mParentStatus(Pending),
|
||||
mParentFrozen(false), mIsChromeWorker(aIsChromeWorker),
|
||||
mMainThreadObjectsForgotten(false), mIsSecureContext(false),
|
||||
mWorkerType(aWorkerType),
|
||||
mWorkerName(aWorkerName), mServiceWorkerScope(aServiceWorkerScope),
|
||||
mLoadingWorkerScript(false), mBusyCount(0), mParentWindowPausedDepth(0),
|
||||
mParentStatus(Pending), mParentFrozen(false),
|
||||
mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
|
||||
mIsSecureContext(false), mWorkerType(aWorkerType),
|
||||
mCreationTimeStamp(TimeStamp::Now()),
|
||||
mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
|
||||
{
|
||||
MOZ_ASSERT_IF(!IsDedicatedWorker(),
|
||||
!aWorkerName.IsVoid() && NS_IsMainThread());
|
||||
MOZ_ASSERT_IF(IsDedicatedWorker(), aWorkerName.IsEmpty());
|
||||
MOZ_ASSERT_IF(!IsDedicatedWorker(), NS_IsMainThread());
|
||||
|
||||
if (aLoadInfo.mWindow) {
|
||||
AssertIsOnMainThread();
|
||||
|
@ -4420,11 +4419,13 @@ WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
|
|||
WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker, WorkerType aWorkerType,
|
||||
const nsACString& aWorkerName,
|
||||
const nsAString& aWorkerName,
|
||||
const nsACString& aServiceWorkerScope,
|
||||
WorkerLoadInfo& aLoadInfo)
|
||||
: WorkerPrivateParent<WorkerPrivate>(aParent, aScriptURL,
|
||||
aIsChromeWorker, aWorkerType,
|
||||
aWorkerName, aLoadInfo)
|
||||
aWorkerName, aServiceWorkerScope,
|
||||
aLoadInfo)
|
||||
, mDebuggerRegistered(false)
|
||||
, mDebugger(nullptr)
|
||||
, mJSContext(nullptr)
|
||||
|
@ -4447,9 +4448,6 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
|
|||
, mFetchHandlerWasAdded(false)
|
||||
, mOnLine(false)
|
||||
{
|
||||
MOZ_ASSERT_IF(!IsDedicatedWorker(), !aWorkerName.IsVoid());
|
||||
MOZ_ASSERT_IF(IsDedicatedWorker(), aWorkerName.IsEmpty());
|
||||
|
||||
if (aParent) {
|
||||
aParent->AssertIsOnWorkerThread();
|
||||
aParent->GetAllPreferences(mPreferences);
|
||||
|
@ -4506,11 +4504,12 @@ WorkerPrivate::~WorkerPrivate()
|
|||
already_AddRefed<WorkerPrivate>
|
||||
WorkerPrivate::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
const WorkerOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return WorkerPrivate::Constructor(aGlobal, aScriptURL, false,
|
||||
WorkerTypeDedicated, EmptyCString(),
|
||||
nullptr, aRv);
|
||||
WorkerTypeDedicated,
|
||||
aOptions.mName, nullptr, aRv);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -4538,7 +4537,7 @@ ChromeWorkerPrivate::Constructor(const GlobalObject& aGlobal,
|
|||
ErrorResult& aRv)
|
||||
{
|
||||
return WorkerPrivate::Constructor(aGlobal, aScriptURL, true,
|
||||
WorkerTypeDedicated, EmptyCString(),
|
||||
WorkerTypeDedicated, EmptyString(),
|
||||
nullptr, aRv)
|
||||
.downcast<ChromeWorkerPrivate>();
|
||||
}
|
||||
|
@ -4563,12 +4562,12 @@ already_AddRefed<WorkerPrivate>
|
|||
WorkerPrivate::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker, WorkerType aWorkerType,
|
||||
const nsACString& aWorkerName,
|
||||
const nsAString& aWorkerName,
|
||||
WorkerLoadInfo* aLoadInfo, ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.Context();
|
||||
return Constructor(cx, aScriptURL, aIsChromeWorker, aWorkerType,
|
||||
aWorkerName, aLoadInfo, aRv);
|
||||
aWorkerName, NullCString(), aLoadInfo, aRv);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -4576,7 +4575,8 @@ already_AddRefed<WorkerPrivate>
|
|||
WorkerPrivate::Constructor(JSContext* aCx,
|
||||
const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker, WorkerType aWorkerType,
|
||||
const nsACString& aWorkerName,
|
||||
const nsAString& aWorkerName,
|
||||
const nsACString& aServiceWorkerScope,
|
||||
WorkerLoadInfo* aLoadInfo, ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* parent = NS_IsMainThread() ?
|
||||
|
@ -4588,12 +4588,6 @@ WorkerPrivate::Constructor(JSContext* aCx,
|
|||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
// Only service and shared workers can have names.
|
||||
MOZ_ASSERT_IF(aWorkerType != WorkerTypeDedicated,
|
||||
!aWorkerName.IsVoid());
|
||||
MOZ_ASSERT_IF(aWorkerType == WorkerTypeDedicated,
|
||||
aWorkerName.IsEmpty());
|
||||
|
||||
Maybe<WorkerLoadInfo> stackLoadInfo;
|
||||
if (!aLoadInfo) {
|
||||
stackLoadInfo.emplace();
|
||||
|
@ -4630,7 +4624,8 @@ WorkerPrivate::Constructor(JSContext* aCx,
|
|||
|
||||
RefPtr<WorkerPrivate> worker =
|
||||
new WorkerPrivate(parent, aScriptURL, aIsChromeWorker,
|
||||
aWorkerType, aWorkerName, *aLoadInfo);
|
||||
aWorkerType, aWorkerName, aServiceWorkerScope,
|
||||
*aLoadInfo);
|
||||
|
||||
// Gecko contexts always have an explicitly-set default locale (set by
|
||||
// XPJSRuntime::Initialize for the main thread, set by
|
||||
|
@ -6921,7 +6916,7 @@ WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx)
|
|||
} else if (IsServiceWorker()) {
|
||||
globalScope = new ServiceWorkerGlobalScope(this, ServiceWorkerScope());
|
||||
} else {
|
||||
globalScope = new DedicatedWorkerGlobalScope(this);
|
||||
globalScope = new DedicatedWorkerGlobalScope(this, WorkerName());
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx);
|
||||
|
|
|
@ -69,6 +69,7 @@ class PromiseNativeHandler;
|
|||
class StructuredCloneHolder;
|
||||
class WorkerDebuggerGlobalScope;
|
||||
class WorkerGlobalScope;
|
||||
struct WorkerOptions;
|
||||
} // namespace dom
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
|
@ -216,9 +217,10 @@ protected:
|
|||
private:
|
||||
WorkerPrivate* mParent;
|
||||
nsString mScriptURL;
|
||||
// This is the worker name for shared workers or the worker scope
|
||||
// for service workers.
|
||||
nsCString mWorkerName;
|
||||
// This is the worker name for shared workers and dedicated workers.
|
||||
nsString mWorkerName;
|
||||
// This is the worker scope for service workers.
|
||||
nsCString mServiceWorkerScope;
|
||||
LocationInfo mLocationInfo;
|
||||
// The lifetime of these objects within LoadInfo is managed explicitly;
|
||||
// they do not need to be cycle collected.
|
||||
|
@ -266,7 +268,8 @@ protected:
|
|||
WorkerPrivateParent(WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
WorkerType aWorkerType,
|
||||
const nsACString& aSharedWorkerName,
|
||||
const nsAString& aWorkerName,
|
||||
const nsACString& aServiceWorkerScope,
|
||||
WorkerLoadInfo& aLoadInfo);
|
||||
|
||||
~WorkerPrivateParent();
|
||||
|
@ -530,7 +533,7 @@ public:
|
|||
ServiceWorkerScope() const
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
|
||||
return mWorkerName;
|
||||
return mServiceWorkerScope;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
|
@ -835,10 +838,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
const nsCString&
|
||||
const nsString&
|
||||
WorkerName() const
|
||||
{
|
||||
MOZ_ASSERT(IsSharedWorker());
|
||||
return mWorkerName;
|
||||
}
|
||||
|
||||
|
@ -1053,17 +1055,19 @@ protected:
|
|||
public:
|
||||
static already_AddRefed<WorkerPrivate>
|
||||
Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
|
||||
const WorkerOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<WorkerPrivate>
|
||||
Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker, WorkerType aWorkerType,
|
||||
const nsACString& aSharedWorkerName,
|
||||
const nsAString& aWorkerName,
|
||||
WorkerLoadInfo* aLoadInfo, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<WorkerPrivate>
|
||||
Constructor(JSContext* aCx, const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
WorkerType aWorkerType, const nsACString& aSharedWorkerName,
|
||||
WorkerType aWorkerType, const nsAString& aWorkerName,
|
||||
const nsACString& aServiceWorkerScope,
|
||||
WorkerLoadInfo* aLoadInfo, ErrorResult& aRv);
|
||||
|
||||
static bool
|
||||
|
@ -1462,7 +1466,8 @@ public:
|
|||
private:
|
||||
WorkerPrivate(WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
WorkerType aWorkerType, const nsACString& aSharedWorkerName,
|
||||
WorkerType aWorkerType, const nsAString& aWorkerName,
|
||||
const nsACString& aServiceWorkerScope,
|
||||
WorkerLoadInfo& aLoadInfo);
|
||||
|
||||
bool
|
||||
|
|
|
@ -489,8 +489,10 @@ WorkerGlobalScope::CreateImageBitmap(JSContext* aCx,
|
|||
}
|
||||
}
|
||||
|
||||
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerGlobalScope(aWorkerPrivate)
|
||||
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
|
||||
const nsString& aName)
|
||||
: WorkerGlobalScope(aWorkerPrivate)
|
||||
, mName(aName)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -547,7 +549,7 @@ DedicatedWorkerGlobalScope::Close(JSContext* aCx)
|
|||
}
|
||||
|
||||
SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
|
||||
const nsCString& aName)
|
||||
const nsString& aName)
|
||||
: WorkerGlobalScope(aWorkerPrivate), mName(aName)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -207,15 +207,23 @@ public:
|
|||
|
||||
class DedicatedWorkerGlobalScope final : public WorkerGlobalScope
|
||||
{
|
||||
const nsString mName;
|
||||
|
||||
~DedicatedWorkerGlobalScope() { }
|
||||
|
||||
public:
|
||||
explicit DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate);
|
||||
DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
|
||||
const nsString& aName);
|
||||
|
||||
virtual bool
|
||||
WrapGlobalObject(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aReflector) override;
|
||||
|
||||
void GetName(DOMString& aName) const
|
||||
{
|
||||
aName.AsAString() = mName;
|
||||
}
|
||||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
|
@ -229,13 +237,13 @@ public:
|
|||
|
||||
class SharedWorkerGlobalScope final : public WorkerGlobalScope
|
||||
{
|
||||
const nsCString mName;
|
||||
const nsString mName;
|
||||
|
||||
~SharedWorkerGlobalScope() { }
|
||||
|
||||
public:
|
||||
SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
|
||||
const nsCString& aName);
|
||||
const nsString& aName);
|
||||
|
||||
virtual bool
|
||||
WrapGlobalObject(JSContext* aCx,
|
||||
|
@ -243,7 +251,7 @@ public:
|
|||
|
||||
void GetName(DOMString& aName) const
|
||||
{
|
||||
aName.AsAString() = NS_ConvertUTF8toUTF16(mName);
|
||||
aName.AsAString() = mName;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
var promise = new Promise((resolve, reject) => {
|
||||
info("Waiting a few seconds...");
|
||||
setTimeout(resolve, 5000);
|
||||
setTimeout(resolve, 10000);
|
||||
});
|
||||
|
||||
promise.then(function() {
|
||||
|
|
|
@ -3767,10 +3767,20 @@ NS_IMETHODIMP XMLHttpRequestMainThread::
|
|||
nsHeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value)
|
||||
{
|
||||
if (mXHR.IsSafeHeader(header, mHttpChannel)) {
|
||||
mHeaders.Append(header);
|
||||
mHeaders.AppendLiteral(": ");
|
||||
mHeaders.Append(value);
|
||||
mHeaders.AppendLiteral("\r\n");
|
||||
if (!Preferences::GetBool("dom.xhr.lowercase_header.enabled", false)) {
|
||||
if(!mHeaderList.InsertElementSorted(HeaderEntry(header, value),
|
||||
fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString lowerHeader(header);
|
||||
ToLowerCase(lowerHeader);
|
||||
if (!mHeaderList.InsertElementSorted(HeaderEntry(lowerHeader, value),
|
||||
fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -596,16 +596,51 @@ protected:
|
|||
// used to implement getAllResponseHeaders()
|
||||
class nsHeaderVisitor : public nsIHttpHeaderVisitor
|
||||
{
|
||||
struct HeaderEntry final
|
||||
{
|
||||
nsCString mName;
|
||||
nsCString mValue;
|
||||
|
||||
HeaderEntry(const nsACString& aName, const nsACString& aValue)
|
||||
: mName(aName), mValue(aValue)
|
||||
{}
|
||||
|
||||
bool
|
||||
operator==(const HeaderEntry& aOther) const
|
||||
{
|
||||
return mName == aOther.mName;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const HeaderEntry& aOther) const
|
||||
{
|
||||
return mName < aOther.mName;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHTTPHEADERVISITOR
|
||||
nsHeaderVisitor(const XMLHttpRequestMainThread& aXMLHttpRequest,
|
||||
NotNull<nsIHttpChannel*> aHttpChannel)
|
||||
: mXHR(aXMLHttpRequest), mHttpChannel(aHttpChannel) {}
|
||||
const nsACString &Headers() { return mHeaders; }
|
||||
const nsACString &Headers()
|
||||
{
|
||||
for (uint32_t i = 0; i < mHeaderList.Length(); i++) {
|
||||
HeaderEntry& header = mHeaderList.ElementAt(i);
|
||||
|
||||
mHeaders.Append(header.mName);
|
||||
mHeaders.AppendLiteral(": ");
|
||||
mHeaders.Append(header.mValue);
|
||||
mHeaders.AppendLiteral("\r\n");
|
||||
}
|
||||
return mHeaders;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~nsHeaderVisitor() {}
|
||||
|
||||
nsTArray<HeaderEntry> mHeaderList;
|
||||
nsCString mHeaders;
|
||||
const XMLHttpRequestMainThread& mXHR;
|
||||
NotNull<nsCOMPtr<nsIHttpChannel>> mHttpChannel;
|
||||
|
|
|
@ -48,7 +48,7 @@ typedef IO_COUNTERS IoCounters;
|
|||
struct ProcessEntry {
|
||||
int pid;
|
||||
int ppid;
|
||||
char szExeFile[NAME_MAX + 1];
|
||||
char szExeFile[_POSIX_PATH_MAX + 1];
|
||||
};
|
||||
|
||||
struct IoCounters {
|
||||
|
|
|
@ -325,6 +325,9 @@ class BarrieredBase
|
|||
// BarrieredBase is not directly instantiable.
|
||||
explicit BarrieredBase(const T& v) : value(v) {}
|
||||
|
||||
// BarrieredBase subclasses cannot be copy constructed by default.
|
||||
BarrieredBase(const BarrieredBase<T>& other) = default;
|
||||
|
||||
// Storage for all barrier classes. |value| must be a GC thing reference
|
||||
// type: either a direct pointer to a GC thing or a supported tagged
|
||||
// pointer that can reference GC things, such as JS::Value or jsid. Nested
|
||||
|
|
|
@ -85,15 +85,15 @@ class MOZ_RAII AutoStopVerifyingBarriers
|
|||
// inside of an outer minor GC. This is not allowed by the
|
||||
// gc::Statistics phase tree. So we pause the "real" GC, if in fact one
|
||||
// is in progress.
|
||||
gcstats::Phase outer = gc->stats().currentPhase();
|
||||
if (outer != gcstats::PHASE_NONE)
|
||||
gcstats::PhaseKind outer = gc->stats().currentPhaseKind();
|
||||
if (outer != gcstats::PhaseKind::NONE)
|
||||
gc->stats().endPhase(outer);
|
||||
MOZ_ASSERT(gc->stats().currentPhase() == gcstats::PHASE_NONE);
|
||||
MOZ_ASSERT(gc->stats().currentPhaseKind() == gcstats::PhaseKind::NONE);
|
||||
|
||||
if (restartPreVerifier)
|
||||
gc->startVerifyPreBarriers();
|
||||
|
||||
if (outer != gcstats::PHASE_NONE)
|
||||
if (outer != gcstats::PhaseKind::NONE)
|
||||
gc->stats().beginPhase(outer);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -973,14 +973,14 @@ class GCRuntime
|
|||
void bufferGrayRoots();
|
||||
void maybeDoCycleCollection();
|
||||
void markCompartments();
|
||||
IncrementalProgress drainMarkStack(SliceBudget& sliceBudget, gcstats::Phase phase);
|
||||
template <class CompartmentIterT> void markWeakReferences(gcstats::Phase phase);
|
||||
void markWeakReferencesInCurrentGroup(gcstats::Phase phase);
|
||||
template <class ZoneIterT, class CompartmentIterT> void markGrayReferences(gcstats::Phase phase);
|
||||
IncrementalProgress drainMarkStack(SliceBudget& sliceBudget, gcstats::PhaseKind phase);
|
||||
template <class CompartmentIterT> void markWeakReferences(gcstats::PhaseKind phase);
|
||||
void markWeakReferencesInCurrentGroup(gcstats::PhaseKind phase);
|
||||
template <class ZoneIterT, class CompartmentIterT> void markGrayReferences(gcstats::PhaseKind phase);
|
||||
void markBufferedGrayRoots(JS::Zone* zone);
|
||||
void markGrayReferencesInCurrentGroup(gcstats::Phase phase);
|
||||
void markAllWeakReferences(gcstats::Phase phase);
|
||||
void markAllGrayReferences(gcstats::Phase phase);
|
||||
void markGrayReferencesInCurrentGroup(gcstats::PhaseKind phase);
|
||||
void markAllWeakReferences(gcstats::PhaseKind phase);
|
||||
void markAllGrayReferences(gcstats::PhaseKind phase);
|
||||
|
||||
void beginSweepPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock);
|
||||
void groupZonesForSweeping(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock);
|
||||
|
@ -1228,8 +1228,8 @@ class GCRuntime
|
|||
/*
|
||||
* Concurrent sweep infrastructure.
|
||||
*/
|
||||
void startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked);
|
||||
void joinTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked);
|
||||
void startTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked);
|
||||
void joinTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked);
|
||||
friend class AutoRunParallelTask;
|
||||
|
||||
/*
|
||||
|
@ -1366,9 +1366,9 @@ class GCRuntime
|
|||
}
|
||||
|
||||
void minorGC(JS::gcreason::Reason reason,
|
||||
gcstats::Phase phase = gcstats::PHASE_MINOR_GC) JS_HAZ_GC_CALL;
|
||||
gcstats::PhaseKind phase = gcstats::PhaseKind::MINOR_GC) JS_HAZ_GC_CALL;
|
||||
void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) {
|
||||
minorGC(reason, gcstats::PHASE_EVICT_NURSERY);
|
||||
minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY);
|
||||
}
|
||||
void freeAllLifoBlocksAfterMinorGC(LifoAlloc* lifo);
|
||||
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
# 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/.
|
||||
|
||||
# Generate graph structures for GC statistics recording.
|
||||
#
|
||||
# Stats phases are nested and form a directed acyclic graph starting
|
||||
# from a set of root phases. Importantly, a phase may appear under more
|
||||
# than one parent phase.
|
||||
#
|
||||
# For example, the following arrangement is possible:
|
||||
#
|
||||
# +---+
|
||||
# | A |
|
||||
# +---+
|
||||
# |
|
||||
# +-------+-------+
|
||||
# | | |
|
||||
# v v v
|
||||
# +---+ +---+ +---+
|
||||
# | B | | C | | D |
|
||||
# +---+ +---+ +---+
|
||||
# | |
|
||||
# +---+---+
|
||||
# |
|
||||
# v
|
||||
# +---+
|
||||
# | E |
|
||||
# +---+
|
||||
#
|
||||
# This graph is expanded into a tree (or really a forest) and phases
|
||||
# with multiple parents are duplicated.
|
||||
#
|
||||
# For example, the input example above would be expanded to:
|
||||
#
|
||||
# +---+
|
||||
# | A |
|
||||
# +---+
|
||||
# |
|
||||
# +-------+-------+
|
||||
# | | |
|
||||
# v v v
|
||||
# +---+ +---+ +---+
|
||||
# | B | | C | | D |
|
||||
# +---+ +---+ +---+
|
||||
# | |
|
||||
# v v
|
||||
# +---+ +---+
|
||||
# | E | | E'|
|
||||
# +---+ +---+
|
||||
|
||||
import sys
|
||||
import collections
|
||||
|
||||
class PhaseKind():
|
||||
def __init__(self, name, descr, bucket, children = []):
|
||||
self.name = name
|
||||
self.descr = descr
|
||||
self.bucket = bucket
|
||||
self.children = children
|
||||
|
||||
# The root marking phase appears in several places in the graph.
|
||||
MarkRootsPhaseKind = PhaseKind("MARK_ROOTS", "Mark Roots", 48, [
|
||||
PhaseKind("BUFFER_GRAY_ROOTS", "Buffer Gray Roots", 49),
|
||||
PhaseKind("MARK_CCWS", "Mark Cross Compartment Wrappers", 50),
|
||||
PhaseKind("MARK_STACK", "Mark C and JS stacks", 51),
|
||||
PhaseKind("MARK_RUNTIME_DATA", "Mark Runtime-wide Data", 52),
|
||||
PhaseKind("MARK_EMBEDDING", "Mark Embedding", 53),
|
||||
PhaseKind("MARK_COMPARTMENTS", "Mark Compartments", 54),
|
||||
])
|
||||
|
||||
PhaseKindGraphRoots = [
|
||||
PhaseKind("MUTATOR", "Mutator Running", 0),
|
||||
PhaseKind("GC_BEGIN", "Begin Callback", 1),
|
||||
PhaseKind("WAIT_BACKGROUND_THREAD", "Wait Background Thread", 2),
|
||||
PhaseKind("MARK_DISCARD_CODE", "Mark Discard Code", 3),
|
||||
PhaseKind("RELAZIFY_FUNCTIONS", "Relazify Functions", 4),
|
||||
PhaseKind("PURGE", "Purge", 5),
|
||||
PhaseKind("MARK", "Mark", 6, [
|
||||
PhaseKind("UNMARK", "Unmark", 7),
|
||||
MarkRootsPhaseKind,
|
||||
PhaseKind("MARK_DELAYED", "Mark Delayed", 8),
|
||||
]),
|
||||
PhaseKind("SWEEP", "Sweep", 9, [
|
||||
PhaseKind("SWEEP_MARK", "Mark During Sweeping", 10, [
|
||||
PhaseKind("SWEEP_MARK_TYPES", "Mark Types During Sweeping", 11),
|
||||
PhaseKind("SWEEP_MARK_INCOMING_BLACK", "Mark Incoming Black Pointers", 12),
|
||||
PhaseKind("SWEEP_MARK_WEAK", "Mark Weak", 13),
|
||||
PhaseKind("SWEEP_MARK_INCOMING_GRAY", "Mark Incoming Gray Pointers", 14),
|
||||
PhaseKind("SWEEP_MARK_GRAY", "Mark Gray", 15),
|
||||
PhaseKind("SWEEP_MARK_GRAY_WEAK", "Mark Gray and Weak", 16)
|
||||
]),
|
||||
PhaseKind("FINALIZE_START", "Finalize Start Callbacks", 17, [
|
||||
PhaseKind("WEAK_ZONES_CALLBACK", "Per-Slice Weak Callback", 57),
|
||||
PhaseKind("WEAK_COMPARTMENT_CALLBACK", "Per-Compartment Weak Callback", 58)
|
||||
]),
|
||||
PhaseKind("SWEEP_ATOMS", "Sweep Atoms", 18),
|
||||
PhaseKind("SWEEP_COMPARTMENTS", "Sweep Compartments", 20, [
|
||||
PhaseKind("SWEEP_DISCARD_CODE", "Sweep Discard Code", 21),
|
||||
PhaseKind("SWEEP_INNER_VIEWS", "Sweep Inner Views", 22),
|
||||
PhaseKind("SWEEP_CC_WRAPPER", "Sweep Cross Compartment Wrappers", 23),
|
||||
PhaseKind("SWEEP_BASE_SHAPE", "Sweep Base Shapes", 24),
|
||||
PhaseKind("SWEEP_INITIAL_SHAPE", "Sweep Initial Shapes", 25),
|
||||
PhaseKind("SWEEP_TYPE_OBJECT", "Sweep Type Objects", 26),
|
||||
PhaseKind("SWEEP_BREAKPOINT", "Sweep Breakpoints", 27),
|
||||
PhaseKind("SWEEP_REGEXP", "Sweep Regexps", 28),
|
||||
PhaseKind("SWEEP_COMPRESSION", "Sweep Compression Tasks", 62),
|
||||
PhaseKind("SWEEP_WEAKMAPS", "Sweep WeakMaps", 63),
|
||||
PhaseKind("SWEEP_UNIQUEIDS", "Sweep Unique IDs", 64),
|
||||
PhaseKind("SWEEP_JIT_DATA", "Sweep JIT Data", 65),
|
||||
PhaseKind("SWEEP_WEAK_CACHES", "Sweep Weak Caches", 66),
|
||||
PhaseKind("SWEEP_MISC", "Sweep Miscellaneous", 29),
|
||||
PhaseKind("SWEEP_TYPES", "Sweep type information", 30, [
|
||||
PhaseKind("SWEEP_TYPES_BEGIN", "Sweep type tables and compilations", 31),
|
||||
PhaseKind("SWEEP_TYPES_END", "Free type arena", 32),
|
||||
]),
|
||||
]),
|
||||
PhaseKind("SWEEP_OBJECT", "Sweep Object", 33),
|
||||
PhaseKind("SWEEP_STRING", "Sweep String", 34),
|
||||
PhaseKind("SWEEP_SCRIPT", "Sweep Script", 35),
|
||||
PhaseKind("SWEEP_SCOPE", "Sweep Scope", 59),
|
||||
PhaseKind("SWEEP_REGEXP_SHARED", "Sweep RegExpShared", 61),
|
||||
PhaseKind("SWEEP_SHAPE", "Sweep Shape", 36),
|
||||
PhaseKind("SWEEP_JITCODE", "Sweep JIT code", 37),
|
||||
PhaseKind("FINALIZE_END", "Finalize End Callback", 38),
|
||||
PhaseKind("DESTROY", "Deallocate", 39)
|
||||
]),
|
||||
PhaseKind("COMPACT", "Compact", 40, [
|
||||
PhaseKind("COMPACT_MOVE", "Compact Move", 41),
|
||||
PhaseKind("COMPACT_UPDATE", "Compact Update", 42, [
|
||||
MarkRootsPhaseKind,
|
||||
PhaseKind("COMPACT_UPDATE_CELLS", "Compact Update Cells", 43),
|
||||
]),
|
||||
]),
|
||||
PhaseKind("GC_END", "End Callback", 44),
|
||||
PhaseKind("MINOR_GC", "All Minor GCs", 45, [
|
||||
MarkRootsPhaseKind,
|
||||
]),
|
||||
PhaseKind("EVICT_NURSERY", "Minor GCs to Evict Nursery", 46, [
|
||||
MarkRootsPhaseKind,
|
||||
]),
|
||||
PhaseKind("TRACE_HEAP", "Trace Heap", 47, [
|
||||
MarkRootsPhaseKind,
|
||||
]),
|
||||
PhaseKind("BARRIER", "Barriers", 55, [
|
||||
PhaseKind("UNMARK_GRAY", "Unmark gray", 56),
|
||||
]),
|
||||
PhaseKind("PURGE_SHAPE_TABLES", "Purge ShapeTables", 60)
|
||||
]
|
||||
|
||||
# Make a linear list of all unique phases by performing a depth first
|
||||
# search on the phase graph starting at the roots. This will be used to
|
||||
# generate the PhaseKind enum.
|
||||
|
||||
def findAllPhaseKinds():
|
||||
phases = []
|
||||
seen = set()
|
||||
|
||||
def dfs(phase):
|
||||
if phase in seen:
|
||||
return
|
||||
phases.append(phase)
|
||||
seen.add(phase)
|
||||
for child in phase.children:
|
||||
dfs(child)
|
||||
|
||||
for phase in PhaseKindGraphRoots:
|
||||
dfs(phase)
|
||||
return phases
|
||||
|
||||
AllPhaseKinds = findAllPhaseKinds()
|
||||
|
||||
# Expand the DAG into a tree, duplicating phases which have more than
|
||||
# one parent.
|
||||
|
||||
class Phase:
|
||||
def __init__(self, phaseKind, parent, depth):
|
||||
self.phaseKind = phaseKind
|
||||
self.parent = parent
|
||||
self.depth = depth
|
||||
self.children = []
|
||||
self.nextSibling = None
|
||||
self.nextInPhaseKind = None
|
||||
|
||||
def expandPhases():
|
||||
phases = []
|
||||
phasesForPhase = collections.defaultdict(list)
|
||||
|
||||
def traverse(phaseKind, parent, depth):
|
||||
ep = Phase(phaseKind, parent, depth)
|
||||
phases.append(ep)
|
||||
|
||||
# Update list of expanded phases for this phase kind.
|
||||
if phasesForPhase[phaseKind]:
|
||||
phasesForPhase[phaseKind][-1].nextInPhaseKind = ep
|
||||
phasesForPhase[phaseKind].append(ep)
|
||||
|
||||
# Recurse over children.
|
||||
for child in phaseKind.children:
|
||||
child_ep = traverse(child, ep, depth + 1)
|
||||
if ep.children:
|
||||
ep.children[-1].nextSibling = child_ep
|
||||
ep.children.append(child_ep)
|
||||
return ep
|
||||
|
||||
for phaseKind in PhaseKindGraphRoots:
|
||||
traverse(phaseKind, None, 0)
|
||||
|
||||
return phases, phasesForPhase
|
||||
|
||||
AllPhases, PhasesForPhaseKind = expandPhases()
|
||||
|
||||
# Name expanded phases based on phase kind name and index if there are
|
||||
# multiple expanded phases corresponding to a single phase kind.
|
||||
|
||||
for phaseKind in AllPhaseKinds:
|
||||
phases = PhasesForPhaseKind[phaseKind]
|
||||
if len(phases) == 1:
|
||||
phases[0].name = "%s" % phaseKind.name
|
||||
else:
|
||||
for index, xphase in enumerate(phases):
|
||||
xphase.name = "%s_%d" % (phaseKind.name, index + 1)
|
||||
|
||||
# Generate code.
|
||||
|
||||
def writeList(out, items):
|
||||
if items:
|
||||
out.write(",\n".join(" " + item for item in items) + "\n")
|
||||
|
||||
def writeEnumClass(out, name, type, items, extraItems):
|
||||
items = [ "FIRST" ] + items + [ "LIMIT" ] + extraItems
|
||||
items[1] += " = " + items[0]
|
||||
out.write("enum class %s : %s {\n" % (name, type));
|
||||
writeList(out, items)
|
||||
out.write("};\n")
|
||||
|
||||
def generateHeader(out):
|
||||
#
|
||||
# Generate PhaseKind enum.
|
||||
#
|
||||
phaseKindNames = map(lambda phaseKind: phaseKind.name, AllPhaseKinds)
|
||||
extraPhaseKinds = [
|
||||
"NONE = LIMIT",
|
||||
"EXPLICIT_SUSPENSION = LIMIT",
|
||||
"IMPLICIT_SUSPENSION"
|
||||
]
|
||||
writeEnumClass(out, "PhaseKind", "uint8_t", phaseKindNames, extraPhaseKinds)
|
||||
out.write("\n")
|
||||
|
||||
#
|
||||
# Generate Phase enum.
|
||||
#
|
||||
expandedPhaseNames = map(lambda xphase: xphase.name, AllPhases)
|
||||
extraPhases = [
|
||||
"NONE = LIMIT",
|
||||
"EXPLICIT_SUSPENSION = LIMIT",
|
||||
"IMPLICIT_SUSPENSION"
|
||||
]
|
||||
writeEnumClass(out, "Phase", "uint8_t", expandedPhaseNames, extraPhases)
|
||||
|
||||
def generateCpp(out):
|
||||
#
|
||||
# Generate the PhaseKindInfo table.
|
||||
#
|
||||
out.write("static const PhaseKindTable phaseKinds = {\n")
|
||||
for phaseKind in AllPhaseKinds:
|
||||
xPhase = PhasesForPhaseKind[phaseKind][0]
|
||||
out.write(" /* PhaseKind::%s */ PhaseKindInfo { Phase::%s, %d },\n" %
|
||||
(phaseKind.name, xPhase.name, phaseKind.bucket))
|
||||
out.write("};\n")
|
||||
out.write("\n")
|
||||
|
||||
#
|
||||
# Generate the PhaseInfo tree.
|
||||
#
|
||||
def name(xphase):
|
||||
return "Phase::" + xphase.name if xphase else "Phase::NONE"
|
||||
|
||||
out.write("static const PhaseTable phases = {\n")
|
||||
for xphase in AllPhases:
|
||||
firstChild = xphase.children[0] if xphase.children else None
|
||||
phaseKind = xphase.phaseKind
|
||||
out.write(" /* %s */ PhaseInfo { %s, %s, %s, %s, PhaseKind::%s, %d, \"%s\" },\n" %
|
||||
(name(xphase),
|
||||
name(xphase.parent),
|
||||
name(firstChild),
|
||||
name(xphase.nextSibling),
|
||||
name(xphase.nextInPhaseKind),
|
||||
phaseKind.name,
|
||||
xphase.depth,
|
||||
phaseKind.descr))
|
||||
out.write("};\n")
|
|
@ -2523,7 +2523,7 @@ bool
|
|||
GCMarker::markDelayedChildren(SliceBudget& budget)
|
||||
{
|
||||
GCRuntime& gc = runtime()->gc;
|
||||
gcstats::AutoPhase ap(gc.stats(), gc.state() == State::Mark, gcstats::PHASE_MARK_DELAYED);
|
||||
gcstats::AutoPhase ap(gc.stats(), gc.state() == State::Mark, gcstats::PhaseKind::MARK_DELAYED);
|
||||
|
||||
MOZ_ASSERT(unmarkedArenaStackTop);
|
||||
do {
|
||||
|
@ -3406,8 +3406,8 @@ TypedUnmarkGrayCellRecursively(T* t)
|
|||
MOZ_ASSERT(!JS::CurrentThreadIsHeapCycleCollecting());
|
||||
|
||||
UnmarkGrayTracer unmarker(rt);
|
||||
gcstats::AutoPhase outerPhase(rt->gc.stats(), gcstats::PHASE_BARRIER);
|
||||
gcstats::AutoPhase innerPhase(rt->gc.stats(), gcstats::PHASE_UNMARK_GRAY);
|
||||
gcstats::AutoPhase outerPhase(rt->gc.stats(), gcstats::PhaseKind::BARRIER);
|
||||
gcstats::AutoPhase innerPhase(rt->gc.stats(), gcstats::PhaseKind::UNMARK_GRAY);
|
||||
unmarker.unmark(JS::GCCellPtr(t, MapTypeToTraceKind<T>::kind));
|
||||
return unmarker.unmarkedAny;
|
||||
}
|
||||
|
|
|
@ -738,7 +738,7 @@ js::Nursery::doCollection(JS::gcreason::Reason reason,
|
|||
|
||||
maybeStartProfile(ProfileKey::MarkDebugger);
|
||||
{
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PHASE_MARK_ROOTS);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
Debugger::traceAllForMovingGC(&mover);
|
||||
}
|
||||
maybeEndProfile(ProfileKey::MarkDebugger);
|
||||
|
|
|
@ -259,7 +259,7 @@ js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, AutoLockForExclusiveAcc
|
|||
if (rt->isBeingDestroyed())
|
||||
return;
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_ROOTS);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
if (rt->atomsCompartment(lock)->zone()->isCollecting())
|
||||
traceRuntimeAtoms(trc, lock);
|
||||
JSCompartment::traceIncomingCrossCompartmentEdgesForZoneGC(trc);
|
||||
|
@ -276,7 +276,7 @@ js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc, AutoLockForExclusiveAcc
|
|||
// the map. And we can reach its trace function despite having finished the
|
||||
// roots via the edges stored by the pre-barrier verifier when we finish
|
||||
// the verifier for the last time.
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_ROOTS);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
|
||||
jit::JitRuntime::TraceJitcodeGlobalTableForMinorGC(trc);
|
||||
|
||||
|
@ -291,7 +291,7 @@ js::TraceRuntime(JSTracer* trc)
|
|||
JSRuntime* rt = trc->runtime();
|
||||
EvictAllNurseries(rt);
|
||||
AutoPrepareForTracing prep(TlsContext.get(), WithAtoms);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PHASE_TRACE_HEAP);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
rt->gc.traceRuntime(trc, prep.session().lock);
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,7 @@ js::gc::GCRuntime::traceRuntime(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
|||
{
|
||||
MOZ_ASSERT(!rt->isBeingDestroyed());
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_ROOTS);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
traceRuntimeAtoms(trc, lock);
|
||||
traceRuntimeCommon(trc, TraceRuntime, lock);
|
||||
}
|
||||
|
@ -308,7 +308,7 @@ js::gc::GCRuntime::traceRuntime(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
|||
void
|
||||
js::gc::GCRuntime::traceRuntimeAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_RUNTIME_DATA);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_RUNTIME_DATA);
|
||||
TracePermanentAtoms(trc);
|
||||
TraceAtoms(trc, lock);
|
||||
TraceWellKnownSymbols(trc);
|
||||
|
@ -322,7 +322,7 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
|
|||
MOZ_ASSERT(!TlsContext.get()->suppressGC);
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_STACK);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_STACK);
|
||||
|
||||
JSContext* cx = TlsContext.get();
|
||||
for (const CooperatingContext& target : rt->cooperatingContexts()) {
|
||||
|
@ -370,7 +370,7 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
|
|||
|
||||
// Trace the embedding's black and gray roots.
|
||||
if (!JS::CurrentThreadIsHeapMinorCollecting()) {
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_EMBEDDING);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_EMBEDDING);
|
||||
|
||||
/*
|
||||
* The embedding can register additional roots here.
|
||||
|
@ -431,7 +431,7 @@ js::gc::GCRuntime::finishRoots()
|
|||
|
||||
AssertNoRootsTracer trc(rt, TraceWeakMapKeysValues);
|
||||
AutoPrepareForTracing prep(TlsContext.get(), WithAtoms);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PHASE_TRACE_HEAP);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
traceRuntime(&trc, prep.session().lock);
|
||||
|
||||
// Restore the wrapper tracing so that we leak instead of leaving dangling
|
||||
|
@ -481,7 +481,7 @@ js::gc::GCRuntime::bufferGrayRoots()
|
|||
for (GCZonesIter zone(rt); !zone.done(); zone.next())
|
||||
MOZ_ASSERT(zone->gcGrayRoots().empty());
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_BUFFER_GRAY_ROOTS);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::BUFFER_GRAY_ROOTS);
|
||||
|
||||
BufferGrayRootsTracer grayBufferer(rt);
|
||||
if (JSTraceDataOp op = grayRootTracer.op)
|
||||
|
|
|
@ -31,6 +31,7 @@ using namespace js::gc;
|
|||
using namespace js::gcstats;
|
||||
|
||||
using mozilla::DebugOnly;
|
||||
using mozilla::EnumeratedArray;
|
||||
using mozilla::IntegerRange;
|
||||
using mozilla::PodArrayZero;
|
||||
using mozilla::PodZero;
|
||||
|
@ -44,10 +45,10 @@ using mozilla::TimeDuration;
|
|||
*/
|
||||
JS_STATIC_ASSERT(JS::gcreason::NUM_TELEMETRY_REASONS >= JS::gcreason::NUM_REASONS);
|
||||
|
||||
static inline decltype(mozilla::MakeEnumeratedRange(PHASE_FIRST, PHASE_LIMIT))
|
||||
AllPhases()
|
||||
static inline decltype(mozilla::MakeEnumeratedRange(PhaseKind::FIRST, PhaseKind::LIMIT))
|
||||
AllPhaseKinds()
|
||||
{
|
||||
return mozilla::MakeEnumeratedRange(PHASE_FIRST, PHASE_LIMIT);
|
||||
return mozilla::MakeEnumeratedRange(PhaseKind::FIRST, PhaseKind::LIMIT);
|
||||
}
|
||||
|
||||
const char*
|
||||
|
@ -90,219 +91,92 @@ js::gcstats::ExplainAbortReason(gc::AbortReason reason)
|
|||
}
|
||||
}
|
||||
|
||||
struct PhaseKindInfo
|
||||
{
|
||||
Phase firstPhase;
|
||||
uint8_t telemetryBucket;
|
||||
};
|
||||
|
||||
// PhaseInfo objects form a tree.
|
||||
struct PhaseInfo
|
||||
{
|
||||
Phase parent;
|
||||
Phase firstChild;
|
||||
Phase nextSibling;
|
||||
Phase nextInPhase;
|
||||
PhaseKind phaseKind;
|
||||
uint8_t depth;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
// A table of ExpandePhaseInfo indexed by Phase.
|
||||
using PhaseTable = EnumeratedArray<Phase, Phase::LIMIT, PhaseInfo>;
|
||||
|
||||
// A table of PhaseKindInfo indexed by Phase.
|
||||
using PhaseKindTable = EnumeratedArray<PhaseKind, PhaseKind::LIMIT, PhaseKindInfo>;
|
||||
|
||||
#include "gc/StatsPhasesGenerated.cpp"
|
||||
|
||||
static double
|
||||
t(TimeDuration duration)
|
||||
{
|
||||
return duration.ToMilliseconds();
|
||||
}
|
||||
|
||||
struct PhaseInfo
|
||||
Phase
|
||||
Statistics::currentPhase() const
|
||||
{
|
||||
Phase index;
|
||||
const char* name;
|
||||
Phase parent;
|
||||
uint8_t telemetryBucket;
|
||||
};
|
||||
return phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : Phase::NONE;
|
||||
}
|
||||
|
||||
// The zeroth entry in the timing arrays is used for phases that have a
|
||||
// unique lineage.
|
||||
static const size_t PHASE_DAG_NONE = 0;
|
||||
|
||||
// These are really just fields of PhaseInfo, but I have to initialize them
|
||||
// programmatically, which prevents making phases[] const. (And marking these
|
||||
// fields mutable does not work on Windows; the whole thing gets created in
|
||||
// read-only memory anyway.)
|
||||
struct ExtraPhaseInfo
|
||||
PhaseKind
|
||||
Statistics::currentPhaseKind() const
|
||||
{
|
||||
// Depth in the tree of each phase type
|
||||
size_t depth;
|
||||
// Public API to get the current phase. Return the current phase,
|
||||
// suppressing the synthetic PhaseKind::MUTATOR phase.
|
||||
|
||||
// Index into the set of parallel arrays of timing data, for parents with
|
||||
// at least one multi-parented child
|
||||
size_t dagSlot;
|
||||
Phase phase = currentPhase();
|
||||
MOZ_ASSERT_IF(phase == Phase::MUTATOR, phaseNestingDepth == 1);
|
||||
if (phase == Phase::NONE || phase == Phase::MUTATOR)
|
||||
return PhaseKind::NONE;
|
||||
|
||||
ExtraPhaseInfo() : depth(0), dagSlot(0) {}
|
||||
};
|
||||
return phases[phase].phaseKind;
|
||||
}
|
||||
|
||||
static const Phase PHASE_NO_PARENT = PHASE_LIMIT;
|
||||
Phase
|
||||
Statistics::lookupChildPhase(PhaseKind phaseKind) const
|
||||
{
|
||||
if (phaseKind == PhaseKind::IMPLICIT_SUSPENSION)
|
||||
return Phase::IMPLICIT_SUSPENSION;
|
||||
if (phaseKind == PhaseKind::EXPLICIT_SUSPENSION)
|
||||
return Phase::EXPLICIT_SUSPENSION;
|
||||
|
||||
struct DagChildEdge {
|
||||
Phase parent;
|
||||
Phase child;
|
||||
} dagChildEdges[] = {
|
||||
{ PHASE_MARK, PHASE_MARK_ROOTS },
|
||||
{ PHASE_MINOR_GC, PHASE_MARK_ROOTS },
|
||||
{ PHASE_TRACE_HEAP, PHASE_MARK_ROOTS },
|
||||
{ PHASE_EVICT_NURSERY, PHASE_MARK_ROOTS },
|
||||
{ PHASE_COMPACT_UPDATE, PHASE_MARK_ROOTS }
|
||||
};
|
||||
MOZ_ASSERT(phaseKind < PhaseKind::LIMIT);
|
||||
|
||||
/*
|
||||
* Note that PHASE_MUTATOR never has any child phases. If beginPhase is called
|
||||
* while PHASE_MUTATOR is active, it will automatically be suspended and
|
||||
* resumed when the phase stack is next empty. Timings for these phases are
|
||||
* thus exclusive of any other phase.
|
||||
*/
|
||||
|
||||
static const PhaseInfo phases[] = {
|
||||
{ PHASE_MUTATOR, "Mutator Running", PHASE_NO_PARENT, 0 },
|
||||
{ PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT, 1 },
|
||||
{ PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread", PHASE_NO_PARENT, 2 },
|
||||
{ PHASE_MARK_DISCARD_CODE, "Mark Discard Code", PHASE_NO_PARENT, 3 },
|
||||
{ PHASE_RELAZIFY_FUNCTIONS, "Relazify Functions", PHASE_NO_PARENT, 4 },
|
||||
{ PHASE_PURGE, "Purge", PHASE_NO_PARENT, 5 },
|
||||
{ PHASE_MARK, "Mark", PHASE_NO_PARENT, 6 },
|
||||
{ PHASE_UNMARK, "Unmark", PHASE_MARK, 7 },
|
||||
/* PHASE_MARK_ROOTS */
|
||||
{ PHASE_MARK_DELAYED, "Mark Delayed", PHASE_MARK, 8 },
|
||||
{ PHASE_SWEEP, "Sweep", PHASE_NO_PARENT, 9 },
|
||||
{ PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP, 10 },
|
||||
{ PHASE_SWEEP_MARK_TYPES, "Mark Types During Sweeping", PHASE_SWEEP_MARK, 11 },
|
||||
{ PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK, 12 },
|
||||
{ PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK, 13 },
|
||||
{ PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK, 14 },
|
||||
{ PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK, 15 },
|
||||
{ PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK, 16 },
|
||||
{ PHASE_FINALIZE_START, "Finalize Start Callbacks", PHASE_SWEEP, 17 },
|
||||
{ PHASE_WEAK_ZONES_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START, 57 },
|
||||
{ PHASE_WEAK_COMPARTMENT_CALLBACK, "Per-Compartment Weak Callback", PHASE_FINALIZE_START, 58 },
|
||||
{ PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP, 18 },
|
||||
{ PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP, 20 },
|
||||
{ PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code", PHASE_SWEEP_COMPARTMENTS, 21 },
|
||||
{ PHASE_SWEEP_INNER_VIEWS, "Sweep Inner Views", PHASE_SWEEP_COMPARTMENTS, 22 },
|
||||
{ PHASE_SWEEP_CC_WRAPPER, "Sweep Cross Compartment Wrappers", PHASE_SWEEP_COMPARTMENTS, 23 },
|
||||
{ PHASE_SWEEP_BASE_SHAPE, "Sweep Base Shapes", PHASE_SWEEP_COMPARTMENTS, 24 },
|
||||
{ PHASE_SWEEP_INITIAL_SHAPE, "Sweep Initial Shapes", PHASE_SWEEP_COMPARTMENTS, 25 },
|
||||
{ PHASE_SWEEP_TYPE_OBJECT, "Sweep Type Objects", PHASE_SWEEP_COMPARTMENTS, 26 },
|
||||
{ PHASE_SWEEP_BREAKPOINT, "Sweep Breakpoints", PHASE_SWEEP_COMPARTMENTS, 27 },
|
||||
{ PHASE_SWEEP_REGEXP, "Sweep Regexps", PHASE_SWEEP_COMPARTMENTS, 28 },
|
||||
{ PHASE_SWEEP_COMPRESSION, "Sweep Compression Tasks", PHASE_SWEEP_COMPARTMENTS, 62 },
|
||||
{ PHASE_SWEEP_WEAKMAPS, "Sweep WeakMaps", PHASE_SWEEP_COMPARTMENTS, 63 },
|
||||
{ PHASE_SWEEP_UNIQUEIDS, "Sweep Unique IDs", PHASE_SWEEP_COMPARTMENTS, 64 },
|
||||
{ PHASE_SWEEP_JIT_DATA, "Sweep JIT Data", PHASE_SWEEP_COMPARTMENTS, 65 },
|
||||
{ PHASE_SWEEP_WEAK_CACHES, "Sweep Weak Caches", PHASE_SWEEP_COMPARTMENTS, 66 },
|
||||
{ PHASE_SWEEP_MISC, "Sweep Miscellaneous", PHASE_SWEEP_COMPARTMENTS, 29 },
|
||||
{ PHASE_SWEEP_TYPES, "Sweep type information", PHASE_SWEEP_COMPARTMENTS, 30 },
|
||||
{ PHASE_SWEEP_TYPES_BEGIN, "Sweep type tables and compilations", PHASE_SWEEP_TYPES, 31 },
|
||||
{ PHASE_SWEEP_TYPES_END, "Free type arena", PHASE_SWEEP_TYPES, 32 },
|
||||
{ PHASE_SWEEP_OBJECT, "Sweep Object", PHASE_SWEEP, 33 },
|
||||
{ PHASE_SWEEP_STRING, "Sweep String", PHASE_SWEEP, 34 },
|
||||
{ PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP, 35 },
|
||||
{ PHASE_SWEEP_SCOPE, "Sweep Scope", PHASE_SWEEP, 59 },
|
||||
{ PHASE_SWEEP_REGEXP_SHARED, "Sweep RegExpShared", PHASE_SWEEP, 61 },
|
||||
{ PHASE_SWEEP_SHAPE, "Sweep Shape", PHASE_SWEEP, 36 },
|
||||
{ PHASE_SWEEP_JITCODE, "Sweep JIT code", PHASE_SWEEP, 37 },
|
||||
{ PHASE_FINALIZE_END, "Finalize End Callback", PHASE_SWEEP, 38 },
|
||||
{ PHASE_DESTROY, "Deallocate", PHASE_SWEEP, 39 },
|
||||
{ PHASE_COMPACT, "Compact", PHASE_NO_PARENT, 40 },
|
||||
{ PHASE_COMPACT_MOVE, "Compact Move", PHASE_COMPACT, 41 },
|
||||
{ PHASE_COMPACT_UPDATE, "Compact Update", PHASE_COMPACT, 42 },
|
||||
/* PHASE_MARK_ROOTS */
|
||||
{ PHASE_COMPACT_UPDATE_CELLS, "Compact Update Cells", PHASE_COMPACT_UPDATE, 43 },
|
||||
{ PHASE_GC_END, "End Callback", PHASE_NO_PARENT, 44 },
|
||||
{ PHASE_MINOR_GC, "All Minor GCs", PHASE_NO_PARENT, 45 },
|
||||
/* PHASE_MARK_ROOTS */
|
||||
{ PHASE_EVICT_NURSERY, "Minor GCs to Evict Nursery", PHASE_NO_PARENT, 46 },
|
||||
/* PHASE_MARK_ROOTS */
|
||||
{ PHASE_TRACE_HEAP, "Trace Heap", PHASE_NO_PARENT, 47 },
|
||||
/* PHASE_MARK_ROOTS */
|
||||
{ PHASE_BARRIER, "Barriers", PHASE_NO_PARENT, 55 },
|
||||
{ PHASE_UNMARK_GRAY, "Unmark gray", PHASE_BARRIER, 56 },
|
||||
{ PHASE_MARK_ROOTS, "Mark Roots", PHASE_MULTI_PARENTS, 48 },
|
||||
{ PHASE_BUFFER_GRAY_ROOTS, "Buffer Gray Roots", PHASE_MARK_ROOTS, 49 },
|
||||
{ PHASE_MARK_CCWS, "Mark Cross Compartment Wrappers", PHASE_MARK_ROOTS, 50 },
|
||||
{ PHASE_MARK_STACK, "Mark C and JS stacks", PHASE_MARK_ROOTS, 51 },
|
||||
{ PHASE_MARK_RUNTIME_DATA, "Mark Runtime-wide Data", PHASE_MARK_ROOTS, 52 },
|
||||
{ PHASE_MARK_EMBEDDING, "Mark Embedding", PHASE_MARK_ROOTS, 53 },
|
||||
{ PHASE_MARK_COMPARTMENTS, "Mark Compartments", PHASE_MARK_ROOTS, 54 },
|
||||
{ PHASE_PURGE_SHAPE_TABLES, "Purge ShapeTables", PHASE_NO_PARENT, 60 },
|
||||
|
||||
{ PHASE_LIMIT, nullptr, PHASE_NO_PARENT, 66 }
|
||||
|
||||
// The current number of telemetryBuckets is equal to the value for
|
||||
// PHASE_LIMIT. If you insert new phases somewhere, start at that number and
|
||||
// count up. Do not change any existing numbers.
|
||||
};
|
||||
|
||||
static mozilla::EnumeratedArray<Phase, PHASE_LIMIT, ExtraPhaseInfo> phaseExtra;
|
||||
|
||||
// Mapping from all nodes with a multi-parented child to a Vector of all
|
||||
// multi-parented children and their descendants. (Single-parented children will
|
||||
// not show up in this list.)
|
||||
static mozilla::Vector<Phase, 0, SystemAllocPolicy> dagDescendants[Statistics::NumTimingArrays];
|
||||
|
||||
// Preorder iterator over all phases in the expanded tree. Positions are
|
||||
// returned as <phase,dagSlot> pairs (dagSlot will be zero aka PHASE_DAG_NONE
|
||||
// for the top nodes with a single path from the parent, and 1 or more for
|
||||
// nodes in multiparented subtrees).
|
||||
struct AllPhaseIterator {
|
||||
// If 'descendants' is empty, the current Phase position.
|
||||
int current;
|
||||
|
||||
// The depth of the current multiparented node that we are processing, or
|
||||
// zero if we are pointing to the top portion of the tree.
|
||||
int baseLevel;
|
||||
|
||||
// When looking at multiparented descendants, the dag slot (index into
|
||||
// PhaseTimeTables) containing the entries for the current parent.
|
||||
size_t activeSlot;
|
||||
|
||||
// When iterating over a multiparented subtree, the list of (remaining)
|
||||
// subtree nodes.
|
||||
mozilla::Vector<Phase, 0, SystemAllocPolicy>::Range descendants;
|
||||
|
||||
explicit AllPhaseIterator()
|
||||
: current(0)
|
||||
, baseLevel(0)
|
||||
, activeSlot(PHASE_DAG_NONE)
|
||||
, descendants(dagDescendants[PHASE_DAG_NONE].all()) /* empty range */
|
||||
{
|
||||
// Most phases only correspond to a single expanded phase so check for that
|
||||
// first.
|
||||
Phase phase = phaseKinds[phaseKind].firstPhase;
|
||||
if (phases[phase].nextInPhase == Phase::NONE) {
|
||||
MOZ_ASSERT(phases[phase].parent == currentPhase());
|
||||
return phase;
|
||||
}
|
||||
|
||||
void get(Phase* phase, size_t* dagSlot, int* level = nullptr) {
|
||||
MOZ_ASSERT(!done());
|
||||
*dagSlot = activeSlot;
|
||||
*phase = descendants.empty() ? Phase(current) : descendants.front();
|
||||
if (level)
|
||||
*level = phaseExtra[*phase].depth + baseLevel;
|
||||
// Otherwise search all expanded phases that correspond to the required
|
||||
// phase to find the one whose parent is the current expanded phase.
|
||||
Phase parent = currentPhase();
|
||||
while (phases[phase].parent != parent) {
|
||||
phase = phases[phase].nextInPhase;
|
||||
MOZ_ASSERT(phase != Phase::NONE);
|
||||
}
|
||||
|
||||
void advance() {
|
||||
MOZ_ASSERT(!done());
|
||||
return phase;
|
||||
}
|
||||
|
||||
if (!descendants.empty()) {
|
||||
// Currently iterating over a multiparented subtree.
|
||||
descendants.popFront();
|
||||
if (!descendants.empty())
|
||||
return;
|
||||
|
||||
// Just before leaving the last child, reset the iterator to look
|
||||
// at "main" phases (in PHASE_DAG_NONE) instead of multiparented
|
||||
// subtree phases.
|
||||
++current;
|
||||
activeSlot = PHASE_DAG_NONE;
|
||||
baseLevel = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
auto phase = Phase(current);
|
||||
if (phaseExtra[phase].dagSlot != PHASE_DAG_NONE) {
|
||||
// The current phase has a shared subtree. Load them up into
|
||||
// 'descendants' and advance to the first child.
|
||||
activeSlot = phaseExtra[phase].dagSlot;
|
||||
descendants = dagDescendants[activeSlot].all();
|
||||
MOZ_ASSERT(!descendants.empty());
|
||||
baseLevel += phaseExtra[phase].depth + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
++current;
|
||||
}
|
||||
|
||||
bool done() const {
|
||||
return phases[current].parent == PHASE_MULTI_PARENTS;
|
||||
}
|
||||
};
|
||||
inline decltype(mozilla::MakeEnumeratedRange(Phase::FIRST, Phase::LIMIT))
|
||||
AllPhases()
|
||||
{
|
||||
return mozilla::MakeEnumeratedRange(Phase::FIRST, Phase::LIMIT);
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::gcDuration(TimeDuration* total, TimeDuration* maxPause) const
|
||||
|
@ -330,7 +204,8 @@ Statistics::sccDurations(TimeDuration* total, TimeDuration* maxPause) const
|
|||
typedef Vector<UniqueChars, 8, SystemAllocPolicy> FragmentVector;
|
||||
|
||||
static UniqueChars
|
||||
Join(const FragmentVector& fragments, const char* separator = "") {
|
||||
Join(const FragmentVector& fragments, const char* separator = "")
|
||||
{
|
||||
const size_t separatorLength = strlen(separator);
|
||||
size_t length = 0;
|
||||
for (size_t i = 0; i < fragments.length(); ++i) {
|
||||
|
@ -340,8 +215,10 @@ Join(const FragmentVector& fragments, const char* separator = "") {
|
|||
}
|
||||
|
||||
char* joined = js_pod_malloc<char>(length + 1);
|
||||
joined[length] = '\0';
|
||||
if (!joined)
|
||||
return UniqueChars();
|
||||
|
||||
joined[length] = '\0';
|
||||
char* cursor = joined;
|
||||
for (size_t i = 0; i < fragments.length(); ++i) {
|
||||
if (fragments[i])
|
||||
|
@ -358,24 +235,14 @@ Join(const FragmentVector& fragments, const char* separator = "") {
|
|||
}
|
||||
|
||||
static TimeDuration
|
||||
SumChildTimes(size_t phaseSlot, Phase phase, const Statistics::PhaseTimeTable& phaseTimes)
|
||||
SumChildTimes(Phase phase, const Statistics::PhaseTimeTable& phaseTimes)
|
||||
{
|
||||
// Sum the contributions from single-parented children.
|
||||
TimeDuration total = 0;
|
||||
size_t depth = phaseExtra[phase].depth;
|
||||
for (unsigned i = phase + 1; i < PHASE_LIMIT && phaseExtra[Phase(i)].depth > depth; i++) {
|
||||
if (phases[i].parent == phase)
|
||||
total += phaseTimes[phaseSlot][Phase(i)];
|
||||
}
|
||||
|
||||
// Sum the contributions from multi-parented children.
|
||||
size_t dagSlot = phaseExtra[phase].dagSlot;
|
||||
MOZ_ASSERT(dagSlot <= Statistics::MaxMultiparentPhases - 1);
|
||||
if (dagSlot != PHASE_DAG_NONE) {
|
||||
for (auto edge : dagChildEdges) {
|
||||
if (edge.parent == phase)
|
||||
total += phaseTimes[dagSlot][edge.child];
|
||||
}
|
||||
for (phase = phases[phase].firstChild;
|
||||
phase != Phase::NONE;
|
||||
phase = phases[phase].nextSibling)
|
||||
{
|
||||
total += phaseTimes[phase];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
@ -470,15 +337,12 @@ Statistics::formatCompactSlicePhaseTimes(const PhaseTimeTable& phaseTimes) const
|
|||
|
||||
FragmentVector fragments;
|
||||
char buffer[128];
|
||||
for (AllPhaseIterator iter; !iter.done(); iter.advance()) {
|
||||
Phase phase;
|
||||
size_t dagSlot;
|
||||
int level;
|
||||
iter.get(&phase, &dagSlot, &level);
|
||||
for (auto phase : AllPhases()) {
|
||||
DebugOnly<uint8_t> level = phases[phase].depth;
|
||||
MOZ_ASSERT(level < 4);
|
||||
|
||||
TimeDuration ownTime = phaseTimes[dagSlot][phase];
|
||||
TimeDuration childTime = SumChildTimes(dagSlot, phase, phaseTimes);
|
||||
TimeDuration ownTime = phaseTimes[phase];
|
||||
TimeDuration childTime = SumChildTimes(phase, phaseTimes);
|
||||
if (ownTime > MaxUnaccountedTime) {
|
||||
SprintfLiteral(buffer, "%s: %.3fms", phases[phase].name, t(ownTime));
|
||||
if (!fragments.append(DuplicateString(buffer)))
|
||||
|
@ -597,14 +461,10 @@ Statistics::formatDetailedPhaseTimes(const PhaseTimeTable& phaseTimes) const
|
|||
|
||||
FragmentVector fragments;
|
||||
char buffer[128];
|
||||
for (AllPhaseIterator iter; !iter.done(); iter.advance()) {
|
||||
Phase phase;
|
||||
size_t dagSlot;
|
||||
int level;
|
||||
iter.get(&phase, &dagSlot, &level);
|
||||
|
||||
TimeDuration ownTime = phaseTimes[dagSlot][phase];
|
||||
TimeDuration childTime = SumChildTimes(dagSlot, phase, phaseTimes);
|
||||
for (auto phase : AllPhases()) {
|
||||
uint8_t level = phases[phase].depth;
|
||||
TimeDuration ownTime = phaseTimes[phase];
|
||||
TimeDuration childTime = SumChildTimes(phase, phaseTimes);
|
||||
if (!ownTime.IsZero()) {
|
||||
SprintfLiteral(buffer, " %*s: %.3fms\n",
|
||||
level * 2, phases[phase].name, t(ownTime));
|
||||
|
@ -782,15 +642,11 @@ SanitizeJsonKey(const char* const buffer)
|
|||
void
|
||||
Statistics::formatJsonPhaseTimes(const PhaseTimeTable& phaseTimes, JSONPrinter& json) const
|
||||
{
|
||||
for (AllPhaseIterator iter; !iter.done(); iter.advance()) {
|
||||
Phase phase;
|
||||
size_t dagSlot;
|
||||
iter.get(&phase, &dagSlot);
|
||||
|
||||
for (auto phase : AllPhases()) {
|
||||
UniqueChars name = SanitizeJsonKey(phases[phase].name);
|
||||
if (!name)
|
||||
json.outOfMemory();
|
||||
TimeDuration ownTime = phaseTimes[dagSlot][phase];
|
||||
TimeDuration ownTime = phaseTimes[phase];
|
||||
if (!ownTime.IsZero())
|
||||
json.property(name.get(), ownTime, JSONPrinter::MILLISECONDS);
|
||||
}
|
||||
|
@ -803,7 +659,6 @@ Statistics::Statistics(JSRuntime* rt)
|
|||
preBytes(0),
|
||||
maxPauseInInterval(0),
|
||||
phaseNestingDepth(0),
|
||||
activeDagSlot(PHASE_DAG_NONE),
|
||||
suspended(0),
|
||||
sliceCallback(nullptr),
|
||||
nurseryCollectionCallback(nullptr),
|
||||
|
@ -853,54 +708,37 @@ Statistics::~Statistics()
|
|||
Statistics::initialize()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// Sanity check generated tables.
|
||||
for (auto i : AllPhases()) {
|
||||
MOZ_ASSERT(phases[i].index == i);
|
||||
for (auto j : AllPhases())
|
||||
MOZ_ASSERT_IF(i != j, phases[i].telemetryBucket != phases[j].telemetryBucket);
|
||||
auto parent = phases[i].parent;
|
||||
if (parent != Phase::NONE) {
|
||||
MOZ_ASSERT(phases[i].depth == phases[parent].depth + 1);
|
||||
}
|
||||
auto firstChild = phases[i].firstChild;
|
||||
if (firstChild != Phase::NONE) {
|
||||
MOZ_ASSERT(i == phases[firstChild].parent);
|
||||
MOZ_ASSERT(phases[i].depth == phases[firstChild].depth - 1);
|
||||
}
|
||||
auto nextSibling = phases[i].nextSibling;
|
||||
if (nextSibling != Phase::NONE) {
|
||||
MOZ_ASSERT(parent == phases[nextSibling].parent);
|
||||
MOZ_ASSERT(phases[i].depth == phases[nextSibling].depth);
|
||||
}
|
||||
auto nextInPhase = phases[i].nextInPhase;
|
||||
if (nextInPhase != Phase::NONE) {
|
||||
MOZ_ASSERT(phases[i].phaseKind == phases[nextInPhase].phaseKind);
|
||||
MOZ_ASSERT(parent != phases[nextInPhase].parent);
|
||||
}
|
||||
}
|
||||
for (auto i : AllPhaseKinds()) {
|
||||
MOZ_ASSERT(phases[phaseKinds[i].firstPhase].phaseKind == i);
|
||||
for (auto j : AllPhaseKinds()) {
|
||||
MOZ_ASSERT_IF(i != j,
|
||||
phaseKinds[i].telemetryBucket != phaseKinds[j].telemetryBucket);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create a static table of descendants for every phase with multiple
|
||||
// children. This assumes that all descendants come linearly in the
|
||||
// list, which is reasonable since full dags are not supported; any
|
||||
// path from the leaf to the root must encounter at most one node with
|
||||
// multiple parents.
|
||||
size_t dagSlot = 0;
|
||||
for (size_t i = 0; i < mozilla::ArrayLength(dagChildEdges); i++) {
|
||||
Phase parent = dagChildEdges[i].parent;
|
||||
if (!phaseExtra[parent].dagSlot)
|
||||
phaseExtra[parent].dagSlot = ++dagSlot;
|
||||
|
||||
Phase child = dagChildEdges[i].child;
|
||||
MOZ_ASSERT(phases[child].parent == PHASE_MULTI_PARENTS);
|
||||
int j = child;
|
||||
do {
|
||||
if (!dagDescendants[phaseExtra[parent].dagSlot].append(Phase(j)))
|
||||
return false;
|
||||
j++;
|
||||
} while (j != PHASE_LIMIT && phases[j].parent != PHASE_MULTI_PARENTS);
|
||||
}
|
||||
MOZ_ASSERT(dagSlot <= MaxMultiparentPhases - 1);
|
||||
|
||||
// Fill in the depth of each node in the tree. Multi-parented nodes
|
||||
// have depth 0.
|
||||
mozilla::Vector<Phase, 0, SystemAllocPolicy> stack;
|
||||
if (!stack.append(PHASE_LIMIT)) // Dummy entry to avoid special-casing the first node
|
||||
return false;
|
||||
for (auto i : AllPhases()) {
|
||||
if (phases[i].parent == PHASE_NO_PARENT ||
|
||||
phases[i].parent == PHASE_MULTI_PARENTS)
|
||||
{
|
||||
stack.clear();
|
||||
} else {
|
||||
while (stack.back() != phases[i].parent)
|
||||
stack.popBack();
|
||||
}
|
||||
phaseExtra[i].depth = stack.length();
|
||||
if (!stack.append(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -937,68 +775,65 @@ Statistics::getMaxGCPauseSinceClear()
|
|||
// Sum up the time for a phase, including instances of the phase with different
|
||||
// parents.
|
||||
static TimeDuration
|
||||
SumPhase(Phase phase, const Statistics::PhaseTimeTable& times)
|
||||
SumPhase(PhaseKind phaseKind, const Statistics::PhaseTimeTable& times)
|
||||
{
|
||||
TimeDuration sum = 0;
|
||||
for (const auto& phaseTimes : times)
|
||||
sum += phaseTimes[phase];
|
||||
for (Phase phase = phaseKinds[phaseKind].firstPhase;
|
||||
phase != Phase::NONE;
|
||||
phase = phases[phase].nextInPhase)
|
||||
{
|
||||
sum += times[phase];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
static void
|
||||
CheckSelfTime(Phase parent, Phase child, const Statistics::PhaseTimeTable& times, TimeDuration selfTimes[PHASE_LIMIT], TimeDuration childTime)
|
||||
CheckSelfTime(Phase parent,
|
||||
Phase child,
|
||||
const Statistics::PhaseTimeTable& times,
|
||||
const Statistics::PhaseTimeTable& selfTimes,
|
||||
TimeDuration childTime)
|
||||
{
|
||||
if (selfTimes[parent] < childTime) {
|
||||
fprintf(stderr,
|
||||
"Parent %s time = %.3fms"
|
||||
" with %.3fms remaining, "
|
||||
"child %s time %.3fms\n",
|
||||
phases[parent].name, SumPhase(parent, times).ToMilliseconds(),
|
||||
"Parent %s time = %.3fms with %.3fms remaining, child %s time %.3fms\n",
|
||||
phases[parent].name,
|
||||
times[parent].ToMilliseconds(),
|
||||
selfTimes[parent].ToMilliseconds(),
|
||||
phases[child].name, childTime.ToMilliseconds());
|
||||
phases[child].name,
|
||||
childTime.ToMilliseconds());
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
static Phase
|
||||
static PhaseKind
|
||||
LongestPhaseSelfTime(const Statistics::PhaseTimeTable& times)
|
||||
{
|
||||
TimeDuration selfTimes[PHASE_LIMIT];
|
||||
|
||||
// Start with total times, including children's times.
|
||||
for (auto i : AllPhases())
|
||||
selfTimes[i] = SumPhase(i, times);
|
||||
// Start with total times per expanded phase, including children's times.
|
||||
Statistics::PhaseTimeTable selfTimes(times);
|
||||
|
||||
// We have the total time spent in each phase, including descendant times.
|
||||
// Loop over the children and subtract their times from their parent's self
|
||||
// time.
|
||||
for (auto i : AllPhases()) {
|
||||
Phase parent = phases[i].parent;
|
||||
if (parent == PHASE_MULTI_PARENTS) {
|
||||
// Current phase i has multiple parents. Each "instance" of this
|
||||
// phase is in a parallel array of times indexed by 'dagSlot', so
|
||||
// subtract only the dagSlot-specific child's time from the parent.
|
||||
for (auto edge : dagChildEdges) {
|
||||
if (edge.parent == i) {
|
||||
size_t dagSlot = phaseExtra[edge.parent].dagSlot;
|
||||
MOZ_ASSERT(dagSlot <= Statistics::MaxMultiparentPhases - 1);
|
||||
CheckSelfTime(edge.parent, edge.child, times,
|
||||
selfTimes, times[dagSlot][edge.child]);
|
||||
MOZ_ASSERT(selfTimes[edge.parent] >= times[dagSlot][edge.child]);
|
||||
selfTimes[edge.parent] -= times[dagSlot][edge.child];
|
||||
}
|
||||
}
|
||||
} else if (parent != PHASE_NO_PARENT) {
|
||||
CheckSelfTime(parent, i, times, selfTimes, selfTimes[i]);
|
||||
MOZ_ASSERT(selfTimes[parent] >= selfTimes[i]);
|
||||
selfTimes[parent] -= selfTimes[i];
|
||||
if (parent != Phase::NONE) {
|
||||
CheckSelfTime(parent, i, times, selfTimes, times[i]);
|
||||
selfTimes[parent] -= times[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Sum expanded phases corresponding to the same phase.
|
||||
EnumeratedArray<PhaseKind, PhaseKind::LIMIT, TimeDuration> phaseTimes;
|
||||
for (auto i : AllPhaseKinds())
|
||||
phaseTimes[i] = SumPhase(i, selfTimes);
|
||||
|
||||
// Loop over this table to find the longest phase.
|
||||
TimeDuration longestTime = 0;
|
||||
Phase longestPhase = PHASE_NONE;
|
||||
for (auto i : AllPhases()) {
|
||||
if (selfTimes[i] > longestTime) {
|
||||
longestTime = selfTimes[i];
|
||||
PhaseKind longestPhase = PhaseKind::NONE;
|
||||
for (auto i : AllPhaseKinds()) {
|
||||
if (phaseTimes[i] > longestTime) {
|
||||
longestTime = phaseTimes[i];
|
||||
longestPhase = i;
|
||||
}
|
||||
}
|
||||
|
@ -1037,25 +872,20 @@ Statistics::beginGC(JSGCInvocationKind kind)
|
|||
void
|
||||
Statistics::endGC()
|
||||
{
|
||||
for (auto j : IntegerRange(NumTimingArrays)) {
|
||||
for (auto i : AllPhases())
|
||||
phaseTotals[j][i] += phaseTimes[j][i];
|
||||
}
|
||||
|
||||
TimeDuration sccTotal, sccLongest;
|
||||
sccDurations(&sccTotal, &sccLongest);
|
||||
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_IS_ZONE_GC, !zoneStats.isCollectingAllZones());
|
||||
TimeDuration markTotal = SumPhase(PHASE_MARK, phaseTimes);
|
||||
TimeDuration markRootsTotal = SumPhase(PHASE_MARK_ROOTS, phaseTimes);
|
||||
TimeDuration markTotal = SumPhase(PhaseKind::MARK, phaseTimes);
|
||||
TimeDuration markRootsTotal = SumPhase(PhaseKind::MARK_ROOTS, phaseTimes);
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal));
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP]));
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[Phase::SWEEP]));
|
||||
if (runtime->gc.isCompactingGc()) {
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_COMPACT_MS,
|
||||
t(phaseTimes[PHASE_DAG_NONE][PHASE_COMPACT]));
|
||||
t(phaseTimes[Phase::COMPACT]));
|
||||
}
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal));
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP_MARK_GRAY]));
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[Phase::SWEEP_MARK_GRAY]));
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, nonincremental());
|
||||
if (nonincremental())
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL_REASON, uint32_t(nonincrementalReason_));
|
||||
|
@ -1156,8 +986,9 @@ Statistics::endSlice()
|
|||
|
||||
// Record any phase that goes more than 2x over its budget.
|
||||
if (sliceTime.ToMilliseconds() > 2 * budget_ms) {
|
||||
Phase longest = LongestPhaseSelfTime(slices_.back().phaseTimes);
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_SLOW_PHASE, phases[longest].telemetryBucket);
|
||||
PhaseKind longest = LongestPhaseSelfTime(slices_.back().phaseTimes);
|
||||
uint8_t bucket = phaseKinds[longest].telemetryBucket;
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_SLOW_PHASE, bucket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1185,11 +1016,13 @@ Statistics::endSlice()
|
|||
for (auto& count : counts)
|
||||
count = 0;
|
||||
|
||||
// Clear the timers at the end of a GC because we accumulate time in
|
||||
// between GCs for some (which come before PHASE_GC_BEGIN in the list.)
|
||||
PodZero(&phaseStartTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN);
|
||||
for (size_t d = PHASE_DAG_NONE; d < NumTimingArrays; d++)
|
||||
PodZero(&phaseTimes[d][PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN);
|
||||
// Clear the timers at the end of a GC, preserving the data for PhaseKind::MUTATOR.
|
||||
auto mutatorStartTime = phaseStartTimes[Phase::MUTATOR];
|
||||
auto mutatorTime = phaseTimes[Phase::MUTATOR];
|
||||
PodZero(&phaseStartTimes);
|
||||
PodZero(&phaseTimes);
|
||||
phaseStartTimes[Phase::MUTATOR] = mutatorStartTime;
|
||||
phaseTimes[Phase::MUTATOR] = mutatorTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1199,18 +1032,18 @@ Statistics::startTimingMutator()
|
|||
if (phaseNestingDepth != 0) {
|
||||
// Should only be called from outside of GC.
|
||||
MOZ_ASSERT(phaseNestingDepth == 1);
|
||||
MOZ_ASSERT(phaseNesting[0] == PHASE_MUTATOR);
|
||||
MOZ_ASSERT(phaseNesting[0] == Phase::MUTATOR);
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(suspended == 0);
|
||||
|
||||
timedGCTime = 0;
|
||||
phaseStartTimes[PHASE_MUTATOR] = TimeStamp();
|
||||
phaseTimes[PHASE_DAG_NONE][PHASE_MUTATOR] = 0;
|
||||
phaseStartTimes[Phase::MUTATOR] = TimeStamp();
|
||||
phaseTimes[Phase::MUTATOR] = 0;
|
||||
timedGCStart = TimeStamp();
|
||||
|
||||
beginPhase(PHASE_MUTATOR);
|
||||
beginPhase(PhaseKind::MUTATOR);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1218,75 +1051,77 @@ bool
|
|||
Statistics::stopTimingMutator(double& mutator_ms, double& gc_ms)
|
||||
{
|
||||
// This should only be called from outside of GC, while timing the mutator.
|
||||
if (phaseNestingDepth != 1 || phaseNesting[0] != PHASE_MUTATOR)
|
||||
if (phaseNestingDepth != 1 || phaseNesting[0] != Phase::MUTATOR)
|
||||
return false;
|
||||
|
||||
endPhase(PHASE_MUTATOR);
|
||||
mutator_ms = t(phaseTimes[PHASE_DAG_NONE][PHASE_MUTATOR]);
|
||||
endPhase(PhaseKind::MUTATOR);
|
||||
mutator_ms = t(phaseTimes[Phase::MUTATOR]);
|
||||
gc_ms = t(timedGCTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::suspendPhases(Phase suspension)
|
||||
Statistics::suspendPhases(PhaseKind suspension)
|
||||
{
|
||||
MOZ_ASSERT(suspension == PHASE_EXPLICIT_SUSPENSION || suspension == PHASE_IMPLICIT_SUSPENSION);
|
||||
MOZ_ASSERT(suspension == PhaseKind::EXPLICIT_SUSPENSION ||
|
||||
suspension == PhaseKind::IMPLICIT_SUSPENSION);
|
||||
while (phaseNestingDepth) {
|
||||
MOZ_ASSERT(suspended < mozilla::ArrayLength(suspendedPhases));
|
||||
Phase parent = phaseNesting[phaseNestingDepth - 1];
|
||||
suspendedPhases[suspended++] = parent;
|
||||
recordPhaseEnd(parent);
|
||||
}
|
||||
suspendedPhases[suspended++] = suspension;
|
||||
suspendedPhases[suspended++] = lookupChildPhase(suspension);
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::resumePhases()
|
||||
{
|
||||
DebugOnly<Phase> popped = suspendedPhases[--suspended];
|
||||
MOZ_ASSERT(popped == PHASE_EXPLICIT_SUSPENSION || popped == PHASE_IMPLICIT_SUSPENSION);
|
||||
suspended--;
|
||||
#ifdef DEBUG
|
||||
Phase popped = suspendedPhases[suspended];
|
||||
MOZ_ASSERT(popped == Phase::EXPLICIT_SUSPENSION ||
|
||||
popped == Phase::IMPLICIT_SUSPENSION);
|
||||
#endif
|
||||
|
||||
while (suspended &&
|
||||
suspendedPhases[suspended - 1] != PHASE_EXPLICIT_SUSPENSION &&
|
||||
suspendedPhases[suspended - 1] != PHASE_IMPLICIT_SUSPENSION)
|
||||
suspendedPhases[suspended - 1] != Phase::EXPLICIT_SUSPENSION &&
|
||||
suspendedPhases[suspended - 1] != Phase::IMPLICIT_SUSPENSION)
|
||||
{
|
||||
Phase resumePhase = suspendedPhases[--suspended];
|
||||
if (resumePhase == PHASE_MUTATOR)
|
||||
if (resumePhase == Phase::MUTATOR)
|
||||
timedGCTime += TimeStamp::Now() - timedGCStart;
|
||||
beginPhase(resumePhase);
|
||||
recordPhaseBegin(resumePhase);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::beginPhase(Phase phase)
|
||||
Statistics::beginPhase(PhaseKind phaseKind)
|
||||
{
|
||||
// No longer timing these phases. We should never see these.
|
||||
MOZ_ASSERT(phase != PHASE_GC_BEGIN && phase != PHASE_GC_END);
|
||||
MOZ_ASSERT(phaseKind != PhaseKind::GC_BEGIN && phaseKind != PhaseKind::GC_END);
|
||||
|
||||
Phase parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT;
|
||||
|
||||
// PHASE_MUTATOR is suspended while performing GC.
|
||||
if (parent == PHASE_MUTATOR) {
|
||||
suspendPhases(PHASE_IMPLICIT_SUSPENSION);
|
||||
parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT;
|
||||
// PhaseKind::MUTATOR is suspended while performing GC.
|
||||
if (currentPhase() == Phase::MUTATOR) {
|
||||
suspendPhases(PhaseKind::IMPLICIT_SUSPENSION);
|
||||
}
|
||||
|
||||
recordPhaseBegin(lookupChildPhase(phaseKind));
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::recordPhaseBegin(Phase phase)
|
||||
{
|
||||
// Guard against any other re-entry.
|
||||
MOZ_ASSERT(!phaseStartTimes[phase]);
|
||||
|
||||
MOZ_ASSERT(phases[phase].index == phase);
|
||||
MOZ_ASSERT(phaseNestingDepth < MAX_NESTING);
|
||||
MOZ_ASSERT(phases[phase].parent == parent || phases[phase].parent == PHASE_MULTI_PARENTS);
|
||||
MOZ_ASSERT(phases[phase].parent == currentPhase());
|
||||
|
||||
phaseNesting[phaseNestingDepth] = phase;
|
||||
phaseNestingDepth++;
|
||||
|
||||
if (phases[phase].parent == PHASE_MULTI_PARENTS) {
|
||||
MOZ_ASSERT(parent != PHASE_NO_PARENT);
|
||||
activeDagSlot = phaseExtra[parent].dagSlot;
|
||||
}
|
||||
MOZ_ASSERT(activeDagSlot <= MaxMultiparentPhases - 1);
|
||||
|
||||
phaseStartTimes[phase] = TimeStamp::Now();
|
||||
}
|
||||
|
||||
|
@ -1295,40 +1130,46 @@ Statistics::recordPhaseEnd(Phase phase)
|
|||
{
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
||||
if (phase == PHASE_MUTATOR)
|
||||
if (phase == Phase::MUTATOR)
|
||||
timedGCStart = now;
|
||||
|
||||
phaseNestingDepth--;
|
||||
|
||||
TimeDuration t = now - phaseStartTimes[phase];
|
||||
if (!slices_.empty())
|
||||
slices_.back().phaseTimes[activeDagSlot][phase] += t;
|
||||
phaseTimes[activeDagSlot][phase] += t;
|
||||
slices_.back().phaseTimes[phase] += t;
|
||||
phaseTimes[phase] += t;
|
||||
phaseStartTimes[phase] = TimeStamp();
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::endPhase(Phase phase)
|
||||
Statistics::endPhase(PhaseKind phaseKind)
|
||||
{
|
||||
Phase phase = currentPhase();
|
||||
MOZ_ASSERT(phase != Phase::NONE);
|
||||
MOZ_ASSERT(phases[phase].phaseKind == phaseKind);
|
||||
|
||||
recordPhaseEnd(phase);
|
||||
|
||||
if (phases[phase].parent == PHASE_MULTI_PARENTS)
|
||||
activeDagSlot = PHASE_DAG_NONE;
|
||||
|
||||
// When emptying the stack, we may need to return to timing the mutator
|
||||
// (PHASE_MUTATOR).
|
||||
if (phaseNestingDepth == 0 && suspended > 0 && suspendedPhases[suspended - 1] == PHASE_IMPLICIT_SUSPENSION)
|
||||
// (PhaseKind::MUTATOR).
|
||||
if (phaseNestingDepth == 0 &&
|
||||
suspended > 0 &&
|
||||
suspendedPhases[suspended - 1] == Phase::IMPLICIT_SUSPENSION)
|
||||
{
|
||||
resumePhases();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::endParallelPhase(Phase phase, const GCParallelTask* task)
|
||||
Statistics::endParallelPhase(PhaseKind phaseKind, const GCParallelTask* task)
|
||||
{
|
||||
Phase phase = lookupChildPhase(phaseKind);
|
||||
phaseNestingDepth--;
|
||||
|
||||
if (!slices_.empty())
|
||||
slices_.back().phaseTimes[PHASE_DAG_NONE][phase] += task->duration();
|
||||
phaseTimes[PHASE_DAG_NONE][phase] += task->duration();
|
||||
slices_.back().phaseTimes[phase] += task->duration();
|
||||
phaseTimes[phase] += task->duration();
|
||||
phaseStartTimes[phase] = TimeStamp();
|
||||
}
|
||||
|
||||
|
@ -1441,7 +1282,7 @@ Statistics::printSliceProfile()
|
|||
totalTimes_[ProfileKey::Total] += times[ProfileKey::Total];
|
||||
|
||||
#define GET_PROFILE_TIME(name, text, phase) \
|
||||
times[ProfileKey::name] = slice.phaseTimes[PHASE_DAG_NONE][phase]; \
|
||||
times[ProfileKey::name] = SumPhase(phase, slice.phaseTimes); \
|
||||
totalTimes_[ProfileKey::name] += times[ProfileKey::name];
|
||||
FOR_EACH_GC_PROFILE_TIME(GET_PROFILE_TIME)
|
||||
#undef GET_PROFILE_TIME
|
||||
|
|
|
@ -30,82 +30,10 @@ class GCParallelTask;
|
|||
|
||||
namespace gcstats {
|
||||
|
||||
enum Phase : uint8_t {
|
||||
PHASE_FIRST,
|
||||
// Phase data is generated by a script. If you need to add phases, edit
|
||||
// js/src/gc/GenerateStatsPhases.py
|
||||
|
||||
PHASE_MUTATOR = PHASE_FIRST,
|
||||
PHASE_GC_BEGIN,
|
||||
PHASE_WAIT_BACKGROUND_THREAD,
|
||||
PHASE_MARK_DISCARD_CODE,
|
||||
PHASE_RELAZIFY_FUNCTIONS,
|
||||
PHASE_PURGE,
|
||||
PHASE_MARK,
|
||||
PHASE_UNMARK,
|
||||
PHASE_MARK_DELAYED,
|
||||
PHASE_SWEEP,
|
||||
PHASE_SWEEP_MARK,
|
||||
PHASE_SWEEP_MARK_TYPES,
|
||||
PHASE_SWEEP_MARK_INCOMING_BLACK,
|
||||
PHASE_SWEEP_MARK_WEAK,
|
||||
PHASE_SWEEP_MARK_INCOMING_GRAY,
|
||||
PHASE_SWEEP_MARK_GRAY,
|
||||
PHASE_SWEEP_MARK_GRAY_WEAK,
|
||||
PHASE_FINALIZE_START,
|
||||
PHASE_WEAK_ZONES_CALLBACK,
|
||||
PHASE_WEAK_COMPARTMENT_CALLBACK,
|
||||
PHASE_SWEEP_ATOMS,
|
||||
PHASE_SWEEP_COMPARTMENTS,
|
||||
PHASE_SWEEP_DISCARD_CODE,
|
||||
PHASE_SWEEP_INNER_VIEWS,
|
||||
PHASE_SWEEP_CC_WRAPPER,
|
||||
PHASE_SWEEP_BASE_SHAPE,
|
||||
PHASE_SWEEP_INITIAL_SHAPE,
|
||||
PHASE_SWEEP_TYPE_OBJECT,
|
||||
PHASE_SWEEP_BREAKPOINT,
|
||||
PHASE_SWEEP_REGEXP,
|
||||
PHASE_SWEEP_COMPRESSION,
|
||||
PHASE_SWEEP_WEAKMAPS,
|
||||
PHASE_SWEEP_UNIQUEIDS,
|
||||
PHASE_SWEEP_JIT_DATA,
|
||||
PHASE_SWEEP_WEAK_CACHES,
|
||||
PHASE_SWEEP_MISC,
|
||||
PHASE_SWEEP_TYPES,
|
||||
PHASE_SWEEP_TYPES_BEGIN,
|
||||
PHASE_SWEEP_TYPES_END,
|
||||
PHASE_SWEEP_OBJECT,
|
||||
PHASE_SWEEP_STRING,
|
||||
PHASE_SWEEP_SCRIPT,
|
||||
PHASE_SWEEP_SCOPE,
|
||||
PHASE_SWEEP_REGEXP_SHARED,
|
||||
PHASE_SWEEP_SHAPE,
|
||||
PHASE_SWEEP_JITCODE,
|
||||
PHASE_FINALIZE_END,
|
||||
PHASE_DESTROY,
|
||||
PHASE_COMPACT,
|
||||
PHASE_COMPACT_MOVE,
|
||||
PHASE_COMPACT_UPDATE,
|
||||
PHASE_COMPACT_UPDATE_CELLS,
|
||||
PHASE_GC_END,
|
||||
PHASE_MINOR_GC,
|
||||
PHASE_EVICT_NURSERY,
|
||||
PHASE_TRACE_HEAP,
|
||||
PHASE_BARRIER,
|
||||
PHASE_UNMARK_GRAY,
|
||||
PHASE_MARK_ROOTS,
|
||||
PHASE_BUFFER_GRAY_ROOTS,
|
||||
PHASE_MARK_CCWS,
|
||||
PHASE_MARK_STACK,
|
||||
PHASE_MARK_RUNTIME_DATA,
|
||||
PHASE_MARK_EMBEDDING,
|
||||
PHASE_MARK_COMPARTMENTS,
|
||||
PHASE_PURGE_SHAPE_TABLES,
|
||||
|
||||
PHASE_LIMIT,
|
||||
PHASE_NONE = PHASE_LIMIT,
|
||||
PHASE_EXPLICIT_SUSPENSION = PHASE_LIMIT,
|
||||
PHASE_IMPLICIT_SUSPENSION,
|
||||
PHASE_MULTI_PARENTS
|
||||
};
|
||||
#include "gc/StatsPhasesGenerated.h"
|
||||
|
||||
enum Stat {
|
||||
STAT_NEW_CHUNK,
|
||||
|
@ -151,17 +79,17 @@ struct ZoneGCStats
|
|||
};
|
||||
|
||||
#define FOR_EACH_GC_PROFILE_TIME(_) \
|
||||
_(BeginCallback, "bgnCB", PHASE_GC_BEGIN) \
|
||||
_(WaitBgThread, "waitBG", PHASE_WAIT_BACKGROUND_THREAD) \
|
||||
_(DiscardCode, "discrd", PHASE_MARK_DISCARD_CODE) \
|
||||
_(RelazifyFunc, "relzfy", PHASE_RELAZIFY_FUNCTIONS) \
|
||||
_(PurgeTables, "prgTbl", PHASE_PURGE_SHAPE_TABLES) \
|
||||
_(Purge, "purge", PHASE_PURGE) \
|
||||
_(Mark, "mark", PHASE_MARK) \
|
||||
_(Sweep, "sweep", PHASE_SWEEP) \
|
||||
_(Compact, "cmpct", PHASE_COMPACT) \
|
||||
_(EndCallback, "endCB", PHASE_GC_END) \
|
||||
_(Barriers, "brrier", PHASE_BARRIER)
|
||||
_(BeginCallback, "bgnCB", PhaseKind::GC_BEGIN) \
|
||||
_(WaitBgThread, "waitBG", PhaseKind::WAIT_BACKGROUND_THREAD) \
|
||||
_(DiscardCode, "discrd", PhaseKind::MARK_DISCARD_CODE) \
|
||||
_(RelazifyFunc, "relzfy", PhaseKind::RELAZIFY_FUNCTIONS) \
|
||||
_(PurgeTables, "prgTbl", PhaseKind::PURGE_SHAPE_TABLES) \
|
||||
_(Purge, "purge", PhaseKind::PURGE) \
|
||||
_(Mark, "mark", PhaseKind::MARK) \
|
||||
_(Sweep, "sweep", PhaseKind::SWEEP) \
|
||||
_(Compact, "cmpct", PhaseKind::COMPACT) \
|
||||
_(EndCallback, "endCB", PhaseKind::GC_END) \
|
||||
_(Barriers, "brrier", PhaseKind::BARRIER)
|
||||
|
||||
const char* ExplainAbortReason(gc::AbortReason reason);
|
||||
const char* ExplainInvocationKind(JSGCInvocationKind gckind);
|
||||
|
@ -174,7 +102,7 @@ const char* ExplainInvocationKind(JSGCInvocationKind gckind);
|
|||
*
|
||||
* During execution, a child phase can be activated multiple times, and the
|
||||
* total time will be accumulated. (So for example, you can start and end
|
||||
* PHASE_MARK_ROOTS multiple times before completing the parent phase.)
|
||||
* PhaseKind::MARK_ROOTS multiple times before completing the parent phase.)
|
||||
*
|
||||
* Incremental GC is represented by recording separate timing results for each
|
||||
* slice within the overall GC.
|
||||
|
@ -190,26 +118,8 @@ struct Statistics
|
|||
using TimeDuration = mozilla::TimeDuration;
|
||||
using TimeStamp = mozilla::TimeStamp;
|
||||
|
||||
/*
|
||||
* Phases are allowed to have multiple parents, though any path from root
|
||||
* to leaf is allowed at most one multi-parented phase. We keep a full set
|
||||
* of timings for each of the multi-parented phases, to be able to record
|
||||
* all the timings in the expanded tree induced by our dag.
|
||||
*
|
||||
* Note that this wastes quite a bit of space, since we have a whole
|
||||
* separate array of timing data containing all the phases. We could be
|
||||
* more clever and keep an array of pointers biased by the offset of the
|
||||
* multi-parented phase, and thereby preserve the simple
|
||||
* timings[slot][PHASE_*] indexing. But the complexity doesn't seem worth
|
||||
* the few hundred bytes of savings. If we want to extend things to full
|
||||
* DAGs, this decision should be reconsidered.
|
||||
*/
|
||||
static const size_t MaxMultiparentPhases = 6;
|
||||
static const size_t NumTimingArrays = MaxMultiparentPhases + 1;
|
||||
|
||||
/* Create a convenient type for referring to tables of phase times. */
|
||||
using PhaseTimeTable =
|
||||
Array<EnumeratedArray<Phase, PHASE_LIMIT, TimeDuration>, NumTimingArrays>;
|
||||
// Create a convenient type for referring to tables of phase times.
|
||||
using PhaseTimeTable = EnumeratedArray<Phase, Phase::LIMIT, TimeDuration>;
|
||||
|
||||
static MOZ_MUST_USE bool initialize();
|
||||
|
||||
|
@ -219,9 +129,9 @@ struct Statistics
|
|||
Statistics(const Statistics&) = delete;
|
||||
Statistics& operator=(const Statistics&) = delete;
|
||||
|
||||
void beginPhase(Phase phase);
|
||||
void endPhase(Phase phase);
|
||||
void endParallelPhase(Phase phase, const GCParallelTask* task);
|
||||
void beginPhase(PhaseKind phaseKind);
|
||||
void endPhase(PhaseKind phaseKind);
|
||||
void endParallelPhase(PhaseKind phaseKind, const GCParallelTask* task);
|
||||
|
||||
// Occasionally, we may be in the middle of something that is tracked by
|
||||
// this class, and we need to do something unusual (eg evict the nursery)
|
||||
|
@ -229,11 +139,11 @@ struct Statistics
|
|||
// currently tracked phase stack, at which time the caller is free to do
|
||||
// other tracked operations.
|
||||
//
|
||||
// This also happens internally with the PHASE_MUTATOR "phase". While in
|
||||
// This also happens internally with the PhaseKind::MUTATOR "phase". While in
|
||||
// this phase, any beginPhase will automatically suspend the non-GC phase,
|
||||
// until that inner stack is complete, at which time it will automatically
|
||||
// resume the non-GC phase. Explicit suspensions do not get auto-resumed.
|
||||
void suspendPhases(Phase suspension = PHASE_EXPLICIT_SUSPENSION);
|
||||
void suspendPhases(PhaseKind suspension = PhaseKind::EXPLICIT_SUSPENSION);
|
||||
|
||||
// Resume a suspended stack of phases.
|
||||
void resumePhases();
|
||||
|
@ -293,14 +203,7 @@ struct Statistics
|
|||
TimeDuration clearMaxGCPauseAccumulator();
|
||||
TimeDuration getMaxGCPauseSinceClear();
|
||||
|
||||
// Return the current phase, suppressing the synthetic PHASE_MUTATOR phase.
|
||||
Phase currentPhase() {
|
||||
if (phaseNestingDepth == 0)
|
||||
return PHASE_NONE;
|
||||
if (phaseNestingDepth == 1)
|
||||
return phaseNesting[0] == PHASE_MUTATOR ? PHASE_NONE : phaseNesting[0];
|
||||
return phaseNesting[phaseNestingDepth - 1];
|
||||
}
|
||||
PhaseKind currentPhaseKind() const;
|
||||
|
||||
static const size_t MAX_NESTING = 20;
|
||||
|
||||
|
@ -373,7 +276,7 @@ struct Statistics
|
|||
SliceDataVector slices_;
|
||||
|
||||
/* Most recent time when the given phase started. */
|
||||
EnumeratedArray<Phase, PHASE_LIMIT, TimeStamp> phaseStartTimes;
|
||||
EnumeratedArray<Phase, Phase::LIMIT, TimeStamp> phaseStartTimes;
|
||||
|
||||
/* Bookkeeping for GC timings when timingMutator is true */
|
||||
TimeStamp timedGCStart;
|
||||
|
@ -382,9 +285,6 @@ struct Statistics
|
|||
/* Total time in a given phase for this GC. */
|
||||
PhaseTimeTable phaseTimes;
|
||||
|
||||
/* Total time in a given phase over all GCs. */
|
||||
PhaseTimeTable phaseTotals;
|
||||
|
||||
/* Number of events of this type for this GC. */
|
||||
EnumeratedArray<Stat,
|
||||
STAT_LIMIT,
|
||||
|
@ -403,13 +303,12 @@ struct Statistics
|
|||
/* Phases that are currently on stack. */
|
||||
Array<Phase, MAX_NESTING> phaseNesting;
|
||||
size_t phaseNestingDepth;
|
||||
size_t activeDagSlot;
|
||||
|
||||
/*
|
||||
* Certain phases can interrupt the phase stack, eg callback phases. When
|
||||
* this happens, we move the suspended phases over to a sepearate list,
|
||||
* terminated by a dummy PHASE_SUSPENSION phase (so that we can nest
|
||||
* suspensions by suspending multiple stacks with a PHASE_SUSPENSION in
|
||||
* terminated by a dummy PhaseKind::SUSPENSION phase (so that we can nest
|
||||
* suspensions by suspending multiple stacks with a PhaseKind::SUSPENSION in
|
||||
* between).
|
||||
*/
|
||||
Array<Phase, MAX_NESTING * 3> suspendedPhases;
|
||||
|
@ -446,9 +345,13 @@ FOR_EACH_GC_PROFILE_TIME(DEFINE_TIME_KEY)
|
|||
ProfileDurations totalTimes_;
|
||||
uint64_t sliceCount_;
|
||||
|
||||
Phase currentPhase() const;
|
||||
Phase lookupChildPhase(PhaseKind phaseKind) const;
|
||||
|
||||
void beginGC(JSGCInvocationKind kind);
|
||||
void endGC();
|
||||
|
||||
void recordPhaseBegin(Phase phase);
|
||||
void recordPhaseEnd(Phase phase);
|
||||
|
||||
void gcDuration(TimeDuration* total, TimeDuration* maxPause) const;
|
||||
|
@ -488,24 +391,24 @@ struct MOZ_RAII AutoGCSlice
|
|||
|
||||
struct MOZ_RAII AutoPhase
|
||||
{
|
||||
AutoPhase(Statistics& stats, Phase phase)
|
||||
: stats(stats), task(nullptr), phase(phase), enabled(true)
|
||||
AutoPhase(Statistics& stats, PhaseKind phaseKind)
|
||||
: stats(stats), task(nullptr), phaseKind(phaseKind), enabled(true)
|
||||
{
|
||||
stats.beginPhase(phase);
|
||||
stats.beginPhase(phaseKind);
|
||||
}
|
||||
|
||||
AutoPhase(Statistics& stats, bool condition, Phase phase)
|
||||
: stats(stats), task(nullptr), phase(phase), enabled(condition)
|
||||
AutoPhase(Statistics& stats, bool condition, PhaseKind phaseKind)
|
||||
: stats(stats), task(nullptr), phaseKind(phaseKind), enabled(condition)
|
||||
{
|
||||
if (enabled)
|
||||
stats.beginPhase(phase);
|
||||
stats.beginPhase(phaseKind);
|
||||
}
|
||||
|
||||
AutoPhase(Statistics& stats, const GCParallelTask& task, Phase phase)
|
||||
: stats(stats), task(&task), phase(phase), enabled(true)
|
||||
AutoPhase(Statistics& stats, const GCParallelTask& task, PhaseKind phaseKind)
|
||||
: stats(stats), task(&task), phaseKind(phaseKind), enabled(true)
|
||||
{
|
||||
if (enabled)
|
||||
stats.beginPhase(phase);
|
||||
stats.beginPhase(phaseKind);
|
||||
}
|
||||
|
||||
~AutoPhase() {
|
||||
|
@ -514,13 +417,13 @@ struct MOZ_RAII AutoPhase
|
|||
// spent waiting to join with helper threads), but should start
|
||||
// recording total work on helper threads sometime by calling
|
||||
// endParallelPhase here if task is nonnull.
|
||||
stats.endPhase(phase);
|
||||
stats.endPhase(phaseKind);
|
||||
}
|
||||
}
|
||||
|
||||
Statistics& stats;
|
||||
const GCParallelTask* task;
|
||||
Phase phase;
|
||||
PhaseKind phaseKind;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ gc::GCRuntime::startVerifyPreBarriers()
|
|||
for (auto chunk = allNonEmptyChunks(); !chunk.done(); chunk.next())
|
||||
chunk->bitmap.clear();
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_TRACE_HEAP);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
|
||||
const size_t size = 64 * 1024 * 1024;
|
||||
trc->root = (VerifyNode*)js_malloc(size);
|
||||
|
@ -680,7 +680,7 @@ js::CheckGrayMarkingState(JSRuntime* rt)
|
|||
if (!rt->gc.areGrayBitsValid())
|
||||
return true;
|
||||
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PHASE_TRACE_HEAP);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
AutoTraceSession session(rt, JS::HeapState::Tracing);
|
||||
CheckGrayMarkingTracer tracer(rt);
|
||||
if (!tracer.init())
|
||||
|
|
|
@ -698,7 +698,7 @@ JSCompartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc)
|
|||
/* static */ void
|
||||
JSCompartment::traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc)
|
||||
{
|
||||
gcstats::AutoPhase ap(trc->runtime()->gc.stats(), gcstats::PHASE_MARK_CCWS);
|
||||
gcstats::AutoPhase ap(trc->runtime()->gc.stats(), gcstats::PhaseKind::MARK_CCWS);
|
||||
MOZ_ASSERT(JS::CurrentThreadIsHeapMajorCollecting());
|
||||
for (CompartmentsIter c(trc->runtime(), SkipAtoms); !c.done(); c.next()) {
|
||||
if (!c->zone()->isCollecting())
|
||||
|
|
|
@ -1189,7 +1189,7 @@ js::DumpHeap(JSContext* cx, FILE* fp, js::DumpHeapNurseryBehaviour nurseryBehavi
|
|||
{
|
||||
JSRuntime* rt = cx->runtime();
|
||||
js::gc::AutoPrepareForTracing prep(cx, WithAtoms);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PHASE_TRACE_HEAP);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
rt->gc.traceRuntime(&dtrc, prep.session().lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -540,9 +540,12 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
|
|||
if (fun->hasResolvedName())
|
||||
return true;
|
||||
|
||||
RootedAtom name(cx);
|
||||
if (!JSFunction::getUnresolvedName(cx, fun, &name))
|
||||
return false;
|
||||
|
||||
// Don't define an own .name property for unnamed functions.
|
||||
JSAtom* name = fun->getUnresolvedName(cx);
|
||||
if (name == nullptr)
|
||||
if (!name)
|
||||
return true;
|
||||
|
||||
v.setString(name);
|
||||
|
@ -1044,7 +1047,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto AppendPrelude = [&out, &fun]() {
|
||||
auto AppendPrelude = [cx, &out, &fun]() {
|
||||
if (fun->isAsync()) {
|
||||
if (!out.append("async "))
|
||||
return false;
|
||||
|
@ -1063,6 +1066,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
|||
if (fun->explicitName()) {
|
||||
if (!out.append(' '))
|
||||
return false;
|
||||
if (fun->isBoundFunction()) {
|
||||
if (!out.append(cx->names().boundWithSpace))
|
||||
return false;
|
||||
}
|
||||
if (!out.append(fun->explicitName()))
|
||||
return false;
|
||||
}
|
||||
|
@ -1365,23 +1372,42 @@ JSFunction::getUnresolvedLength(JSContext* cx, HandleFunction fun, MutableHandle
|
|||
return true;
|
||||
}
|
||||
|
||||
JSAtom*
|
||||
JSFunction::getUnresolvedName(JSContext* cx)
|
||||
/* static */ bool
|
||||
JSFunction::getUnresolvedName(JSContext* cx, HandleFunction fun, MutableHandleAtom v)
|
||||
{
|
||||
MOZ_ASSERT(!IsInternalFunctionObject(*this));
|
||||
MOZ_ASSERT(!hasResolvedName());
|
||||
MOZ_ASSERT(!IsInternalFunctionObject(*fun));
|
||||
MOZ_ASSERT(!fun->hasResolvedName());
|
||||
|
||||
if (isClassConstructor()) {
|
||||
JSAtom* name = fun->explicitOrCompileTimeName();
|
||||
if (fun->isClassConstructor()) {
|
||||
// It's impossible to have an empty named class expression. We use
|
||||
// empty as a sentinel when creating default class constructors.
|
||||
MOZ_ASSERT(explicitOrCompileTimeName() != cx->names().empty);
|
||||
MOZ_ASSERT(name != cx->names().empty);
|
||||
|
||||
// Unnamed class expressions should not get a .name property at all.
|
||||
return explicitOrCompileTimeName();
|
||||
if (name)
|
||||
v.set(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return explicitOrCompileTimeName() != nullptr ? explicitOrCompileTimeName()
|
||||
: cx->names().empty;
|
||||
if (fun->isBoundFunction()) {
|
||||
// Bound functions are never unnamed.
|
||||
MOZ_ASSERT(name);
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append(cx->names().boundWithSpace) || !sb.append(name))
|
||||
return false;
|
||||
|
||||
JSAtom* boundName = sb.finishAtom();
|
||||
if (!boundName)
|
||||
return false;
|
||||
|
||||
v.set(boundName);
|
||||
return true;
|
||||
}
|
||||
|
||||
v.set(name != nullptr ? name : cx->names().empty);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const js::Value&
|
||||
|
|
|
@ -312,7 +312,8 @@ class JSFunction : public js::NativeObject
|
|||
static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun,
|
||||
js::MutableHandleValue v);
|
||||
|
||||
JSAtom* getUnresolvedName(JSContext* cx);
|
||||
static bool getUnresolvedName(JSContext* cx, js::HandleFunction fun,
|
||||
js::MutableHandleAtom v);
|
||||
|
||||
JSAtom* explicitName() const {
|
||||
return (hasCompileTimeName() || hasGuessedAtom()) ? nullptr : atom_.get();
|
||||
|
|
190
js/src/jsgc.cpp
190
js/src/jsgc.cpp
|
@ -323,7 +323,7 @@ FOR_EACH_ALLOCKIND(EXPAND_THINGS_PER_ARENA)
|
|||
|
||||
struct js::gc::FinalizePhase
|
||||
{
|
||||
gcstats::Phase statsPhase;
|
||||
gcstats::PhaseKind statsPhase;
|
||||
AllocKinds kinds;
|
||||
};
|
||||
|
||||
|
@ -331,7 +331,7 @@ struct js::gc::FinalizePhase
|
|||
* Finalization order for objects swept incrementally on the active thread.
|
||||
*/
|
||||
static const FinalizePhase ForegroundObjectFinalizePhase = {
|
||||
gcstats::PHASE_SWEEP_OBJECT, {
|
||||
gcstats::PhaseKind::SWEEP_OBJECT, {
|
||||
AllocKind::OBJECT0,
|
||||
AllocKind::OBJECT2,
|
||||
AllocKind::OBJECT4,
|
||||
|
@ -346,17 +346,17 @@ static const FinalizePhase ForegroundObjectFinalizePhase = {
|
|||
*/
|
||||
static const FinalizePhase IncrementalFinalizePhases[] = {
|
||||
{
|
||||
gcstats::PHASE_SWEEP_STRING, {
|
||||
gcstats::PhaseKind::SWEEP_STRING, {
|
||||
AllocKind::EXTERNAL_STRING
|
||||
}
|
||||
},
|
||||
{
|
||||
gcstats::PHASE_SWEEP_SCRIPT, {
|
||||
gcstats::PhaseKind::SWEEP_SCRIPT, {
|
||||
AllocKind::SCRIPT
|
||||
}
|
||||
},
|
||||
{
|
||||
gcstats::PHASE_SWEEP_JITCODE, {
|
||||
gcstats::PhaseKind::SWEEP_JITCODE, {
|
||||
AllocKind::JITCODE
|
||||
}
|
||||
}
|
||||
|
@ -367,12 +367,12 @@ static const FinalizePhase IncrementalFinalizePhases[] = {
|
|||
*/
|
||||
static const FinalizePhase BackgroundFinalizePhases[] = {
|
||||
{
|
||||
gcstats::PHASE_SWEEP_SCRIPT, {
|
||||
gcstats::PhaseKind::SWEEP_SCRIPT, {
|
||||
AllocKind::LAZY_SCRIPT
|
||||
}
|
||||
},
|
||||
{
|
||||
gcstats::PHASE_SWEEP_OBJECT, {
|
||||
gcstats::PhaseKind::SWEEP_OBJECT, {
|
||||
AllocKind::FUNCTION,
|
||||
AllocKind::FUNCTION_EXTENDED,
|
||||
AllocKind::OBJECT0_BACKGROUND,
|
||||
|
@ -384,17 +384,17 @@ static const FinalizePhase BackgroundFinalizePhases[] = {
|
|||
}
|
||||
},
|
||||
{
|
||||
gcstats::PHASE_SWEEP_SCOPE, {
|
||||
gcstats::PhaseKind::SWEEP_SCOPE, {
|
||||
AllocKind::SCOPE,
|
||||
}
|
||||
},
|
||||
{
|
||||
gcstats::PHASE_SWEEP_REGEXP_SHARED, {
|
||||
gcstats::PhaseKind::SWEEP_REGEXP_SHARED, {
|
||||
AllocKind::REGEXP_SHARED,
|
||||
}
|
||||
},
|
||||
{
|
||||
gcstats::PHASE_SWEEP_STRING, {
|
||||
gcstats::PhaseKind::SWEEP_STRING, {
|
||||
AllocKind::FAT_INLINE_STRING,
|
||||
AllocKind::STRING,
|
||||
AllocKind::FAT_INLINE_ATOM,
|
||||
|
@ -403,7 +403,7 @@ static const FinalizePhase BackgroundFinalizePhases[] = {
|
|||
}
|
||||
},
|
||||
{
|
||||
gcstats::PHASE_SWEEP_SHAPE, {
|
||||
gcstats::PhaseKind::SWEEP_SHAPE, {
|
||||
AllocKind::SHAPE,
|
||||
AllocKind::ACCESSOR_SHAPE,
|
||||
AllocKind::BASE_SHAPE,
|
||||
|
@ -2137,7 +2137,7 @@ bool
|
|||
GCRuntime::relocateArenas(Zone* zone, JS::gcreason::Reason reason, Arena*& relocatedListOut,
|
||||
SliceBudget& sliceBudget)
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_COMPACT_MOVE);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT_MOVE);
|
||||
|
||||
MOZ_ASSERT(!zone->isPreservingCode());
|
||||
MOZ_ASSERT(CanRelocateZone(zone));
|
||||
|
@ -2465,7 +2465,7 @@ GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, s
|
|||
|
||||
for (size_t i = 0; i < bgTaskCount && !bgArenas.done(); i++) {
|
||||
bgTasks[i].emplace(rt, &bgArenas, lock);
|
||||
startTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS, lock);
|
||||
startTask(*bgTasks[i], gcstats::PhaseKind::COMPACT_UPDATE_CELLS, lock);
|
||||
tasksStarted = i;
|
||||
}
|
||||
}
|
||||
|
@ -2476,7 +2476,7 @@ GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, s
|
|||
AutoLockHelperThreadState lock;
|
||||
|
||||
for (size_t i = 0; i < tasksStarted; i++)
|
||||
joinTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS, lock);
|
||||
joinTask(*bgTasks[i], gcstats::PhaseKind::COMPACT_UPDATE_CELLS, lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2560,7 +2560,7 @@ GCRuntime::updateZonePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAc
|
|||
MOZ_ASSERT(!rt->isBeingDestroyed());
|
||||
MOZ_ASSERT(zone->isGCCompacting());
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_COMPACT_UPDATE);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT_UPDATE);
|
||||
MovingTracer trc(rt);
|
||||
|
||||
zone->fixupAfterMovingGC();
|
||||
|
@ -2578,7 +2578,7 @@ GCRuntime::updateZonePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAc
|
|||
|
||||
// Mark roots to update them.
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_ROOTS);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
|
||||
WeakMapBase::traceZone(zone, &trc);
|
||||
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
|
||||
|
@ -2603,7 +2603,7 @@ GCRuntime::updateRuntimePointersToRelocatedCells(AutoLockForExclusiveAccess& loc
|
|||
{
|
||||
MOZ_ASSERT(!rt->isBeingDestroyed());
|
||||
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PHASE_COMPACT_UPDATE);
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PhaseKind::COMPACT_UPDATE);
|
||||
MovingTracer trc(rt);
|
||||
|
||||
JSCompartment::fixupCrossCompartmentWrappersAfterMovingGC(&trc);
|
||||
|
@ -2614,7 +2614,7 @@ GCRuntime::updateRuntimePointersToRelocatedCells(AutoLockForExclusiveAccess& loc
|
|||
|
||||
// Mark roots to update them.
|
||||
{
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PHASE_MARK_ROOTS);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
Debugger::traceAllForMovingGC(&trc);
|
||||
Debugger::traceIncomingCrossCompartmentEdges(&trc);
|
||||
|
||||
|
@ -3884,7 +3884,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
|||
if (isIncremental) {
|
||||
js::CancelOffThreadIonCompile(rt, JS::Zone::Mark);
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_DISCARD_CODE);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_DISCARD_CODE);
|
||||
zone->discardJitCode(rt->defaultFreeOp());
|
||||
}
|
||||
}
|
||||
|
@ -3899,7 +3899,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
|||
*/
|
||||
if (invocationKind == GC_SHRINK) {
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_RELAZIFY_FUNCTIONS);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::RELAZIFY_FUNCTIONS);
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
if (zone->isSelfHostingZone())
|
||||
continue;
|
||||
|
@ -3909,7 +3909,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
|||
}
|
||||
|
||||
/* Purge ShapeTables. */
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_PURGE_SHAPE_TABLES);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::PURGE_SHAPE_TABLES);
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
if (zone->keepShapeTables() || zone->isSelfHostingZone())
|
||||
continue;
|
||||
|
@ -3939,17 +3939,17 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
|||
* a GC hazard would exist.
|
||||
*/
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_PURGE);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::PURGE);
|
||||
purgeRuntime(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark phase.
|
||||
*/
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PHASE_MARK);
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PhaseKind::MARK);
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_UNMARK);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::UNMARK);
|
||||
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
/* Unmark everything in the zones being collected. */
|
||||
|
@ -3964,7 +3964,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
|||
|
||||
traceRuntimeForMajorGC(gcmarker, lock);
|
||||
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PHASE_MARK_ROOTS);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
|
||||
if (isIncremental) {
|
||||
bufferGrayRoots();
|
||||
|
@ -3977,7 +3977,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
|||
void
|
||||
GCRuntime::markCompartments()
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_MARK_COMPARTMENTS);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_COMPARTMENTS);
|
||||
|
||||
/*
|
||||
* This code ensures that if a compartment is "dead", then it will be
|
||||
|
@ -4045,7 +4045,7 @@ GCRuntime::markCompartments()
|
|||
|
||||
template <class ZoneIterT>
|
||||
void
|
||||
GCRuntime::markWeakReferences(gcstats::Phase phase)
|
||||
GCRuntime::markWeakReferences(gcstats::PhaseKind phase)
|
||||
{
|
||||
MOZ_ASSERT(marker.isDrained());
|
||||
|
||||
|
@ -4082,14 +4082,14 @@ GCRuntime::markWeakReferences(gcstats::Phase phase)
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::markWeakReferencesInCurrentGroup(gcstats::Phase phase)
|
||||
GCRuntime::markWeakReferencesInCurrentGroup(gcstats::PhaseKind phase)
|
||||
{
|
||||
markWeakReferences<GCSweepGroupIter>(phase);
|
||||
}
|
||||
|
||||
template <class ZoneIterT, class CompartmentIterT>
|
||||
void
|
||||
GCRuntime::markGrayReferences(gcstats::Phase phase)
|
||||
GCRuntime::markGrayReferences(gcstats::PhaseKind phase)
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), phase);
|
||||
if (hasBufferedGrayRoots()) {
|
||||
|
@ -4105,19 +4105,19 @@ GCRuntime::markGrayReferences(gcstats::Phase phase)
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::markGrayReferencesInCurrentGroup(gcstats::Phase phase)
|
||||
GCRuntime::markGrayReferencesInCurrentGroup(gcstats::PhaseKind phase)
|
||||
{
|
||||
markGrayReferences<GCSweepGroupIter, GCCompartmentGroupIter>(phase);
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::markAllWeakReferences(gcstats::Phase phase)
|
||||
GCRuntime::markAllWeakReferences(gcstats::PhaseKind phase)
|
||||
{
|
||||
markWeakReferences<GCZonesIter>(phase);
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::markAllGrayReferences(gcstats::Phase phase)
|
||||
GCRuntime::markAllGrayReferences(gcstats::PhaseKind phase)
|
||||
{
|
||||
markGrayReferences<GCZonesIter, GCCompartmentsIter>(phase);
|
||||
}
|
||||
|
@ -4245,10 +4245,10 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock)
|
|||
gc->incrementalState = State::MarkRoots;
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(gc->stats(), gcstats::PHASE_MARK);
|
||||
gcstats::AutoPhase ap(gc->stats(), gcstats::PhaseKind::MARK);
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(gc->stats(), gcstats::PHASE_UNMARK);
|
||||
gcstats::AutoPhase ap(gc->stats(), gcstats::PhaseKind::UNMARK);
|
||||
|
||||
for (GCZonesIter zone(runtime); !zone.done(); zone.next())
|
||||
WeakMapBase::unmarkZone(zone);
|
||||
|
@ -4269,10 +4269,10 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock)
|
|||
|
||||
gc->incrementalState = State::Sweep;
|
||||
{
|
||||
gcstats::AutoPhase ap1(gc->stats(), gcstats::PHASE_SWEEP);
|
||||
gcstats::AutoPhase ap2(gc->stats(), gcstats::PHASE_SWEEP_MARK);
|
||||
gcstats::AutoPhase ap1(gc->stats(), gcstats::PhaseKind::SWEEP);
|
||||
gcstats::AutoPhase ap2(gc->stats(), gcstats::PhaseKind::SWEEP_MARK);
|
||||
|
||||
gc->markAllWeakReferences(gcstats::PHASE_SWEEP_MARK_WEAK);
|
||||
gc->markAllWeakReferences(gcstats::PhaseKind::SWEEP_MARK_WEAK);
|
||||
|
||||
/* Update zone state for gray marking. */
|
||||
for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
|
||||
|
@ -4281,8 +4281,8 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock)
|
|||
}
|
||||
gc->marker.setMarkColorGray();
|
||||
|
||||
gc->markAllGrayReferences(gcstats::PHASE_SWEEP_MARK_GRAY);
|
||||
gc->markAllWeakReferences(gcstats::PHASE_SWEEP_MARK_GRAY_WEAK);
|
||||
gc->markAllGrayReferences(gcstats::PhaseKind::SWEEP_MARK_GRAY);
|
||||
gc->markAllWeakReferences(gcstats::PhaseKind::SWEEP_MARK_GRAY_WEAK);
|
||||
|
||||
/* Restore zone state. */
|
||||
for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
|
||||
|
@ -4770,9 +4770,9 @@ MarkIncomingCrossCompartmentPointers(JSRuntime* rt, const uint32_t color)
|
|||
{
|
||||
MOZ_ASSERT(color == BLACK || color == GRAY);
|
||||
|
||||
static const gcstats::Phase statsPhases[] = {
|
||||
gcstats::PHASE_SWEEP_MARK_INCOMING_BLACK,
|
||||
gcstats::PHASE_SWEEP_MARK_INCOMING_GRAY
|
||||
static const gcstats::PhaseKind statsPhases[] = {
|
||||
gcstats::PhaseKind::SWEEP_MARK_INCOMING_BLACK,
|
||||
gcstats::PhaseKind::SWEEP_MARK_INCOMING_GRAY
|
||||
};
|
||||
gcstats::AutoPhase ap1(rt->gc.stats(), statsPhases[color]);
|
||||
|
||||
|
@ -4896,7 +4896,7 @@ js::NotifyGCPostSwap(JSObject* a, JSObject* b, unsigned removedFlags)
|
|||
void
|
||||
GCRuntime::endMarkingSweepGroup()
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_MARK);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP_MARK);
|
||||
|
||||
/*
|
||||
* Mark any incoming black pointers from previously swept compartments
|
||||
|
@ -4904,7 +4904,7 @@ GCRuntime::endMarkingSweepGroup()
|
|||
* black by the action of UnmarkGray.
|
||||
*/
|
||||
MarkIncomingCrossCompartmentPointers(rt, BLACK);
|
||||
markWeakReferencesInCurrentGroup(gcstats::PHASE_SWEEP_MARK_WEAK);
|
||||
markWeakReferencesInCurrentGroup(gcstats::PhaseKind::SWEEP_MARK_WEAK);
|
||||
|
||||
/*
|
||||
* Change state of current group to MarkGray to restrict marking to this
|
||||
|
@ -4922,8 +4922,8 @@ GCRuntime::endMarkingSweepGroup()
|
|||
MarkIncomingCrossCompartmentPointers(rt, GRAY);
|
||||
|
||||
/* Mark gray roots and mark transitively inside the current compartment group. */
|
||||
markGrayReferencesInCurrentGroup(gcstats::PHASE_SWEEP_MARK_GRAY);
|
||||
markWeakReferencesInCurrentGroup(gcstats::PHASE_SWEEP_MARK_GRAY_WEAK);
|
||||
markGrayReferencesInCurrentGroup(gcstats::PhaseKind::SWEEP_MARK_GRAY);
|
||||
markWeakReferencesInCurrentGroup(gcstats::PhaseKind::SWEEP_MARK_GRAY_WEAK);
|
||||
|
||||
/* Restore marking state. */
|
||||
for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) {
|
||||
|
@ -5063,7 +5063,7 @@ SweepUniqueIds(JSRuntime* runtime)
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked)
|
||||
GCRuntime::startTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked)
|
||||
{
|
||||
if (!task.startWithLockHeld(locked)) {
|
||||
AutoUnlockHelperThreadState unlock(locked);
|
||||
|
@ -5073,7 +5073,7 @@ GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperT
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::joinTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked)
|
||||
GCRuntime::joinTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked)
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), task, phase);
|
||||
task.joinWithLockHeld(locked);
|
||||
|
@ -5086,13 +5086,13 @@ GCRuntime::sweepDebuggerOnMainThread(FreeOp* fop)
|
|||
// This can modify weakmaps and so must happen before weakmap sweeping.
|
||||
Debugger::sweepAll(fop);
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_COMPARTMENTS);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP_COMPARTMENTS);
|
||||
|
||||
// Sweep debug environment information. This performs lookups in the Zone's
|
||||
// unique IDs table and so must not happen in parallel with sweeping that
|
||||
// table.
|
||||
{
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PHASE_SWEEP_MISC);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::SWEEP_MISC);
|
||||
for (GCCompartmentGroupIter c(rt); !c.done(); c.next())
|
||||
c->sweepDebugEnvironments();
|
||||
}
|
||||
|
@ -5100,7 +5100,7 @@ GCRuntime::sweepDebuggerOnMainThread(FreeOp* fop)
|
|||
// Sweep breakpoints. This is done here to be with the other debug sweeping,
|
||||
// although note that it can cause JIT code to be patched.
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_BREAKPOINT);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP_BREAKPOINT);
|
||||
for (GCSweepGroupIter zone(rt); !zone.done(); zone.next())
|
||||
zone->sweepBreakpoints(fop);
|
||||
}
|
||||
|
@ -5110,7 +5110,7 @@ void
|
|||
GCRuntime::sweepJitDataOnMainThread(FreeOp* fop)
|
||||
{
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_JIT_DATA);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP_JIT_DATA);
|
||||
|
||||
// Cancel any active or pending off thread compilations.
|
||||
js::CancelOffThreadIonCompile(rt, JS::Zone::Sweep);
|
||||
|
@ -5132,14 +5132,14 @@ GCRuntime::sweepJitDataOnMainThread(FreeOp* fop)
|
|||
}
|
||||
|
||||
{
|
||||
gcstats::AutoPhase apdc(stats(), gcstats::PHASE_SWEEP_DISCARD_CODE);
|
||||
gcstats::AutoPhase apdc(stats(), gcstats::PhaseKind::SWEEP_DISCARD_CODE);
|
||||
for (GCSweepGroupIter zone(rt); !zone.done(); zone.next())
|
||||
zone->discardJitCode(fop);
|
||||
}
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PHASE_SWEEP_TYPES);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PHASE_SWEEP_TYPES_BEGIN);
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PhaseKind::SWEEP_TYPES);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::SWEEP_TYPES_BEGIN);
|
||||
for (GCSweepGroupIter zone(rt); !zone.done(); zone.next())
|
||||
zone->beginSweepTypes(fop, releaseObservedTypes && !zone->isPreservingCode());
|
||||
}
|
||||
|
@ -5193,11 +5193,11 @@ class MOZ_RAII js::gc::AutoRunParallelTask : public GCParallelTask
|
|||
using Func = void (*)(JSRuntime*);
|
||||
|
||||
Func func_;
|
||||
gcstats::Phase phase_;
|
||||
gcstats::PhaseKind phase_;
|
||||
AutoLockHelperThreadState& lock_;
|
||||
|
||||
public:
|
||||
AutoRunParallelTask(JSRuntime* rt, Func func, gcstats::Phase phase,
|
||||
AutoRunParallelTask(JSRuntime* rt, Func func, gcstats::PhaseKind phase,
|
||||
AutoLockHelperThreadState& lock)
|
||||
: GCParallelTask(rt),
|
||||
func_(func),
|
||||
|
@ -5248,14 +5248,14 @@ GCRuntime::beginSweepingSweepGroup()
|
|||
FreeOp fop(rt);
|
||||
|
||||
{
|
||||
AutoPhase ap(stats(), PHASE_FINALIZE_START);
|
||||
AutoPhase ap(stats(), PhaseKind::FINALIZE_START);
|
||||
callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_PREPARE);
|
||||
{
|
||||
AutoPhase ap2(stats(), PHASE_WEAK_ZONES_CALLBACK);
|
||||
AutoPhase ap2(stats(), PhaseKind::WEAK_ZONES_CALLBACK);
|
||||
callWeakPointerZonesCallbacks();
|
||||
}
|
||||
{
|
||||
AutoPhase ap2(stats(), PHASE_WEAK_COMPARTMENT_CALLBACK);
|
||||
AutoPhase ap2(stats(), PhaseKind::WEAK_COMPARTMENT_CALLBACK);
|
||||
for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
|
||||
callWeakPointerCompartmentCallbacks(comp);
|
||||
|
@ -5271,22 +5271,22 @@ GCRuntime::beginSweepingSweepGroup()
|
|||
|
||||
Maybe<AutoRunParallelTask> sweepAtoms;
|
||||
if (sweepingAtoms)
|
||||
sweepAtoms.emplace(rt, SweepAtoms, PHASE_SWEEP_ATOMS, lock);
|
||||
sweepAtoms.emplace(rt, SweepAtoms, PhaseKind::SWEEP_ATOMS, lock);
|
||||
|
||||
AutoPhase ap(stats(), PHASE_SWEEP_COMPARTMENTS);
|
||||
AutoPhase ap(stats(), PhaseKind::SWEEP_COMPARTMENTS);
|
||||
AutoSCC scc(stats(), sweepGroupIndex);
|
||||
|
||||
AutoRunParallelTask sweepCCWrappers(rt, SweepCCWrappers, PHASE_SWEEP_CC_WRAPPER, lock);
|
||||
AutoRunParallelTask sweepObjectGroups(rt, SweepObjectGroups, PHASE_SWEEP_TYPE_OBJECT, lock);
|
||||
AutoRunParallelTask sweepRegExps(rt, SweepRegExps, PHASE_SWEEP_REGEXP, lock);
|
||||
AutoRunParallelTask sweepMisc(rt, SweepMisc, PHASE_SWEEP_MISC, lock);
|
||||
AutoRunParallelTask sweepCompTasks(rt, SweepCompressionTasks, PHASE_SWEEP_COMPRESSION, lock);
|
||||
AutoRunParallelTask sweepWeakMaps(rt, SweepWeakMaps, PHASE_SWEEP_WEAKMAPS, lock);
|
||||
AutoRunParallelTask sweepUniqueIds(rt, SweepUniqueIds, PHASE_SWEEP_UNIQUEIDS, lock);
|
||||
AutoRunParallelTask sweepCCWrappers(rt, SweepCCWrappers, PhaseKind::SWEEP_CC_WRAPPER, lock);
|
||||
AutoRunParallelTask sweepObjectGroups(rt, SweepObjectGroups, PhaseKind::SWEEP_TYPE_OBJECT, lock);
|
||||
AutoRunParallelTask sweepRegExps(rt, SweepRegExps, PhaseKind::SWEEP_REGEXP, lock);
|
||||
AutoRunParallelTask sweepMisc(rt, SweepMisc, PhaseKind::SWEEP_MISC, lock);
|
||||
AutoRunParallelTask sweepCompTasks(rt, SweepCompressionTasks, PhaseKind::SWEEP_COMPRESSION, lock);
|
||||
AutoRunParallelTask sweepWeakMaps(rt, SweepWeakMaps, PhaseKind::SWEEP_WEAKMAPS, lock);
|
||||
AutoRunParallelTask sweepUniqueIds(rt, SweepUniqueIds, PhaseKind::SWEEP_UNIQUEIDS, lock);
|
||||
|
||||
WeakCacheTaskVector sweepCacheTasks = PrepareWeakCacheTasks(rt);
|
||||
for (auto& task : sweepCacheTasks)
|
||||
startTask(task, PHASE_SWEEP_WEAK_CACHES, lock);
|
||||
startTask(task, PhaseKind::SWEEP_WEAK_CACHES, lock);
|
||||
|
||||
{
|
||||
AutoUnlockHelperThreadState unlock(lock);
|
||||
|
@ -5294,7 +5294,7 @@ GCRuntime::beginSweepingSweepGroup()
|
|||
}
|
||||
|
||||
for (auto& task : sweepCacheTasks)
|
||||
joinTask(task, PHASE_SWEEP_WEAK_CACHES, lock);
|
||||
joinTask(task, PhaseKind::SWEEP_WEAK_CACHES, lock);
|
||||
}
|
||||
|
||||
// Queue all GC things in all zones for sweeping, either on the foreground
|
||||
|
@ -5322,7 +5322,7 @@ void
|
|||
GCRuntime::endSweepingSweepGroup()
|
||||
{
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_FINALIZE_END);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::FINALIZE_END);
|
||||
FreeOp fop(rt);
|
||||
callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_END);
|
||||
}
|
||||
|
@ -5371,7 +5371,7 @@ GCRuntime::beginSweepPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcce
|
|||
|
||||
computeNonIncrementalMarkingForValidation(lock);
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP);
|
||||
|
||||
sweepOnBackgroundThread =
|
||||
reason != JS::gcreason::DESTROY_RUNTIME && !TraceEnabled() && CanUseExtraThreads();
|
||||
|
@ -5422,7 +5422,7 @@ ArenaLists::foregroundFinalize(FreeOp* fop, AllocKind thingKind, SliceBudget& sl
|
|||
}
|
||||
|
||||
IncrementalProgress
|
||||
GCRuntime::drainMarkStack(SliceBudget& sliceBudget, gcstats::Phase phase)
|
||||
GCRuntime::drainMarkStack(SliceBudget& sliceBudget, gcstats::PhaseKind phase)
|
||||
{
|
||||
/* Run a marking slice and return whether the stack is now empty. */
|
||||
gcstats::AutoPhase ap(stats(), phase);
|
||||
|
@ -5480,8 +5480,8 @@ GCRuntime::sweepTypeInformation(GCRuntime* gc, FreeOp* fop, Zone* zone, SliceBud
|
|||
|
||||
MOZ_ASSERT(kind == AllocKind::LIMIT);
|
||||
|
||||
gcstats::AutoPhase ap1(gc->stats(), gcstats::PHASE_SWEEP_COMPARTMENTS);
|
||||
gcstats::AutoPhase ap2(gc->stats(), gcstats::PHASE_SWEEP_TYPES);
|
||||
gcstats::AutoPhase ap1(gc->stats(), gcstats::PhaseKind::SWEEP_COMPARTMENTS);
|
||||
gcstats::AutoPhase ap2(gc->stats(), gcstats::PhaseKind::SWEEP_TYPES);
|
||||
|
||||
ArenaLists& al = zone->arenas;
|
||||
|
||||
|
@ -5495,7 +5495,7 @@ GCRuntime::sweepTypeInformation(GCRuntime* gc, FreeOp* fop, Zone* zone, SliceBud
|
|||
|
||||
// Finish sweeping type information in the zone.
|
||||
{
|
||||
gcstats::AutoPhase ap(gc->stats(), gcstats::PHASE_SWEEP_TYPES_END);
|
||||
gcstats::AutoPhase ap(gc->stats(), gcstats::PhaseKind::SWEEP_TYPES_END);
|
||||
zone->types.endSweep(gc->rt);
|
||||
}
|
||||
|
||||
|
@ -5541,7 +5541,7 @@ GCRuntime::sweepShapeTree(GCRuntime* gc, FreeOp* fop, Zone* zone, SliceBudget& b
|
|||
|
||||
MOZ_ASSERT(kind == AllocKind::LIMIT);
|
||||
|
||||
gcstats::AutoPhase ap(gc->stats(), gcstats::PHASE_SWEEP_SHAPE);
|
||||
gcstats::AutoPhase ap(gc->stats(), gcstats::PhaseKind::SWEEP_SHAPE);
|
||||
|
||||
ArenaLists& al = zone->arenas;
|
||||
|
||||
|
@ -5598,10 +5598,10 @@ GCRuntime::performSweepActions(SliceBudget& budget, AutoLockForExclusiveAccess&
|
|||
{
|
||||
AutoSetThreadIsSweeping threadIsSweeping;
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP);
|
||||
FreeOp fop(rt);
|
||||
|
||||
if (drainMarkStack(budget, gcstats::PHASE_SWEEP_MARK) == NotFinished)
|
||||
if (drainMarkStack(budget, gcstats::PhaseKind::SWEEP_MARK) == NotFinished)
|
||||
return NotFinished;
|
||||
|
||||
for (;;) {
|
||||
|
@ -5664,7 +5664,7 @@ GCRuntime::endSweepPhase(bool destroyingRuntime, AutoLockForExclusiveAccess& loc
|
|||
{
|
||||
AutoSetThreadIsSweeping threadIsSweeping;
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP);
|
||||
FreeOp fop(rt);
|
||||
|
||||
MOZ_ASSERT_IF(destroyingRuntime, !sweepOnBackgroundThread);
|
||||
|
@ -5683,7 +5683,7 @@ GCRuntime::endSweepPhase(bool destroyingRuntime, AutoLockForExclusiveAccess& loc
|
|||
}
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_DESTROY);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::DESTROY);
|
||||
|
||||
/*
|
||||
* Sweep script filenames after sweeping functions in the generic loop
|
||||
|
@ -5701,7 +5701,7 @@ GCRuntime::endSweepPhase(bool destroyingRuntime, AutoLockForExclusiveAccess& loc
|
|||
}
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_FINALIZE_END);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::FINALIZE_END);
|
||||
callFinalizeCallbacks(&fop, JSFINALIZE_COLLECTION_END);
|
||||
|
||||
if (allCCVisibleZonesWereCollected())
|
||||
|
@ -5728,7 +5728,7 @@ GCRuntime::beginCompactPhase()
|
|||
{
|
||||
MOZ_ASSERT(!isBackgroundSweeping());
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_COMPACT);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT);
|
||||
|
||||
MOZ_ASSERT(zonesToMaybeCompact.ref().isEmpty());
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
|
@ -5747,7 +5747,7 @@ GCRuntime::compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
|||
assertBackgroundSweepingFinished();
|
||||
MOZ_ASSERT(startedCompacting);
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_COMPACT);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT);
|
||||
|
||||
// TODO: JSScripts can move. If the sampler interrupts the GC in the
|
||||
// middle of relocating an arena, invalid JSScript pointers may be
|
||||
|
@ -5965,7 +5965,7 @@ GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoLockForExclusiveAccess
|
|||
isCompacting = wasCompacting;
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
|
||||
rt->gc.waitBackgroundSweepOrAllocEnd();
|
||||
}
|
||||
break;
|
||||
|
@ -5973,7 +5973,7 @@ GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoLockForExclusiveAccess
|
|||
|
||||
case State::Finalize: {
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
|
||||
rt->gc.waitBackgroundSweepOrAllocEnd();
|
||||
}
|
||||
|
||||
|
@ -6169,7 +6169,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
isIncremental = false;
|
||||
}
|
||||
|
||||
if (drainMarkStack(budget, gcstats::PHASE_MARK) == NotFinished)
|
||||
if (drainMarkStack(budget, gcstats::PhaseKind::MARK) == NotFinished)
|
||||
break;
|
||||
|
||||
MOZ_ASSERT(marker.isDrained());
|
||||
|
@ -6230,7 +6230,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
|
||||
case State::Finalize:
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
|
||||
|
||||
// Yield until background finalization is done.
|
||||
if (!budget.isUnlimited()) {
|
||||
|
@ -6246,8 +6246,8 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
{
|
||||
// Re-sweep the zones list, now that background finalization is
|
||||
// finished to actually remove and free dead zones.
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PHASE_SWEEP);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PHASE_DESTROY);
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PhaseKind::SWEEP);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::DESTROY);
|
||||
AutoSetThreadIsSweeping threadIsSweeping;
|
||||
FreeOp fop(rt);
|
||||
sweepZoneGroups(&fop, destroyingRuntime);
|
||||
|
@ -6280,7 +6280,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
|
||||
case State::Decommit:
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
|
||||
|
||||
// Yield until background decommit is done.
|
||||
if (!budget.isUnlimited() && decommitTask.isRunning())
|
||||
|
@ -6474,7 +6474,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
|
|||
TlsContext.get()->verifyIsSafeToGC();
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
|
||||
|
||||
// Background finalization and decommit are finished by defininition
|
||||
// before we can start a new GC session.
|
||||
|
@ -6688,7 +6688,7 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
|
|||
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (rt->hasZealMode(ZealMode::CheckHeapAfterGC)) {
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PHASE_TRACE_HEAP);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
CheckHeapAfterGC(rt);
|
||||
}
|
||||
#endif
|
||||
|
@ -6866,7 +6866,7 @@ GCRuntime::onOutOfMallocMemory(const AutoLockGC& lock)
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::Phase phase)
|
||||
GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::PhaseKind phase)
|
||||
{
|
||||
MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase>
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
static T extractUnbarriered(WriteBarrieredBase<T> v)
|
||||
static T extractUnbarriered(const WriteBarrieredBase<T>& v)
|
||||
{
|
||||
return v.get();
|
||||
}
|
||||
|
|
|
@ -739,3 +739,11 @@ if CONFIG['CLANG_CXX']:
|
|||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['NOMINMAX'] = True
|
||||
|
||||
# Generate GC statistics phase data.
|
||||
GENERATED_FILES += ['gc/StatsPhasesGenerated.h']
|
||||
StatsPhasesGeneratedHeader = GENERATED_FILES['gc/StatsPhasesGenerated.h']
|
||||
StatsPhasesGeneratedHeader.script = 'gc/GenerateStatsPhases.py:generateHeader'
|
||||
GENERATED_FILES += ['gc/StatsPhasesGenerated.cpp']
|
||||
StatsPhasesGeneratedCpp = GENERATED_FILES['gc/StatsPhasesGenerated.cpp']
|
||||
StatsPhasesGeneratedCpp.script = 'gc/GenerateStatsPhases.py:generateCpp'
|
||||
|
|
|
@ -503,39 +503,31 @@ intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp)
|
|||
bound->setExtendedSlot(BOUND_FUN_LENGTH_SLOT, NumberValue(length));
|
||||
|
||||
// Try to avoid invoking the resolve hook.
|
||||
JSAtom* name = nullptr;
|
||||
if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedName())
|
||||
name = targetObj->as<JSFunction>().getUnresolvedName(cx);
|
||||
RootedAtom name(cx);
|
||||
if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedName()) {
|
||||
if (!JSFunction::getUnresolvedName(cx, targetObj.as<JSFunction>(), &name))
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedString rootedName(cx);
|
||||
if (name) {
|
||||
rootedName = name;
|
||||
} else {
|
||||
// 19.2.3.2 Function.prototype.bind, steps 9-11.
|
||||
if (!name) {
|
||||
// 19.2.3.2 Function.prototype.bind, step 9.
|
||||
RootedValue targetName(cx);
|
||||
if (!GetProperty(cx, targetObj, targetObj, cx->names().name, &targetName))
|
||||
return false;
|
||||
|
||||
// 19.2.3.2 Function.prototype.bind, step 10.
|
||||
if (targetName.isString())
|
||||
rootedName = targetName.toString();
|
||||
if (targetName.isString() && !targetName.toString()->empty()) {
|
||||
name = AtomizeString(cx, targetName.toString());
|
||||
if (!name)
|
||||
return false;
|
||||
} else {
|
||||
name = cx->names().empty;
|
||||
}
|
||||
}
|
||||
|
||||
// 19.2.3.2 Function.prototype.bind, step 11 (Inlined SetFunctionName).
|
||||
MOZ_ASSERT(!bound->hasGuessedAtom());
|
||||
if (rootedName && !rootedName->empty()) {
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append(cx->names().boundWithSpace) || !sb.append(rootedName))
|
||||
return false;
|
||||
|
||||
RootedAtom nameAtom(cx, sb.finishAtom());
|
||||
if (!nameAtom)
|
||||
return false;
|
||||
|
||||
bound->setAtom(nameAtom);
|
||||
} else {
|
||||
bound->setAtom(cx->names().boundWithSpace);
|
||||
}
|
||||
bound->setAtom(name);
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
|
|
|
@ -7112,7 +7112,8 @@ nsLayoutUtils::GetReferenceFrame(nsIFrame* aFrame)
|
|||
{
|
||||
nsIFrame *f = aFrame;
|
||||
for (;;) {
|
||||
if (f->IsTransformed() || f->IsPreserve3DLeaf() || IsPopup(f)) {
|
||||
const nsStyleDisplay* disp = f->StyleDisplay();
|
||||
if (f->IsTransformed(disp) || f->IsPreserve3DLeaf(disp) || IsPopup(f)) {
|
||||
return f;
|
||||
}
|
||||
nsIFrame* parent = GetCrossDocParentFrame(f);
|
||||
|
|
|
@ -494,7 +494,7 @@ void ReflowInput::InitCBReflowInput()
|
|||
return;
|
||||
}
|
||||
|
||||
if (mParentReflowInput->mFrame == mFrame->GetContainingBlock()) {
|
||||
if (mParentReflowInput->mFrame == mFrame->GetContainingBlock(0, mStyleDisplay)) {
|
||||
// Inner table frames need to use the containing block of the outer
|
||||
// table frame.
|
||||
if (mFrame->IsTableFrame()) {
|
||||
|
@ -526,7 +526,7 @@ IsQuirkContainingBlockHeight(const ReflowInput* rs, LayoutFrameType aFrameType)
|
|||
// Note: This next condition could change due to a style change,
|
||||
// but that would cause a style reflow anyway, which means we're ok.
|
||||
if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
|
||||
if (!rs->mFrame->IsAbsolutelyPositioned()) {
|
||||
if (!rs->mFrame->IsAbsolutelyPositioned(rs->mStyleDisplay)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1980,7 +1980,7 @@ CalcQuirkContainingBlockHeight(const ReflowInput* aCBReflowInput)
|
|||
// not auto-height, use this as the percentage base. 2) If auto-height,
|
||||
// keep looking, unless the frame is positioned.
|
||||
if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
|
||||
if (rs->mFrame->IsAbsolutelyPositioned()) {
|
||||
if (rs->mFrame->IsAbsolutelyPositioned(rs->mStyleDisplay)) {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
|
@ -2061,7 +2061,7 @@ ReflowInput::ComputeContainingBlockRectangle(
|
|||
// mFrameType for abs-pos tables is NS_CSS_FRAME_TYPE_BLOCK, so we need to
|
||||
// special case them here.
|
||||
if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE ||
|
||||
(mFrame->IsTableFrame() && mFrame->IsAbsolutelyPositioned() &&
|
||||
(mFrame->IsTableFrame() && mFrame->IsAbsolutelyPositioned(mStyleDisplay) &&
|
||||
(mFrame->GetParent()->GetStateBits() & NS_FRAME_OUT_OF_FLOW))) {
|
||||
// See if the ancestor is block-level or inline-level
|
||||
if (NS_FRAME_GET_TYPE(aContainingBlockRI->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) {
|
||||
|
@ -2175,7 +2175,7 @@ ReflowInput::InitConstraints(nsPresContext* aPresContext,
|
|||
if (nullptr == mParentReflowInput || mFlags.mDummyParentReflowInput) {
|
||||
// XXXldb This doesn't mean what it used to!
|
||||
InitOffsets(wm, OffsetPercentBasis(mFrame, wm, aContainingBlockSize),
|
||||
aFrameType, mFlags, aBorder, aPadding);
|
||||
aFrameType, mFlags, aBorder, aPadding, mStyleDisplay);
|
||||
// Override mComputedMargin since reflow roots start from the
|
||||
// frame's boundary, which is inside the margin.
|
||||
ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
|
||||
|
@ -2234,7 +2234,7 @@ ReflowInput::InitConstraints(nsPresContext* aPresContext,
|
|||
WritingMode cbwm = cbrs->GetWritingMode();
|
||||
InitOffsets(cbwm, OffsetPercentBasis(mFrame, cbwm,
|
||||
cbSize.ConvertTo(cbwm, wm)),
|
||||
aFrameType, mFlags, aBorder, aPadding);
|
||||
aFrameType, mFlags, aBorder, aPadding, mStyleDisplay);
|
||||
|
||||
// For calculating the size of this box, we use its own writing mode
|
||||
const nsStyleCoord &blockSize = mStylePosition->BSize(wm);
|
||||
|
@ -2506,7 +2506,8 @@ SizeComputationInput::InitOffsets(WritingMode aWM,
|
|||
LayoutFrameType aFrameType,
|
||||
ReflowInputFlags aFlags,
|
||||
const nsMargin* aBorder,
|
||||
const nsMargin* aPadding)
|
||||
const nsMargin* aPadding,
|
||||
const nsStyleDisplay* aDisplay)
|
||||
{
|
||||
DISPLAY_INIT_OFFSETS(mFrame, this, aPercentBasis, aBorder, aPadding);
|
||||
|
||||
|
@ -2529,7 +2530,7 @@ SizeComputationInput::InitOffsets(WritingMode aWM,
|
|||
ComputedPhysicalMargin());
|
||||
|
||||
|
||||
const nsStyleDisplay *disp = mFrame->StyleDisplay();
|
||||
const nsStyleDisplay* disp = mFrame->StyleDisplayWithOptionalParam(aDisplay);
|
||||
bool isThemed = mFrame->IsThemed(disp);
|
||||
bool needPaddingProp;
|
||||
nsIntMargin widget;
|
||||
|
|
|
@ -301,7 +301,8 @@ protected:
|
|||
mozilla::LayoutFrameType aFrameType,
|
||||
ReflowInputFlags aFlags,
|
||||
const nsMargin* aBorder = nullptr,
|
||||
const nsMargin* aPadding = nullptr);
|
||||
const nsMargin* aPadding = nullptr,
|
||||
const nsStyleDisplay* aDisplay = nullptr);
|
||||
|
||||
/*
|
||||
* Convert nsStyleCoord to nscoord when percentages depend on the
|
||||
|
|
|
@ -1453,7 +1453,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
}
|
||||
}
|
||||
|
||||
FinishAndStoreOverflow(&aMetrics);
|
||||
FinishAndStoreOverflow(&aMetrics, reflowInput->mStyleDisplay);
|
||||
|
||||
aStatus = state.mReflowStatus;
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext,
|
|||
LogicalSize convertedSize = kidMetrics.Size(lineWM).ConvertTo(wm, lineWM);
|
||||
kid->SetRect(nsRect(bp.IStart(wm), bp.BStart(wm),
|
||||
convertedSize.ISize(wm), convertedSize.BSize(wm)));
|
||||
kid->FinishAndStoreOverflow(&kidMetrics);
|
||||
kid->FinishAndStoreOverflow(&kidMetrics, rs.mStyleDisplay);
|
||||
kid->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
|
||||
|
||||
convertedSize.ISize(wm) += bp.IStartEnd(wm);
|
||||
|
@ -232,7 +232,7 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext,
|
|||
aMetrics.UnionOverflowAreasWithDesiredBounds();
|
||||
ConsiderChildOverflow(aMetrics.mOverflowAreas, kid);
|
||||
|
||||
FinishAndStoreOverflow(&aMetrics);
|
||||
FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay);
|
||||
} else {
|
||||
// Pretend we are a span and reflow the child frame
|
||||
nsLineLayout* ll = aReflowInput.mLineLayout;
|
||||
|
|
|
@ -1307,8 +1307,9 @@ nsIFrame::GetMarginRectRelativeToSelf() const
|
|||
bool
|
||||
nsIFrame::IsTransformed(const nsStyleDisplay* aStyleDisplay) const
|
||||
{
|
||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||
return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
||||
(StyleDisplayWithOptionalParam(aStyleDisplay)->HasTransform(this) ||
|
||||
(aStyleDisplay->HasTransform(this) ||
|
||||
IsSVGTransformed() ||
|
||||
HasAnimationOfTransform()));
|
||||
}
|
||||
|
@ -1341,9 +1342,9 @@ nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
|
|||
}
|
||||
|
||||
bool
|
||||
nsIFrame::Extend3DContext() const
|
||||
nsIFrame::Extend3DContext(const nsStyleDisplay* aStyleDisplay) const
|
||||
{
|
||||
const nsStyleDisplay* disp = StyleDisplay();
|
||||
const nsStyleDisplay* disp = StyleDisplayWithOptionalParam(aStyleDisplay);
|
||||
if (disp->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
|
||||
!IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) {
|
||||
return false;
|
||||
|
@ -1367,6 +1368,7 @@ nsIFrame::Extend3DContext() const
|
|||
bool
|
||||
nsIFrame::Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay) const
|
||||
{
|
||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||
if (!GetParent() || !GetParent()->Extend3DContext()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1383,24 +1385,19 @@ nsIFrame::In3DContextAndBackfaceIsHidden() const
|
|||
}
|
||||
|
||||
bool
|
||||
nsIFrame::HasPerspective() const
|
||||
nsIFrame::HasPerspective(const nsStyleDisplay* aStyleDisplay) const
|
||||
{
|
||||
if (!IsTransformed()) {
|
||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||
if (!IsTransformed(aStyleDisplay)) {
|
||||
return false;
|
||||
}
|
||||
nsIFrame* containingBlock = GetContainingBlock(SKIP_SCROLLED_FRAME);
|
||||
nsIFrame* containingBlock = GetContainingBlock(SKIP_SCROLLED_FRAME, aStyleDisplay);
|
||||
if (!containingBlock) {
|
||||
return false;
|
||||
}
|
||||
return containingBlock->ChildrenHavePerspective();
|
||||
}
|
||||
|
||||
bool
|
||||
nsIFrame::ChildrenHavePerspective() const
|
||||
{
|
||||
return StyleDisplay()->HasPerspectiveStyle();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsIFrame::GetContentRectRelativeToSelf() const
|
||||
{
|
||||
|
@ -2375,9 +2372,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||
aBuilder->AddToWillChangeBudget(this, GetSize());
|
||||
}
|
||||
|
||||
bool extend3DContext = Extend3DContext();
|
||||
bool extend3DContext = Extend3DContext(disp);
|
||||
Maybe<nsDisplayListBuilder::AutoPreserves3DContext> autoPreserves3DContext;
|
||||
if (extend3DContext && !Combines3DTransformWithAncestors()) {
|
||||
if (extend3DContext && !Combines3DTransformWithAncestors(disp)) {
|
||||
// Start a new preserves3d context to keep informations on
|
||||
// nsDisplayListBuilder.
|
||||
autoPreserves3DContext.emplace(aBuilder);
|
||||
|
@ -2421,7 +2418,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
// If we're in preserve-3d then grab the dirty rect that was given to the root
|
||||
// and transform using the combined transform.
|
||||
if (Combines3DTransformWithAncestors()) {
|
||||
if (Combines3DTransformWithAncestors(disp)) {
|
||||
dirtyRect = aBuilder->GetPreserves3DDirtyRect(this);
|
||||
}
|
||||
|
||||
|
@ -2782,7 +2779,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||
resultList.AppendNewToTop(
|
||||
new (aBuilder) nsDisplayPerspective(
|
||||
aBuilder, this,
|
||||
GetContainingBlock()->GetContent()->GetPrimaryFrame(), &resultList));
|
||||
GetContainingBlock(0, disp)->GetContent()->GetPrimaryFrame(),
|
||||
&resultList));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5889,7 +5887,7 @@ nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
|
|||
{
|
||||
ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus, aConstrainBSize);
|
||||
|
||||
FinishAndStoreOverflow(&aDesiredSize);
|
||||
FinishAndStoreOverflow(&aDesiredSize, aReflowInput.mStyleDisplay);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -7012,8 +7010,10 @@ GetNearestBlockContainer(nsIFrame* frame)
|
|||
}
|
||||
|
||||
nsIFrame*
|
||||
nsIFrame::GetContainingBlock(uint32_t aFlags) const
|
||||
nsIFrame::GetContainingBlock(uint32_t aFlags,
|
||||
const nsStyleDisplay* aStyleDisplay) const
|
||||
{
|
||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||
if (!GetParent()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7021,7 +7021,7 @@ nsIFrame::GetContainingBlock(uint32_t aFlags) const
|
|||
// still be in-flow. So we have to check to make sure that the frame
|
||||
// is really out-of-flow too.
|
||||
nsIFrame* f;
|
||||
if (IsAbsolutelyPositioned() &&
|
||||
if (IsAbsolutelyPositioned(aStyleDisplay) &&
|
||||
(GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
|
||||
f = GetParent(); // the parent is always the containing block
|
||||
} else {
|
||||
|
@ -8955,12 +8955,13 @@ ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas,
|
|||
|
||||
bool
|
||||
nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
nsSize aNewSize, nsSize* aOldSize)
|
||||
nsSize aNewSize, nsSize* aOldSize,
|
||||
const nsStyleDisplay* aStyleDisplay)
|
||||
{
|
||||
MOZ_ASSERT(FrameMaintainsOverflow(),
|
||||
"Don't call - overflow rects not maintained on these SVG frames");
|
||||
|
||||
const nsStyleDisplay* disp = StyleDisplay();
|
||||
const nsStyleDisplay* disp = StyleDisplayWithOptionalParam(aStyleDisplay);
|
||||
bool hasTransform = IsTransformed(disp);
|
||||
|
||||
nsRect bounds(nsPoint(0, 0), aNewSize);
|
||||
|
@ -9072,7 +9073,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
|||
*/
|
||||
SetSize(aNewSize);
|
||||
|
||||
if (ChildrenHavePerspective() && sizeChanged) {
|
||||
if (ChildrenHavePerspective(disp) && sizeChanged) {
|
||||
nsRect newBounds(nsPoint(0, 0), aNewSize);
|
||||
RecomputePerspectiveChildrenOverflow(this);
|
||||
}
|
||||
|
@ -9081,7 +9082,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
|||
Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
|
||||
new nsOverflowAreas(aOverflowAreas));
|
||||
|
||||
if (Combines3DTransformWithAncestors()) {
|
||||
if (Combines3DTransformWithAncestors(disp)) {
|
||||
/* If we're a preserve-3d leaf frame, then our pre-transform overflow should be correct. Our
|
||||
* post-transform overflow is empty though, because we only contribute to the overflow area
|
||||
* of the preserve-3d root frame.
|
||||
|
@ -9099,7 +9100,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
|||
* the participants. This won't have happened yet as the code above set their overflow
|
||||
* area to empty. Manually collect these overflow areas now.
|
||||
*/
|
||||
if (Extend3DContext()) {
|
||||
if (Extend3DContext(disp)) {
|
||||
ComputePreserve3DChildrenOverflow(aOverflowAreas);
|
||||
}
|
||||
}
|
||||
|
@ -9177,7 +9178,8 @@ nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas)
|
|||
// If this child participates in the 3d context, then take the pre-transform
|
||||
// region (which contains all descendants that aren't participating in the 3d context)
|
||||
// and transform it into the 3d context root coordinate space.
|
||||
if (child->Combines3DTransformWithAncestors()) {
|
||||
const nsStyleDisplay* childDisp = child->StyleDisplay();
|
||||
if (child->Combines3DTransformWithAncestors(childDisp)) {
|
||||
nsOverflowAreas childOverflow = child->GetOverflowAreasRelativeToSelf();
|
||||
|
||||
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
||||
|
@ -9189,7 +9191,7 @@ nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas)
|
|||
|
||||
// If this child also extends the 3d context, then recurse into it
|
||||
// looking for more participants.
|
||||
if (child->Extend3DContext()) {
|
||||
if (child->Extend3DContext(childDisp)) {
|
||||
child->ComputePreserve3DChildrenOverflow(aOverflowAreas);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1671,7 +1671,10 @@ public:
|
|||
* @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
|
||||
* it here will improve performance.
|
||||
*/
|
||||
bool IsTransformed(const nsStyleDisplay* aStyleDisplay = nullptr) const;
|
||||
bool IsTransformed(const nsStyleDisplay* aStyleDisplay) const;
|
||||
bool IsTransformed() const {
|
||||
return IsTransformed(StyleDisplay());
|
||||
}
|
||||
|
||||
/**
|
||||
* True if this frame has any animation of transform in effect.
|
||||
|
@ -1718,8 +1721,14 @@ public:
|
|||
* Returns whether this frame will attempt to extend the 3d transforms of its
|
||||
* children. This requires transform-style: preserve-3d, as well as no clipping
|
||||
* or svg effects.
|
||||
*
|
||||
* @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
|
||||
* it here will improve performance.
|
||||
*/
|
||||
bool Extend3DContext() const;
|
||||
bool Extend3DContext(const nsStyleDisplay* aStyleDisplay) const;
|
||||
bool Extend3DContext() const {
|
||||
return Extend3DContext(StyleDisplay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this frame has a parent that Extend3DContext() and has
|
||||
|
@ -1729,8 +1738,10 @@ public:
|
|||
* @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
|
||||
* it here will improve performance.
|
||||
*/
|
||||
bool Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay
|
||||
= nullptr) const;
|
||||
bool Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay) const;
|
||||
bool Combines3DTransformWithAncestors() const {
|
||||
return Combines3DTransformWithAncestors(StyleDisplay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this frame has a hidden backface and has a parent that
|
||||
|
@ -1739,13 +1750,26 @@ public:
|
|||
*/
|
||||
bool In3DContextAndBackfaceIsHidden() const;
|
||||
|
||||
bool IsPreserve3DLeaf(const nsStyleDisplay* aStyleDisplay) const {
|
||||
return Combines3DTransformWithAncestors(aStyleDisplay) &&
|
||||
!Extend3DContext(aStyleDisplay);
|
||||
}
|
||||
bool IsPreserve3DLeaf() const {
|
||||
return Combines3DTransformWithAncestors() && !Extend3DContext();
|
||||
return IsPreserve3DLeaf(StyleDisplay());
|
||||
}
|
||||
|
||||
bool HasPerspective() const;
|
||||
bool HasPerspective(const nsStyleDisplay* aStyleDisplay) const;
|
||||
bool HasPerspective() const {
|
||||
return HasPerspective(StyleDisplay());
|
||||
}
|
||||
|
||||
bool ChildrenHavePerspective() const;
|
||||
bool ChildrenHavePerspective(const nsStyleDisplay* aStyleDisplay) const {
|
||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||
return aStyleDisplay->HasPerspectiveStyle();
|
||||
}
|
||||
bool ChildrenHavePerspective() const {
|
||||
return ChildrenHavePerspective(StyleDisplay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes the overflow area of all descendants that participate in the current
|
||||
|
@ -2753,7 +2777,11 @@ public:
|
|||
// this and return the outer scroll frame.
|
||||
SKIP_SCROLLED_FRAME = 0x01
|
||||
};
|
||||
nsIFrame* GetContainingBlock(uint32_t aFlags = 0) const;
|
||||
nsIFrame* GetContainingBlock(uint32_t aFlags,
|
||||
const nsStyleDisplay* aStyleDisplay) const;
|
||||
nsIFrame* GetContainingBlock(uint32_t aFlags = 0) const {
|
||||
return GetContainingBlock(aFlags, StyleDisplay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this frame a containing block for floating elements?
|
||||
|
@ -3027,11 +3055,14 @@ public:
|
|||
* the overflow areas changed.
|
||||
*/
|
||||
bool FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
nsSize aNewSize, nsSize* aOldSize = nullptr);
|
||||
nsSize aNewSize, nsSize* aOldSize = nullptr,
|
||||
const nsStyleDisplay* aStyleDisplay = nullptr);
|
||||
|
||||
bool FinishAndStoreOverflow(ReflowOutput* aMetrics) {
|
||||
bool FinishAndStoreOverflow(ReflowOutput* aMetrics,
|
||||
const nsStyleDisplay* aStyleDisplay = nullptr) {
|
||||
return FinishAndStoreOverflow(aMetrics->mOverflowAreas,
|
||||
nsSize(aMetrics->Width(), aMetrics->Height()));
|
||||
nsSize(aMetrics->Width(), aMetrics->Height()),
|
||||
nullptr, aStyleDisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3602,7 +3633,7 @@ public:
|
|||
inline bool IsAbsPosContainingBlock() const;
|
||||
inline bool IsFixedPosContainingBlock() const;
|
||||
inline bool IsRelativelyPositioned() const;
|
||||
inline bool IsAbsolutelyPositioned() const;
|
||||
inline bool IsAbsolutelyPositioned(const nsStyleDisplay* aStyleDisplay = nullptr) const;
|
||||
|
||||
/**
|
||||
* Returns the vertical-align value to be used for layout, if it is one
|
||||
|
@ -3692,8 +3723,12 @@ public:
|
|||
* @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
|
||||
* it here will improve performance.
|
||||
*/
|
||||
bool BackfaceIsHidden(const nsStyleDisplay* aStyleDisplay = nullptr) const {
|
||||
return StyleDisplayWithOptionalParam(aStyleDisplay)->BackfaceIsHidden();
|
||||
bool BackfaceIsHidden(const nsStyleDisplay* aStyleDisplay) const {
|
||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||
return aStyleDisplay->BackfaceIsHidden();
|
||||
}
|
||||
bool BackfaceIsHidden() const {
|
||||
return StyleDisplay()->BackfaceIsHidden();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,9 +66,10 @@ nsIFrame::IsRelativelyPositioned() const
|
|||
}
|
||||
|
||||
bool
|
||||
nsIFrame::IsAbsolutelyPositioned() const
|
||||
nsIFrame::IsAbsolutelyPositioned(const nsStyleDisplay* aStyleDisplay) const
|
||||
{
|
||||
return StyleDisplay()->IsAbsolutelyPositioned(this);
|
||||
const nsStyleDisplay* disp = StyleDisplayWithOptionalParam(aStyleDisplay);
|
||||
return disp->IsAbsolutelyPositioned(this);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -1048,7 +1048,7 @@ nsImageFrame::Reflow(nsPresContext* aPresContext,
|
|||
// to request a decode.
|
||||
MaybeDecodeForPredictedSize();
|
||||
}
|
||||
FinishAndStoreOverflow(&aMetrics);
|
||||
FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay);
|
||||
|
||||
if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && !mReflowCallbackPosted) {
|
||||
nsIPresShell* shell = PresContext()->PresShell();
|
||||
|
|
|
@ -64,7 +64,7 @@ nsLeafFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
DoReflow(aPresContext, aMetrics, aReflowInput, aStatus);
|
||||
|
||||
FinishAndStoreOverflow(&aMetrics);
|
||||
FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -111,5 +111,5 @@ nsLeafFrame::SizeToAvailSize(const ReflowInput& aReflowInput,
|
|||
aReflowInput.AvailableBSize());
|
||||
aDesiredSize.SetSize(wm, size);
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
FinishAndStoreOverflow(&aDesiredSize);
|
||||
FinishAndStoreOverflow(&aDesiredSize, aReflowInput.mStyleDisplay);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<tabbox id="tab">
|
||||
<tabs>
|
||||
<tab label="zeroTab" id="0" selected="true" />
|
||||
<tab label="firstTab" id="1" />
|
||||
<tab label="secondtab" id="2" />
|
||||
<tab label="thirdTab" id="3" />
|
||||
<tab label="fourthTab" id="4" />
|
||||
<tab label="fifthTab" id="5" />
|
||||
<tab label="sixthTab" id="6" />
|
||||
<tab label="seventhTab" id="7" />
|
||||
<tab label="eightTab" id="8" />
|
||||
<tab label="ninthTab" id="9" />
|
||||
</tabs>
|
||||
</tabbox>
|
||||
</window>
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="reftest-wait">
|
||||
<tabbox id="tab">
|
||||
<tabs>
|
||||
<tab label="zeroTab" id="0" />
|
||||
<tab label="firstTab" id="1" />
|
||||
<tab label="secondtab" id="2" />
|
||||
<tab label="thirdTab" id="3" />
|
||||
<tab label="fourthTab" id="4" />
|
||||
<tab label="fifthTab" id="5" />
|
||||
<tab label="sixthTab" id="6" />
|
||||
<tab label="seventhTab" id="7" />
|
||||
<tab label="eightTab" id="8" />
|
||||
<tab label="ninthTab" id="9" />
|
||||
</tabs>
|
||||
</tabbox>
|
||||
|
||||
<script type="text/javascript">
|
||||
// Overly try to iterate and click through the tabs
|
||||
// since its a timing specific bug.
|
||||
var tabCount = 10;
|
||||
var loops = 10;
|
||||
var i = tabCount * loops;
|
||||
|
||||
function clickTabs() {
|
||||
var currentTab = i % tabCount;
|
||||
var tab = document.getElementById(currentTab);
|
||||
tab.click();
|
||||
|
||||
if (i > 0) {
|
||||
i--;
|
||||
// Relinquish main thread so we can paint
|
||||
setTimeout(clickTabs, 0);
|
||||
} else {
|
||||
// Test finished
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('MozReftestInvalidate', clickTabs);
|
||||
</script>
|
||||
</window>
|
|
@ -8,6 +8,7 @@ random-if(Android) fails-if(winWidget) == menulist-shrinkwrap-2.xul menulist-shr
|
|||
# accesskeys are not normally displayed on Mac, so skip this test
|
||||
skip-if(cocoaWidget) == accesskey.xul accesskey-ref.xul
|
||||
fails-if(cocoaWidget) fuzzy-if(xulRuntime.widgetToolkit=="gtk3",1,11) == tree-row-outline-1.xul tree-row-outline-1-ref.xul # win8: bug 1254832
|
||||
skip-if(!cocoaWidget) == mac-tab-toolbar.xul mac-tab-toolbar-ref.xul
|
||||
!= tree-row-outline-1.xul tree-row-outline-1-notref.xul
|
||||
== text-crop.xul text-crop-ref.xul
|
||||
== text-small-caps-1.xul text-small-caps-1-ref.xul
|
||||
|
|
|
@ -144,6 +144,10 @@ class ReftestArgumentsParser(argparse.ArgumentParser):
|
|||
default=None,
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
self.add_argument("--marionette-startup-timeout",
|
||||
default=None,
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
self.add_argument("--setenv",
|
||||
action="append",
|
||||
type=str,
|
||||
|
|
|
@ -627,6 +627,7 @@ class RefTest(object):
|
|||
if self.use_marionette:
|
||||
marionette_args = {
|
||||
'socket_timeout': options.marionette_socket_timeout,
|
||||
'startup_timeout': options.marionette_startup_timeout,
|
||||
'symbols_path': options.symbolsPath,
|
||||
}
|
||||
if options.marionette:
|
||||
|
|
|
@ -4645,6 +4645,9 @@ pref("layers.bench.enabled", false);
|
|||
pref("layers.gpu-process.enabled", true);
|
||||
pref("layers.gpu-process.max_restarts", 3);
|
||||
pref("media.gpu-process-decoder", true);
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("layers.gpu-process.allow-software", true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Whether to force acceleration on, ignoring blacklists.
|
||||
|
@ -5716,3 +5719,6 @@ pref("layers.advanced.caret-layers", 2);
|
|||
pref("layers.advanced.displaybuttonborder-layers", 2);
|
||||
pref("layers.advanced.outline-layers", 2);
|
||||
pref("layers.advanced.solid-color-layers", 2);
|
||||
|
||||
// Enable lowercased response header name
|
||||
pref("dom.xhr.lowercase_header.enabled", true);
|
||||
|
|
|
@ -122,8 +122,20 @@ interface nsIInterceptedChannel : nsISupports
|
|||
[noscript]
|
||||
void SetHandleFetchEventEnd(in TimeStamp aTimeStamp);
|
||||
|
||||
// Depending on the outcome we measure the time difference between
|
||||
// |FinishResponseStart| and either |FinishSynthesizedResponseEnd| or
|
||||
// |ChannelResetEnd|.
|
||||
[noscript]
|
||||
void SaveTimeStampsToUnderlyingChannel();
|
||||
void SetFinishResponseStart(in TimeStamp aTimeStamp);
|
||||
|
||||
[noscript]
|
||||
void SetFinishSynthesizedResponseEnd(in TimeStamp aTimeStamp);
|
||||
|
||||
[noscript]
|
||||
void SetChannelResetEnd(in TimeStamp aTimeStamp);
|
||||
|
||||
[noscript]
|
||||
void SaveTimeStamps();
|
||||
|
||||
%{C++
|
||||
already_AddRefed<nsIConsoleReportCollector>
|
||||
|
|
|
@ -37,9 +37,10 @@ DoAddCacheEntryHeaders(nsHttpChannel *self,
|
|||
NS_IMPL_ISUPPORTS(InterceptedChannelBase, nsIInterceptedChannel)
|
||||
|
||||
InterceptedChannelBase::InterceptedChannelBase(nsINetworkInterceptController* aController)
|
||||
: mController(aController)
|
||||
, mReportCollector(new ConsoleReportCollector())
|
||||
, mClosed(false)
|
||||
: mController(aController)
|
||||
, mReportCollector(new ConsoleReportCollector())
|
||||
, mClosed(false)
|
||||
, mSynthesizedOrReset(Invalid)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -133,7 +134,7 @@ InterceptedChannelBase::SetReleaseHandle(nsISupports* aHandle)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelBase::SaveTimeStampsToUnderlyingChannel()
|
||||
InterceptedChannelBase::SaveTimeStamps()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -163,6 +164,37 @@ InterceptedChannelBase::SaveTimeStampsToUnderlyingChannel()
|
|||
rv = timedChannel->SetHandleFetchEventEnd(mHandleFetchEventEnd);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
GetChannel(getter_AddRefs(channel));
|
||||
if (NS_WARN_IF(!channel)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCString navigationOrSubresource = nsContentUtils::IsNonSubresourceRequest(channel) ?
|
||||
NS_LITERAL_CSTRING("navigation") : NS_LITERAL_CSTRING("subresource");
|
||||
|
||||
// We may have null timestamps if the fetch dispatch runnable was cancelled
|
||||
// and we defaulted to resuming the request.
|
||||
if (!mFinishResponseStart.IsNull() && !mFinishResponseEnd.IsNull()) {
|
||||
MOZ_ASSERT(mSynthesizedOrReset != Invalid);
|
||||
|
||||
Telemetry::HistogramID id = (mSynthesizedOrReset == Synthesized) ?
|
||||
Telemetry::SERVICE_WORKER_FETCH_EVENT_FINISH_SYNTHESIZED_RESPONSE_MS :
|
||||
Telemetry::SERVICE_WORKER_FETCH_EVENT_CHANNEL_RESET_MS;
|
||||
Telemetry::Accumulate(id, navigationOrSubresource,
|
||||
static_cast<uint32_t>((mFinishResponseEnd - mFinishResponseStart).ToMilliseconds()));
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_FETCH_EVENT_DISPATCH_MS,
|
||||
navigationOrSubresource,
|
||||
static_cast<uint32_t>((mHandleFetchEventStart - mDispatchFetchEventStart).ToMilliseconds()));
|
||||
|
||||
if (!mFinishResponseEnd.IsNull()) {
|
||||
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_FETCH_INTERCEPTION_DURATION_MS,
|
||||
navigationOrSubresource,
|
||||
static_cast<uint32_t>((mFinishResponseEnd - mDispatchFetchEventStart).ToMilliseconds()));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,14 @@ protected:
|
|||
TimeStamp mHandleFetchEventStart;
|
||||
TimeStamp mHandleFetchEventEnd;
|
||||
|
||||
TimeStamp mFinishResponseStart;
|
||||
TimeStamp mFinishResponseEnd;
|
||||
enum {
|
||||
Invalid = 0,
|
||||
Synthesized,
|
||||
Reset
|
||||
} mSynthesizedOrReset;
|
||||
|
||||
virtual ~InterceptedChannelBase();
|
||||
public:
|
||||
explicit InterceptedChannelBase(nsINetworkInterceptController* aController);
|
||||
|
@ -111,7 +119,32 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP SaveTimeStampsToUnderlyingChannel() override;
|
||||
NS_IMETHODIMP
|
||||
SetFinishResponseStart(TimeStamp aTimeStamp) override
|
||||
{
|
||||
mFinishResponseStart = aTimeStamp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SetFinishSynthesizedResponseEnd(TimeStamp aTimeStamp) override
|
||||
{
|
||||
MOZ_ASSERT(mSynthesizedOrReset == Invalid);
|
||||
mSynthesizedOrReset = Synthesized;
|
||||
mFinishResponseEnd = aTimeStamp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SetChannelResetEnd(TimeStamp aTimeStamp) override
|
||||
{
|
||||
MOZ_ASSERT(mSynthesizedOrReset == Invalid);
|
||||
mSynthesizedOrReset = Reset;
|
||||
mFinishResponseEnd = aTimeStamp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP SaveTimeStamps() override;
|
||||
|
||||
static already_AddRefed<nsIURI>
|
||||
SecureUpgradeChannelURI(nsIChannel* aChannel);
|
||||
|
|
|
@ -3848,7 +3848,13 @@ nsHttpChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appC
|
|||
if (mRaceCacheWithNetwork && mFirstResponseSource == RESPONSE_FROM_NETWORK) {
|
||||
LOG(("Not using cached response because we've already got one from the network\n"));
|
||||
*aResult = ENTRY_NOT_WANTED;
|
||||
|
||||
// Net-win indicates that mOnStartRequestTimestamp is from net.
|
||||
int64_t savedTime = (TimeStamp::Now() - mOnStartRequestTimestamp).ToMilliseconds();
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_RACE_CACHE_WITH_NETWORK_SAVED_TIME, savedTime);
|
||||
return NS_OK;
|
||||
} else if (mRaceCacheWithNetwork && mFirstResponseSource == RESPONSE_PENDING) {
|
||||
mOnCacheEntryCheckTimestamp = TimeStamp::Now();
|
||||
}
|
||||
|
||||
nsAutoCString cacheControlRequestHeader;
|
||||
|
@ -6894,6 +6900,17 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
// that are not keep-alive.
|
||||
} else if (WRONG_RACING_RESPONSE_SOURCE(request)) {
|
||||
LOG((" Early return when racing. This response not needed."));
|
||||
|
||||
// Net wins, but OnCacheEntryCheck was already called.
|
||||
if (mFirstResponseSource == RESPONSE_FROM_NETWORK &&
|
||||
!mOnCacheEntryCheckTimestamp.IsNull()) {
|
||||
TimeStamp currentTime = TimeStamp::Now();
|
||||
int64_t savedTime = (currentTime - mOnStartRequestTimestamp).ToMilliseconds();
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_RACE_CACHE_WITH_NETWORK_SAVED_TIME, savedTime);
|
||||
|
||||
int64_t diffTime = (currentTime - mOnCacheEntryCheckTimestamp).ToMilliseconds();
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_RACE_CACHE_WITH_NETWORK_OCEC_ON_START_DIFF, diffTime);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -8844,7 +8861,7 @@ nsHttpChannel::SetDoNotTrack()
|
|||
}
|
||||
|
||||
static const size_t kPositiveBucketNumbers = 34;
|
||||
static const int64_t positiveBucketLevels[kPositiveBucketNumbers] =
|
||||
static const int64_t kPositiveBucketLevels[kPositiveBucketNumbers] =
|
||||
{
|
||||
0, 10, 20, 30, 40, 50, 60, 70, 80, 90,
|
||||
100, 200, 300, 400, 500, 600, 700, 800, 900, 1000,
|
||||
|
@ -8874,10 +8891,10 @@ inline int64_t
|
|||
nsHttpChannel::ComputeTelemetryBucketNumber(int64_t difftime_ms)
|
||||
{
|
||||
int64_t absBucketIndex =
|
||||
std::lower_bound(positiveBucketLevels,
|
||||
positiveBucketLevels + kPositiveBucketNumbers,
|
||||
std::lower_bound(kPositiveBucketLevels,
|
||||
kPositiveBucketLevels + kPositiveBucketNumbers,
|
||||
static_cast<int64_t>(mozilla::Abs(difftime_ms)))
|
||||
- positiveBucketLevels;
|
||||
- kPositiveBucketLevels;
|
||||
|
||||
return difftime_ms >= 0 ? 40 + absBucketIndex
|
||||
: 40 - absBucketIndex;
|
||||
|
|
|
@ -546,6 +546,7 @@ private:
|
|||
mozilla::TimeStamp mOnStartRequestTimestamp;
|
||||
// Timestamp of the time the cnannel was suspended.
|
||||
mozilla::TimeStamp mSuspendTimestamp;
|
||||
mozilla::TimeStamp mOnCacheEntryCheckTimestamp;
|
||||
// Total time the channel spent suspended. This value is reported to
|
||||
// telemetry in nsHttpChannel::OnStartRequest().
|
||||
uint32_t mSuspendTotalTime;
|
||||
|
|
|
@ -362,6 +362,7 @@ PK11_GetLowLevelKeyIDForPrivateKey
|
|||
PK11_GetMechanism
|
||||
PK11_GetMinimumPwdLength
|
||||
PK11_GetModInfo
|
||||
PK11_GetModuleURI
|
||||
PK11_GetNextSafe
|
||||
PK11_GetNextSymKey
|
||||
PK11_GetPadMechanism
|
||||
|
@ -375,6 +376,7 @@ PK11_GetSlotSeries
|
|||
PK11_GetSymKeyNickname
|
||||
PK11_GetTokenInfo
|
||||
PK11_GetTokenName
|
||||
PK11_GetTokenURI
|
||||
PK11_HasAttributeSet
|
||||
PK11_HashBuf
|
||||
PK11_HasRootCerts
|
||||
|
|
|
@ -1 +1 @@
|
|||
236a06d9c3c4
|
||||
57e38a8407b3
|
||||
|
|
|
@ -455,6 +455,19 @@ async function scheduleTestBuilds(base, args = "") {
|
|||
symbol: "mpi",
|
||||
kind: "test"
|
||||
}));
|
||||
queue.scheduleTask(merge(base, {
|
||||
parent: task_build,
|
||||
command: [
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
"bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
|
||||
],
|
||||
name: "Gtests",
|
||||
symbol: "Gtest",
|
||||
tests: "gtests",
|
||||
cycle: "standard",
|
||||
kind: "test"
|
||||
}));
|
||||
|
||||
return queue.submit();
|
||||
}
|
||||
|
|
|
@ -2,52 +2,56 @@
|
|||
|
||||
source $(dirname "$0")/tools.sh
|
||||
|
||||
set +x
|
||||
|
||||
# Apply clang-format on the provided folder and verify that this doesn't change any file.
|
||||
# If any file differs after formatting, the script eventually exits with 1.
|
||||
# Any differences between formatted and unformatted files is printed to stdout to give a hint what's wrong.
|
||||
|
||||
# Includes a default set of directories.
|
||||
# Includes a default set of directories NOT to clang-format on.
|
||||
blacklist=(
|
||||
"./automation" \
|
||||
"./coreconf" \
|
||||
"./doc" \
|
||||
"./pkg" \
|
||||
"./tests" \
|
||||
"./lib/libpkix" \
|
||||
"./lib/zlib" \
|
||||
"./lib/sqlite" \
|
||||
"./gtests/google_test" \
|
||||
"./.hg" \
|
||||
)
|
||||
|
||||
top="$PWD/$(dirname $0)/../../.."
|
||||
cd "$top"
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
dirs=("$@")
|
||||
else
|
||||
top=$(dirname $0)/../../..
|
||||
dirs=( \
|
||||
"$top/cmd" \
|
||||
"$top/fuzz" \
|
||||
"$top/lib/base" \
|
||||
"$top/lib/certdb" \
|
||||
"$top/lib/certhigh" \
|
||||
"$top/lib/ckfw" \
|
||||
"$top/lib/crmf" \
|
||||
"$top/lib/cryptohi" \
|
||||
"$top/lib/dbm" \
|
||||
"$top/lib/dev" \
|
||||
"$top/lib/freebl" \
|
||||
"$top/lib/jar" \
|
||||
"$top/lib/nss" \
|
||||
"$top/lib/pk11wrap" \
|
||||
"$top/lib/pkcs7" \
|
||||
"$top/lib/pkcs12" \
|
||||
"$top/lib/pki" \
|
||||
"$top/lib/smime" \
|
||||
"$top/lib/softoken" \
|
||||
"$top/lib/ssl" \
|
||||
"$top/lib/sysinit" \
|
||||
"$top/lib/util" \
|
||||
"$top/gtests/common" \
|
||||
"$top/gtests/der_gtest" \
|
||||
"$top/gtests/freebl_gtest" \
|
||||
"$top/gtests/pk11_gtest" \
|
||||
"$top/gtests/ssl_gtest" \
|
||||
"$top/gtests/util_gtest" \
|
||||
"$top/nss-tool" \
|
||||
"$top/cpputil" \
|
||||
)
|
||||
dirs=($(find . ! -path . \( ! -regex '.*/' \) -maxdepth 2 -mindepth 1 -type d))
|
||||
fi
|
||||
|
||||
format_folder()
|
||||
{
|
||||
for black in "${blacklist[@]}"; do
|
||||
if [[ "$1" == "$black"* ]]; then
|
||||
echo "skip $1"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
for dir in "${dirs[@]}"; do
|
||||
find "$dir" -type f \( -name '*.[ch]' -o -name '*.cc' \) -exec clang-format -i {} \+
|
||||
if format_folder "$dir" ; then
|
||||
c="${dir//[^\/]}"
|
||||
echo "formatting $dir ..."
|
||||
depth=""
|
||||
if [ "${#c}" == "1" ]; then
|
||||
depth="-maxdepth 1"
|
||||
fi
|
||||
find "$dir" $depth -type f \( -name '*.[ch]' -o -name '*.cc' \) -exec clang-format -i {} \+
|
||||
fi
|
||||
done
|
||||
|
||||
TMPFILE=$(mktemp /tmp/$(basename $0).XXXXXX)
|
||||
|
|
|
@ -183,7 +183,10 @@ if [[ "$rebuild_nspr" = 1 && "$no_local_nspr" = 0 ]]; then
|
|||
mv -f "$nspr_config".new "$nspr_config"
|
||||
fi
|
||||
if [ "$rebuild_gyp" = 1 ]; then
|
||||
|
||||
if ! hash gyp 2> /dev/null; then
|
||||
echo "Please install gyp" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
# These extra arguments aren't used in determining whether to rebuild.
|
||||
obj_dir="$dist_dir"/$target
|
||||
gyp_params+=(-Dnss_dist_obj_dir=$obj_dir)
|
||||
|
|
|
@ -1002,9 +1002,12 @@ ListModules(void)
|
|||
|
||||
/* look at each slot*/
|
||||
for (le = list->head; le; le = le->next) {
|
||||
char *token_uri = PK11_GetTokenURI(le->slot);
|
||||
printf("\n");
|
||||
printf(" slot: %s\n", PK11_GetSlotName(le->slot));
|
||||
printf(" token: %s\n", PK11_GetTokenName(le->slot));
|
||||
printf(" uri: %s\n", token_uri);
|
||||
PORT_Free(token_uri);
|
||||
}
|
||||
PK11_FreeSlotList(list);
|
||||
|
||||
|
|
|
@ -397,6 +397,7 @@ static void
|
|||
printModule(SECMODModule *module, int *count)
|
||||
{
|
||||
int slotCount = module->loaded ? module->slotCount : 0;
|
||||
char *modUri;
|
||||
int i;
|
||||
|
||||
if ((*count)++) {
|
||||
|
@ -408,6 +409,11 @@ printModule(SECMODModule *module, int *count)
|
|||
PR_fprintf(PR_STDOUT, "\tlibrary name: %s\n", module->dllName);
|
||||
}
|
||||
|
||||
modUri = PK11_GetModuleURI(module);
|
||||
if (modUri) {
|
||||
PR_fprintf(PR_STDOUT, "\t uri: %s\n", modUri);
|
||||
PORT_Free(modUri);
|
||||
}
|
||||
if (slotCount == 0) {
|
||||
PR_fprintf(PR_STDOUT,
|
||||
"\t slots: There are no slots attached to this module\n");
|
||||
|
@ -425,10 +431,12 @@ printModule(SECMODModule *module, int *count)
|
|||
/* Print slot and token names */
|
||||
for (i = 0; i < slotCount; i++) {
|
||||
PK11SlotInfo *slot = module->slots[i];
|
||||
|
||||
char *tokenUri = PK11_GetTokenURI(slot);
|
||||
PR_fprintf(PR_STDOUT, "\n");
|
||||
PR_fprintf(PR_STDOUT, "\t slot: %s\n", PK11_GetSlotName(slot));
|
||||
PR_fprintf(PR_STDOUT, "\ttoken: %s\n", PK11_GetTokenName(slot));
|
||||
PR_fprintf(PR_STDOUT, "\t uri: %s\n", tokenUri);
|
||||
PORT_Free(tokenUri);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@
|
|||
'-Wl,--version-script,<(INTERMEDIATE_DIR)/out.>(mapfile)',
|
||||
],
|
||||
}],
|
||||
[ 'OS=="win"', {
|
||||
[ 'cc_use_gnu_ld!=1 and OS=="win"', {
|
||||
# On Windows, .def files are used directly as sources.
|
||||
'sources': [
|
||||
'>(mapfile)',
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
*/
|
||||
|
||||
#error "Do not include this header file."
|
||||
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
#include "cert.h"
|
||||
#include "keyhi.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pkcs11uri.h"
|
||||
|
||||
struct ScopedDelete {
|
||||
void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
|
||||
void operator()(CERTCertificateList* list) {
|
||||
CERT_DestroyCertificateList(list);
|
||||
}
|
||||
void operator()(CERTName* name) { CERT_DestroyName(name); }
|
||||
void operator()(CERTCertList* list) { CERT_DestroyCertList(list); }
|
||||
void operator()(CERTSubjectPublicKeyInfo* spki) {
|
||||
SECKEY_DestroySubjectPublicKeyInfo(spki);
|
||||
|
@ -31,6 +33,7 @@ struct ScopedDelete {
|
|||
void operator()(SECKEYPrivateKeyList* list) {
|
||||
SECKEY_DestroyPrivateKeyList(list);
|
||||
}
|
||||
void operator()(PK11URI* uri) { PK11URI_DestroyURI(uri); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
@ -48,6 +51,7 @@ struct ScopedMaybeDelete {
|
|||
SCOPED(CERTCertificate);
|
||||
SCOPED(CERTCertificateList);
|
||||
SCOPED(CERTCertList);
|
||||
SCOPED(CERTName);
|
||||
SCOPED(CERTSubjectPublicKeyInfo);
|
||||
SCOPED(PK11SlotInfo);
|
||||
SCOPED(PK11SymKey);
|
||||
|
@ -57,6 +61,7 @@ SCOPED(SECItem);
|
|||
SCOPED(SECKEYPublicKey);
|
||||
SCOPED(SECKEYPrivateKey);
|
||||
SCOPED(SECKEYPrivateKeyList);
|
||||
SCOPED(PK11URI);
|
||||
|
||||
#undef SCOPED
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include "databuffer.h"
|
||||
|
||||
#include "sslt.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
@ -79,6 +78,10 @@ static const uint8_t kTls13PskDhKe = 1;
|
|||
static const uint8_t kTls13PskAuth = 0;
|
||||
static const uint8_t kTls13PskSignAuth = 1;
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, SSLProtocolVariant v) {
|
||||
return os << ((v == ssl_variant_stream) ? "TLS" : "DTLS");
|
||||
}
|
||||
|
||||
inline bool IsDtls(uint16_t version) { return (version & 0x8000) == 0x8000; }
|
||||
|
||||
inline uint16_t NormalizeTlsVersion(uint16_t version) {
|
||||
|
@ -135,10 +138,6 @@ class TlsParser {
|
|||
size_t offset_;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, SSLProtocolVariant v) {
|
||||
return os << ((v == ssl_variant_stream) ? "TLS" : "DTLS");
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,8 +32,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||
bp[primeLen - 1] |= 0x01; /* set low-order bit */
|
||||
++count;
|
||||
assert(mp_read_unsigned_octets(&b, bp, primeLen) == MP_OKAY);
|
||||
} while ((res = mpp_make_prime(&b, primeLen * 8, PR_FALSE, nullptr)) !=
|
||||
MP_YES &&
|
||||
} while ((res = mpp_make_prime(&b, primeLen * 8, PR_FALSE)) != MP_YES &&
|
||||
count < 10);
|
||||
if (res != MP_YES) {
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
#! gmake
|
||||
#
|
||||
# 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/.
|
||||
|
||||
#######################################################################
|
||||
# (1) Include initial platform-independent assignments (MANDATORY). #
|
||||
#######################################################################
|
||||
|
||||
include manifest.mn
|
||||
|
||||
#######################################################################
|
||||
# (2) Include "global" configuration information. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/config.mk
|
||||
|
||||
#######################################################################
|
||||
# (3) Include "component" configuration information. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
include ../common/gtest.mk
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/rules.mk
|
||||
|
||||
#######################################################################
|
||||
# (6) Execute "component" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (7) Execute "local" rules. (OPTIONAL). #
|
||||
#######################################################################
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "nss.h"
|
||||
#include "scoped_ptrs.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
typedef struct AVATestValuesStr {
|
||||
std::string avaString;
|
||||
bool expectedResult;
|
||||
} AVATestValues;
|
||||
|
||||
class Alg1485Test : public ::testing::Test,
|
||||
public ::testing::WithParamInterface<AVATestValues> {};
|
||||
|
||||
static const AVATestValues kAVATestStrings[] = {
|
||||
{"CN=Marshall T. Rose, O=Dover Beach Consulting, L=Santa Clara, "
|
||||
"ST=California, C=US",
|
||||
true},
|
||||
{"C=HU,L=Budapest,O=Organization,CN=Example - Qualified Citizen "
|
||||
"CA,2.5.4.97=VATHU-10",
|
||||
true},
|
||||
{"C=HU,L=Budapest,O=Example,CN=Example - Qualified Citizen "
|
||||
"CA,OID.2.5.4.97=VATHU-10",
|
||||
true},
|
||||
{"CN=Somebody,L=Set,O=Up,C=US,1=The,2=Bomb", true},
|
||||
{"OID.2.5.4.6=😑", true},
|
||||
{"2.5.4.6=😑", true},
|
||||
{"OID.moocow=😑", false}, // OIDs must be numeric
|
||||
{"3.2=bad", false}, // OIDs cannot be overly large; 3 is too big
|
||||
{"256.257=bad", false}, // Still too big
|
||||
{"YO=LO", false}, // Unknown Tag, 'YO'
|
||||
{"CN=Tester,ZZ=Top", false}, // Unknown tag, 'ZZ'
|
||||
// These tests are disabled pending Bug 1363416
|
||||
// { "01.02.03=Nope", false }, // Numbers not in minimal form
|
||||
// { "000001.0000000001=👌", false },
|
||||
// { "CN=Somebody,L=Set,O=Up,C=US,01=The,02=Bomb", false },
|
||||
};
|
||||
|
||||
TEST_P(Alg1485Test, TryParsingAVAStrings) {
|
||||
const AVATestValues& param(GetParam());
|
||||
|
||||
ScopedCERTName certName(CERT_AsciiToName(param.avaString.c_str()));
|
||||
ASSERT_EQ(certName != nullptr, param.expectedResult);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ParseAVAStrings, Alg1485Test,
|
||||
::testing::ValuesIn(kAVATestStrings));
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
# 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/.
|
||||
{
|
||||
'includes': [
|
||||
'../../coreconf/config.gypi',
|
||||
'../common/gtest.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'certdb_gtest',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'alg1485_unittest.cc',
|
||||
'<(DEPTH)/gtests/common/gtests.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
|
||||
'<(DEPTH)/lib/util/util.gyp:nssutil3',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss3',
|
||||
]
|
||||
}
|
||||
],
|
||||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# 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/.
|
||||
CORE_DEPTH = ../..
|
||||
DEPTH = ../..
|
||||
MODULE = nss
|
||||
|
||||
CPPSRCS = \
|
||||
alg1485_unittest.cc \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
-I$(CORE_DEPTH)/gtests/common \
|
||||
-I$(CORE_DEPTH)/cpputil
|
||||
|
||||
REQUIRES = nspr nss libdbm gtest
|
||||
|
||||
PROGRAM = certdb_gtest
|
||||
|
||||
EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) $(EXTRA_OBJS) \
|
||||
../common/$(OBJDIR)/gtests$(OBJ_SUFFIX)
|
|
@ -0,0 +1,43 @@
|
|||
#! gmake
|
||||
#
|
||||
# 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/.
|
||||
|
||||
#######################################################################
|
||||
# (1) Include initial platform-independent assignments (MANDATORY). #
|
||||
#######################################################################
|
||||
|
||||
include manifest.mn
|
||||
|
||||
#######################################################################
|
||||
# (2) Include "global" configuration information. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/config.mk
|
||||
|
||||
#######################################################################
|
||||
# (3) Include "component" configuration information. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
include ../common/gtest.mk
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/rules.mk
|
||||
|
||||
#######################################################################
|
||||
# (6) Execute "component" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (7) Execute "local" rules. (OPTIONAL). #
|
||||
#######################################################################
|
|
@ -0,0 +1,29 @@
|
|||
# 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/.
|
||||
{
|
||||
'includes': [
|
||||
'../../coreconf/config.gypi',
|
||||
'../common/gtest.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'certhigh_gtest',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'certhigh_unittest.cc',
|
||||
'<(DEPTH)/gtests/common/gtests.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
|
||||
'<(DEPTH)/lib/util/util.gyp:nssutil3',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss3',
|
||||
]
|
||||
}
|
||||
],
|
||||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "cert.h"
|
||||
#include "certt.h"
|
||||
#include "secitem.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class CERT_FormatNameUnitTest : public ::testing::Test {};
|
||||
|
||||
TEST_F(CERT_FormatNameUnitTest, Overflow) {
|
||||
// Construct a CERTName consisting of a single RDN with 20 organizational unit
|
||||
// AVAs and 20 domain component AVAs. The actual contents don't matter, just
|
||||
// the types.
|
||||
|
||||
uint8_t oidValueBytes[] = {0x0c, 0x02, 0x58, 0x58}; // utf8String "XX"
|
||||
SECItem oidValue = {siBuffer, oidValueBytes, sizeof(oidValueBytes)};
|
||||
uint8_t oidTypeOUBytes[] = {0x55, 0x04, 0x0b}; // organizationalUnit
|
||||
SECItem oidTypeOU = {siBuffer, oidTypeOUBytes, sizeof(oidTypeOUBytes)};
|
||||
CERTAVA ouAVA = {oidTypeOU, oidValue};
|
||||
uint8_t oidTypeDCBytes[] = {0x09, 0x92, 0x26, 0x89, 0x93,
|
||||
0xf2, 0x2c, 0x64, 0x1, 0x19}; // domainComponent
|
||||
SECItem oidTypeDC = {siBuffer, oidTypeDCBytes, sizeof(oidTypeDCBytes)};
|
||||
CERTAVA dcAVA = {oidTypeDC, oidValue};
|
||||
|
||||
const int kNumEachAVA = 20;
|
||||
CERTAVA* avas[(2 * kNumEachAVA) + 1];
|
||||
for (int i = 0; i < kNumEachAVA; i++) {
|
||||
avas[2 * i] = &ouAVA;
|
||||
avas[(2 * i) + 1] = &dcAVA;
|
||||
}
|
||||
avas[2 * kNumEachAVA] = nullptr;
|
||||
|
||||
CERTRDN rdn = {avas};
|
||||
CERTRDN* rdns[2];
|
||||
rdns[0] = &rdn;
|
||||
rdns[1] = nullptr;
|
||||
|
||||
std::string expectedResult =
|
||||
"XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>"
|
||||
"XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>"
|
||||
"XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>XX<br>"
|
||||
"XX<br>XX<br>XX<br>XX<br>";
|
||||
|
||||
CERTName name = {nullptr, rdns};
|
||||
char* result = CERT_FormatName(&name);
|
||||
EXPECT_EQ(expectedResult, result);
|
||||
PORT_Free(result);
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# 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/.
|
||||
CORE_DEPTH = ../..
|
||||
DEPTH = ../..
|
||||
MODULE = nss
|
||||
|
||||
CPPSRCS = \
|
||||
certhigh_unittest.cc \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
-I$(CORE_DEPTH)/gtests/common \
|
||||
-I$(CORE_DEPTH)/cpputil
|
||||
|
||||
REQUIRES = nspr nss libdbm gtest
|
||||
|
||||
PROGRAM = certhigh_gtest
|
||||
|
||||
EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) $(EXTRA_OBJS) \
|
||||
../common/$(OBJDIR)/gtests$(OBJ_SUFFIX)
|
|
@ -0,0 +1,26 @@
|
|||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "blapi.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class DHTest : public ::testing::Test {
|
||||
protected:
|
||||
void TestGenParamSuccess(int size) {
|
||||
DHParams *params;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_EQ(SECSuccess, DH_GenParam(size, ¶ms));
|
||||
PORT_FreeArena(params->arena, PR_TRUE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Test parameter generation for minimum and some common key sizes
|
||||
TEST_F(DHTest, DhGenParamSuccessTest16) { TestGenParamSuccess(16); }
|
||||
TEST_F(DHTest, DhGenParamSuccessTest224) { TestGenParamSuccess(224); }
|
||||
TEST_F(DHTest, DhGenParamSuccessTest256) { TestGenParamSuccess(256); }
|
||||
|
||||
} // nss_test
|
|
@ -12,6 +12,7 @@
|
|||
'type': 'executable',
|
||||
'sources': [
|
||||
'mpi_unittest.cc',
|
||||
'dh_unittest.cc',
|
||||
'<(DEPTH)/gtests/common/gtests.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
|
|
|
@ -40,16 +40,18 @@ class MPITest : public ::testing::Test {
|
|||
protected:
|
||||
void TestCmp(const std::string a_string, const std::string b_string,
|
||||
int result) {
|
||||
mp_int a, b, c;
|
||||
mp_int a, b;
|
||||
MP_DIGITS(&a) = 0;
|
||||
MP_DIGITS(&b) = 0;
|
||||
MP_DIGITS(&c) = 0;
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&a));
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&b));
|
||||
|
||||
mp_read_radix(&a, a_string.c_str(), 16);
|
||||
mp_read_radix(&b, b_string.c_str(), 16);
|
||||
EXPECT_EQ(result, mp_cmp(&a, &b));
|
||||
|
||||
mp_clear(&a);
|
||||
mp_clear(&b);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -58,7 +60,41 @@ TEST_F(MPITest, MpiCmp10Test) { TestCmp("1", "0", 1); }
|
|||
TEST_F(MPITest, MpiCmp00Test) { TestCmp("0", "0", 0); }
|
||||
TEST_F(MPITest, MpiCmp11Test) { TestCmp("1", "1", 0); }
|
||||
|
||||
TEST_F(MPITest, MpiCmpConstTest) {
|
||||
TEST_F(MPITest, MpiCmpUnalignedTest) {
|
||||
mp_int a, b, c;
|
||||
MP_DIGITS(&a) = 0;
|
||||
MP_DIGITS(&b) = 0;
|
||||
MP_DIGITS(&c) = 0;
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&a));
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&b));
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&c));
|
||||
|
||||
mp_read_radix(&a, "ffffffffffffffff3b4e802b4e1478", 16);
|
||||
mp_read_radix(&b, "ffffffffffffffff3b4e802b4e1478", 16);
|
||||
EXPECT_EQ(0, mp_cmp(&a, &b));
|
||||
|
||||
// Now change a and b such that they contain the same numbers but are not
|
||||
// aligned.
|
||||
// a = ffffffffffffff|ff3b4e802b4e1478
|
||||
// b = ffffffffffffffff|3b4e802b4e1478
|
||||
MP_DIGITS(&b)[0] &= 0x00ffffffffffffff;
|
||||
MP_DIGITS(&b)[1] = 0xffffffffffffffff;
|
||||
EXPECT_EQ(-1, mp_cmp(&a, &b));
|
||||
|
||||
ASSERT_EQ(MP_OKAY, mp_sub(&a, &b, &c));
|
||||
char c_tmp[40];
|
||||
ASSERT_EQ(MP_OKAY, mp_toradix(&c, c_tmp, 16));
|
||||
ASSERT_TRUE(strncmp(c_tmp, "feffffffffffffff100000000000000", 31));
|
||||
|
||||
mp_clear(&a);
|
||||
mp_clear(&b);
|
||||
mp_clear(&c);
|
||||
}
|
||||
|
||||
// This test is slow. Disable it by default so we can run these tests on CI.
|
||||
class DISABLED_MPITest : public ::testing::Test {};
|
||||
|
||||
TEST_F(DISABLED_MPITest, MpiCmpConstTest) {
|
||||
mp_int a, b, c;
|
||||
MP_DIGITS(&a) = 0;
|
||||
MP_DIGITS(&b) = 0;
|
||||
|
@ -115,6 +151,10 @@ TEST_F(MPITest, MpiCmpConstTest) {
|
|||
ASSERT_EQ(1, r);
|
||||
}
|
||||
printf("time c: %u\n", time_c / runs);
|
||||
|
||||
mp_clear(&a);
|
||||
mp_clear(&b);
|
||||
mp_clear(&c);
|
||||
}
|
||||
|
||||
} // nss_test
|
||||
|
|
|
@ -8,6 +8,8 @@ DEPTH = ..
|
|||
DIRS = \
|
||||
google_test \
|
||||
common \
|
||||
certdb_gtest \
|
||||
certhigh_gtest \
|
||||
der_gtest \
|
||||
util_gtest \
|
||||
pk11_gtest \
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче