Merge inbound to central, a=merge

UPGRADE_NSS_RELEASE

MozReview-Commit-ID: 9BuuGYyJ3RJ

--HG--
extra : amend_source : 57de84460e0ace13892ff1623451b9b9be8eaeeb
This commit is contained in:
Wes Kocher 2017-05-17 14:48:30 -07:00
Родитель 154a821d07 e26d8d5744
Коммит 0a5ec26ac6
181 изменённых файлов: 4404 добавлений и 1423 удалений

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

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

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

@ -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, &params));
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 \

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