зеркало из https://github.com/mozilla/gecko-dev.git
Bug 911641 (part 1) - Remove about:compartments, and show the compartment and ghost window lists into about:memory. r=johns.
--HG-- extra : rebase_source : c1ef005e272048e2eb84b20bafff15bcb5aae511
This commit is contained in:
Родитель
03da338222
Коммит
fbf85946b7
|
@ -49,8 +49,7 @@ static RedirEntry kRedirMap[] = {
|
|||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
|
||||
// aboutMemory.xhtml implements about:compartments
|
||||
{ "compartments", "chrome://global/content/aboutMemory.xhtml",
|
||||
{ "compartments", "chrome://global/content/aboutCompartments.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
{ "memory", "chrome://global/content/aboutMemory.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
|
|
|
@ -716,7 +716,7 @@ ReportGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void* aClosure)
|
|||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_COUNT,
|
||||
/* amount = */ 1,
|
||||
/* desc = */ EmptyCString(),
|
||||
/* description = */ NS_LITERAL_CSTRING("A ghost window."),
|
||||
data->closure);
|
||||
|
||||
if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
|
||||
|
|
|
@ -1563,12 +1563,12 @@ GetCompartmentName(JSCompartment *c, nsCString &name, bool replaceSlashes)
|
|||
|
||||
// Telemetry relies on this being a uni-reporter (rather than part of the "js"
|
||||
// reporter).
|
||||
class JSGCHeapReporter MOZ_FINAL : public MemoryUniReporter
|
||||
class JSMainRuntimeGCHeapReporter MOZ_FINAL : public MemoryUniReporter
|
||||
{
|
||||
public:
|
||||
JSGCHeapReporter()
|
||||
: MemoryUniReporter("js-gc-heap", KIND_OTHER, UNITS_BYTES,
|
||||
"Memory used by the garbage-collected JavaScript heap.")
|
||||
JSMainRuntimeGCHeapReporter()
|
||||
: MemoryUniReporter("js-main-runtime-gc-heap", KIND_OTHER, UNITS_BYTES,
|
||||
"Memory used by the garbage-collected heap in the main JSRuntime.")
|
||||
{}
|
||||
private:
|
||||
int64_t Amount() MOZ_OVERRIDE
|
||||
|
@ -1579,21 +1579,20 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
// Nb: js-compartments/system + js-compartments/user could be different to the
|
||||
// number of compartments reported by JSReporter if a garbage collection
|
||||
// occurred between them being consulted. We could move these reporters into
|
||||
// JSReporter to avoid that problem, but then we couldn't easily report them
|
||||
// via telemetry, so we live with the small risk of inconsistencies.
|
||||
// Nb: js-main-runtime-compartments/system + js-main-runtime-compartments/user
|
||||
// could be different to the number of compartments reported by JSReporter if a
|
||||
// garbage collection occurred between them being consulted. We could move
|
||||
// these reporters into JSReporter to avoid that problem, but then we couldn't
|
||||
// easily report them via telemetry, so we live with the small risk of
|
||||
// inconsistencies.
|
||||
|
||||
class JSCompartmentsSystemReporter MOZ_FINAL : public MemoryUniReporter
|
||||
class JSMainRuntimeCompartmentsCountSystemReporter MOZ_FINAL : public MemoryUniReporter
|
||||
{
|
||||
public:
|
||||
JSCompartmentsSystemReporter()
|
||||
: MemoryUniReporter("js-compartments/system", KIND_OTHER, UNITS_COUNT,
|
||||
"The number of JavaScript compartments for system code. The sum of this and "
|
||||
"'js-compartments/user' might not match the number of compartments listed "
|
||||
"in the 'explicit' tree if a garbage collection occurs at an inopportune "
|
||||
"time, but such cases should be rare.")
|
||||
JSMainRuntimeCompartmentsCountSystemReporter()
|
||||
: MemoryUniReporter("js-main-runtime-compartments-count/system",
|
||||
KIND_OTHER, UNITS_COUNT,
|
||||
"The number of JavaScript compartments for system code in the main JSRuntime.")
|
||||
{}
|
||||
private:
|
||||
int64_t Amount() MOZ_OVERRIDE
|
||||
|
@ -1603,15 +1602,13 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class JSCompartmentsUserReporter MOZ_FINAL : public MemoryUniReporter
|
||||
class JSMainRuntimeCompartmentsCountUserReporter MOZ_FINAL : public MemoryUniReporter
|
||||
{
|
||||
public:
|
||||
JSCompartmentsUserReporter()
|
||||
: MemoryUniReporter("js-compartments/user", KIND_OTHER, UNITS_COUNT,
|
||||
"The number of JavaScript compartments for user code. The sum of this and "
|
||||
"'js-compartments/system' might not match the number of compartments listed "
|
||||
"under 'js' if a garbage collection occurs at an inopportune time, but such "
|
||||
"cases should be rare.")
|
||||
JSMainRuntimeCompartmentsCountUserReporter()
|
||||
: MemoryUniReporter("js-main-runtime-compartments-count/user",
|
||||
KIND_OTHER, UNITS_COUNT,
|
||||
"The number of JavaScript compartments for user code in the main JSRuntime.")
|
||||
{}
|
||||
private:
|
||||
int64_t Amount() MOZ_OVERRIDE
|
||||
|
@ -2360,13 +2357,13 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
|
|||
|
||||
} // namespace xpc
|
||||
|
||||
class JSCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
|
||||
class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
NS_IMETHOD GetName(nsACString &name) {
|
||||
name.AssignLiteral("compartments");
|
||||
name.AssignLiteral("js-main-runtime-compartments");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2378,8 +2375,8 @@ class JSCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
|
|||
nsCString path;
|
||||
GetCompartmentName(c, path, true);
|
||||
path.Insert(js::IsSystemCompartment(c)
|
||||
? NS_LITERAL_CSTRING("compartments/system/")
|
||||
: NS_LITERAL_CSTRING("compartments/user/"),
|
||||
? NS_LITERAL_CSTRING("js-main-runtime-compartments/system/")
|
||||
: NS_LITERAL_CSTRING("js-main-runtime-compartments/user/"),
|
||||
0);
|
||||
paths->append(path);
|
||||
}
|
||||
|
@ -2400,13 +2397,14 @@ class JSCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
|
|||
// Report.
|
||||
for (size_t i = 0; i < paths.length(); i++)
|
||||
// These ones don't need a description, hence the "".
|
||||
REPORT(nsCString(paths[i]), KIND_OTHER, UNITS_COUNT, 1, "");
|
||||
REPORT(nsCString(paths[i]), KIND_OTHER, UNITS_COUNT, 1,
|
||||
"A live compartment in the main JSRuntime.");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(JSCompartmentsReporter, nsIMemoryReporter)
|
||||
NS_IMPL_ISUPPORTS1(JSMainRuntimeCompartmentsReporter, nsIMemoryReporter)
|
||||
|
||||
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(OrphanMallocSizeOf)
|
||||
|
||||
|
@ -3044,11 +3042,11 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
|||
if (!xpc_LocalizeRuntime(runtime))
|
||||
NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
|
||||
|
||||
NS_RegisterMemoryReporter(new JSGCHeapReporter());
|
||||
NS_RegisterMemoryReporter(new JSCompartmentsSystemReporter());
|
||||
NS_RegisterMemoryReporter(new JSCompartmentsUserReporter());
|
||||
NS_RegisterMemoryReporter(new JSMainRuntimeGCHeapReporter());
|
||||
NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsCountSystemReporter());
|
||||
NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsCountUserReporter());
|
||||
NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
|
||||
NS_RegisterMemoryReporter(new JSCompartmentsReporter);
|
||||
NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter);
|
||||
|
||||
// Install a JavaScript 'debugger' keyword handler in debug builds only
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* This file is used for both about:memory and about:compartments.
|
||||
*
|
||||
* The version used for desktop is located at
|
||||
* toolkit/components/aboutmemory/content/aboutMemory.css.
|
||||
* Mobile-specific stuff is at the bottom of this file.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>about:compartments</title>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
</head>
|
||||
|
||||
<body>about:compartments no longer exists. The lists of compartments and
|
||||
ghost windows can now be found in the "Other Measurements" section of
|
||||
about:memory.</body>
|
||||
</html>
|
|
@ -3,8 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* This file is used for both about:memory and about:compartments.
|
||||
*
|
||||
* The version used for mobile is located at
|
||||
* mobile/android/themes/core/aboutMemory.css.
|
||||
* Desktop-specific stuff is at the bottom of this file.
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* 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/. */
|
||||
|
||||
// This file is used for both about:memory and about:compartments.
|
||||
|
||||
// You can direct about:memory to immediately load memory reports from a file
|
||||
// by providing a file= query string. For example,
|
||||
//
|
||||
|
@ -15,14 +13,9 @@
|
|||
// "file=" argument, and obviously the filename is case-sensitive iff you're on
|
||||
// a case-sensitive filesystem. If you specify more than one "file=" argument,
|
||||
// only the first one is used.
|
||||
//
|
||||
// about:compartments doesn't support "file=" parameters and will ignore them
|
||||
// if they're provided.
|
||||
|
||||
"use strict";
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Code shared by about:memory and about:compartments
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const Cc = Components.classes;
|
||||
|
@ -59,12 +52,6 @@ let gUnnamedProcessStr = "Main Process";
|
|||
|
||||
let gIsDiff = false;
|
||||
|
||||
{
|
||||
let split = document.location.href.split('?');
|
||||
// The toLowerCase() calls ensure that addresses like "ABOUT:MEMORY" work.
|
||||
document.title = split[0].toLowerCase();
|
||||
}
|
||||
|
||||
let gChildMemoryListener = undefined;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -140,22 +127,11 @@ function addChildObserversAndUpdate(aUpdateFn)
|
|||
gChildMemoryListener();
|
||||
}
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
if (document.title === "about:memory") {
|
||||
onLoadAboutMemory();
|
||||
} else if (document.title === "about:compartments") {
|
||||
onLoadAboutCompartments();
|
||||
} else {
|
||||
assert(false, "Unknown location: " + document.title);
|
||||
}
|
||||
}
|
||||
|
||||
function onUnload()
|
||||
{
|
||||
// We need to check if the observer has been added before removing; in some
|
||||
// circumstances (e.g. reloading the page quickly) it might not have because
|
||||
// onLoadAbout{Memory,Compartments} might not fire.
|
||||
// onLoad might not fire.
|
||||
if (gChildMemoryListener) {
|
||||
let os = Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(Ci.nsIObserverService);
|
||||
|
@ -227,7 +203,7 @@ function processMemoryReportsFromFile(aReports, aIgnoreReport, aHandleReport)
|
|||
// It's what is updated each time the page changes.
|
||||
let gMain;
|
||||
|
||||
// The <div> holding the footer. Is undefined in about:compartments.
|
||||
// The <div> holding the footer.
|
||||
let gFooter;
|
||||
|
||||
// The "verbose" checkbox.
|
||||
|
@ -260,13 +236,11 @@ function updateMainAndFooter(aMsg, aFooterAction, aClassName)
|
|||
appendElementWithText(gMain, 'div', className, aMsg);
|
||||
}
|
||||
|
||||
if (gFooter !== undefined) {
|
||||
switch (aFooterAction) {
|
||||
case HIDE_FOOTER: gFooter.classList.add('hidden'); break;
|
||||
case SHOW_FOOTER: gFooter.classList.remove('hidden'); break;
|
||||
case IGNORE_FOOTER: break;
|
||||
default: assertInput(false, "bad footer action in updateMainAndFooter");
|
||||
}
|
||||
switch (aFooterAction) {
|
||||
case HIDE_FOOTER: gFooter.classList.add('hidden'); break;
|
||||
case SHOW_FOOTER: gFooter.classList.remove('hidden'); break;
|
||||
case IGNORE_FOOTER: break;
|
||||
default: assertInput(false, "bad footer action in updateMainAndFooter");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,8 +271,6 @@ function appendElementWithText(aP, aTagName, aClassName, aText)
|
|||
return e;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Code specific to about:memory
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const kTreeDescriptions = {
|
||||
|
@ -405,7 +377,7 @@ function appendHiddenFileInput(aP, aId, aChangeListener)
|
|||
return input;
|
||||
}
|
||||
|
||||
function onLoadAboutMemory()
|
||||
function onLoad()
|
||||
{
|
||||
// Generate the header.
|
||||
|
||||
|
@ -438,7 +410,7 @@ function onLoadAboutMemory()
|
|||
delete this.filename1;
|
||||
updateAboutMemoryFromTwoFiles(filename1, file.mozFullPath);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const CuDesc = "Measure current memory reports and show.";
|
||||
const LdDesc = "Load memory reports from file and show.";
|
||||
|
@ -512,9 +484,9 @@ function onLoadAboutMemory()
|
|||
appendElementWithText(gFooter, "div", "legend", legendText1);
|
||||
appendElementWithText(gFooter, "div", "legend hiddenOnMobile", legendText2);
|
||||
|
||||
// See if we're loading from a file. (Because about:memory and
|
||||
// about:compartments are non-standard URLs, location.search is undefined, so
|
||||
// we have to use location.href instead.)
|
||||
// See if we're loading from a file. (Because about:memory is a non-standard
|
||||
// URL, location.search is undefined, so we have to use location.href
|
||||
// instead.)
|
||||
let search = location.href.split('?')[1];
|
||||
if (search) {
|
||||
let searchSplit = search.split('&');
|
||||
|
@ -1041,9 +1013,9 @@ function getPCollsByProcess(aProcessReports, aForceShowSmaps)
|
|||
const gSentenceRegExp = /^[A-Z].*\.\)?$/m;
|
||||
|
||||
// Ignore the "smaps" reporter in non-verbose mode unless we're reading from
|
||||
// a file or the clipboard, and ignore the "compartments" and "ghost-windows"
|
||||
// reporters all the time. (Note that reports from these reporters can reach
|
||||
// here via a "content-child" reporter if they were in a child process.)
|
||||
// a file or the clipboard. (Note that reports from these reporters can
|
||||
// reach here via a "content-child" reporter if they were in a child
|
||||
// process.)
|
||||
//
|
||||
// Also ignore the "resident-fast" reporter; we use the vanilla "resident"
|
||||
// reporter because it's more important that we get accurate results than
|
||||
|
@ -1056,16 +1028,12 @@ function getPCollsByProcess(aProcessReports, aForceShowSmaps)
|
|||
function ignoreReporter(aName)
|
||||
{
|
||||
return (aName === "smaps" && !gVerbose.checked && !aForceShowSmaps) ||
|
||||
aName === "compartments" ||
|
||||
aName === "ghost-windows" ||
|
||||
aName === "resident-fast";
|
||||
}
|
||||
|
||||
function ignoreReport(aUnsafePath)
|
||||
{
|
||||
return (isSmapsPath(aUnsafePath) && !gVerbose.checked && !aForceShowSmaps) ||
|
||||
aUnsafePath.startsWith("compartments/") ||
|
||||
aUnsafePath.startsWith("ghost-windows/") ||
|
||||
aUnsafePath == "resident-fast";
|
||||
}
|
||||
|
||||
|
@ -1089,7 +1057,7 @@ function getPCollsByProcess(aProcessReports, aForceShowSmaps)
|
|||
"non-sentence other description");
|
||||
}
|
||||
|
||||
assert(aPresence === undefined ||
|
||||
assert(aPresence === undefined ||
|
||||
aPresence == DReport.PRESENT_IN_FIRST_ONLY ||
|
||||
aPresence == DReport.PRESENT_IN_SECOND_ONLY);
|
||||
|
||||
|
@ -2001,279 +1969,3 @@ function saveReportsToFile()
|
|||
};
|
||||
fp.open(fpCallback);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Code specific to about:compartments
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function onLoadAboutCompartments()
|
||||
{
|
||||
// Generate the main div, where content will go. about:compartments doesn't
|
||||
// have a header or footer.
|
||||
gMain = appendElement(document.body, 'div', 'section');
|
||||
|
||||
// First generate the page, then minimize memory usage to collect any dead
|
||||
// compartments, then update the page. The first generation step may sound
|
||||
// unnecessary, but it avoids a short delay in showing content when the page
|
||||
// is loaded, which makes test_aboutcompartments.xul more reliable (see bug
|
||||
// 729018 for details).
|
||||
updateAboutCompartments();
|
||||
gMgr.minimizeMemoryUsage(
|
||||
function() { addChildObserversAndUpdate(updateAboutCompartments); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Top-level function that does the work of generating the page.
|
||||
*/
|
||||
function updateAboutCompartments()
|
||||
{
|
||||
// First, clear the contents of main. Necessary because
|
||||
// updateAboutMemoryFromReporters() might be called more than once due to the
|
||||
// "child-memory-reporter-update" observer.
|
||||
updateMainAndFooter("", IGNORE_FOOTER);
|
||||
|
||||
try {
|
||||
let compartmentsByProcess = getCompartmentsByProcess();
|
||||
let ghostWindowsByProcess = getGhostWindowsByProcess();
|
||||
|
||||
// Sort our list of processes.
|
||||
let processes = Object.keys(compartmentsByProcess);
|
||||
processes.sort(function(aProcessA, aProcessB) {
|
||||
assert(aProcessA != aProcessB,
|
||||
"Elements of Object.keys() should be unique, but " +
|
||||
"saw duplicate '" + aProcessA + "' elem.");
|
||||
|
||||
// Always put the main process first.
|
||||
if (aProcessA == gUnnamedProcessStr) {
|
||||
return -1;
|
||||
}
|
||||
if (aProcessB == gUnnamedProcessStr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Otherwise the order doesn't matter.
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Generate output for each process.
|
||||
for (let i = 0; i < processes.length; i++) {
|
||||
let process = processes[i];
|
||||
appendProcessAboutCompartmentsElements(gMain, process,
|
||||
compartmentsByProcess[process],
|
||||
ghostWindowsByProcess[process]);
|
||||
}
|
||||
|
||||
} catch (ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
function Compartment(aUnsafeName, aIsSystemCompartment)
|
||||
{
|
||||
this._unsafeName = aUnsafeName;
|
||||
this._isSystemCompartment = aIsSystemCompartment;
|
||||
// this._nMerged is only defined if > 1
|
||||
}
|
||||
|
||||
Compartment.prototype = {
|
||||
merge: function(aR) {
|
||||
this._nMerged = this._nMerged ? this._nMerged + 1 : 2;
|
||||
}
|
||||
};
|
||||
|
||||
function getCompartmentsByProcess()
|
||||
{
|
||||
// Ignore anything that didn't come from the "compartments" reporter. (Note
|
||||
// reports from this reporter can reach here via a "content-child" reporter
|
||||
// if they were in a child process.)
|
||||
|
||||
function ignoreReporter(aName)
|
||||
{
|
||||
return !(aName == "compartments" || aName == "content-child");
|
||||
}
|
||||
|
||||
function ignoreReport(aUnsafePath)
|
||||
{
|
||||
return !aUnsafePath.startsWith("compartments/");
|
||||
}
|
||||
|
||||
let compartmentsByProcess = {};
|
||||
|
||||
function handleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
|
||||
aDescription)
|
||||
{
|
||||
let process = aProcess === "" ? gUnnamedProcessStr : aProcess;
|
||||
let unsafeNames = aUnsafePath.split('/');
|
||||
let isSystemCompartment;
|
||||
if (unsafeNames[0] === "compartments" && unsafeNames[1] == "system" &&
|
||||
unsafeNames.length == 3)
|
||||
{
|
||||
isSystemCompartment = true;
|
||||
|
||||
} else if (unsafeNames[0] === "compartments" && unsafeNames[1] == "user" &&
|
||||
unsafeNames.length == 3)
|
||||
{
|
||||
isSystemCompartment = false;
|
||||
// These null principal compartments are user compartments according to
|
||||
// the JS engine, but they look odd being shown with content
|
||||
// compartments, so we put them in the system compartments list.
|
||||
if (unsafeNames[2].startsWith("moz-nullprincipal:{")) {
|
||||
isSystemCompartment = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
assertInput(false, "bad compartments path: " + aUnsafePath);
|
||||
}
|
||||
assertInput(aKind === KIND_OTHER, "bad compartments kind");
|
||||
assertInput(aUnits === UNITS_COUNT, "bad compartments units");
|
||||
assertInput(aAmount === 1, "bad compartments amount");
|
||||
assertInput(aDescription === "", "bad compartments description");
|
||||
|
||||
let c = new Compartment(unsafeNames[2], isSystemCompartment);
|
||||
|
||||
if (!compartmentsByProcess[process]) {
|
||||
compartmentsByProcess[process] = {};
|
||||
}
|
||||
let compartments = compartmentsByProcess[process];
|
||||
let cOld = compartments[c._unsafeName];
|
||||
if (cOld) {
|
||||
// Already an entry; must be a duplicated compartment. This can happen
|
||||
// legitimately. Merge them.
|
||||
cOld.merge(c);
|
||||
} else {
|
||||
compartments[c._unsafeName] = c;
|
||||
}
|
||||
}
|
||||
|
||||
processMemoryReporters(ignoreReporter, ignoreReport, handleReport);
|
||||
|
||||
return compartmentsByProcess;
|
||||
}
|
||||
|
||||
function GhostWindow(aUnsafeURL)
|
||||
{
|
||||
// Call it _unsafeName rather than _unsafeURL for symmetry with the
|
||||
// Compartment object.
|
||||
this._unsafeName = aUnsafeURL;
|
||||
|
||||
// this._nMerged is only defined if > 1
|
||||
}
|
||||
|
||||
GhostWindow.prototype = {
|
||||
merge: function(aR) {
|
||||
this._nMerged = this._nMerged ? this._nMerged + 1 : 2;
|
||||
}
|
||||
};
|
||||
|
||||
function getGhostWindowsByProcess()
|
||||
{
|
||||
function ignoreReporter(aName)
|
||||
{
|
||||
return !(aName == "ghost-windows" || aName == "content-child");
|
||||
}
|
||||
|
||||
function ignoreReport(aUnsafePath)
|
||||
{
|
||||
return !aUnsafePath.startsWith('ghost-windows/')
|
||||
}
|
||||
|
||||
let ghostWindowsByProcess = {};
|
||||
|
||||
function handleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
|
||||
aDescription)
|
||||
{
|
||||
let unsafeSplit = aUnsafePath.split('/');
|
||||
assertInput(unsafeSplit[0] === 'ghost-windows' && unsafeSplit.length === 2,
|
||||
'Unexpected path in getGhostWindowsByProcess: ' + aUnsafePath);
|
||||
assertInput(aKind === KIND_OTHER, "bad ghost-windows kind");
|
||||
assertInput(aUnits === UNITS_COUNT, "bad ghost-windows units");
|
||||
assertInput(aAmount === 1, "bad ghost-windows amount");
|
||||
assertInput(aDescription === "", "bad ghost-windows description");
|
||||
|
||||
let unsafeURL = unsafeSplit[1];
|
||||
let ghostWindow = new GhostWindow(unsafeURL);
|
||||
|
||||
let process = aProcess === "" ? gUnnamedProcessStr : aProcess;
|
||||
if (!ghostWindowsByProcess[process]) {
|
||||
ghostWindowsByProcess[process] = {};
|
||||
}
|
||||
|
||||
if (ghostWindowsByProcess[process][unsafeURL]) {
|
||||
ghostWindowsByProcess[process][unsafeURL].merge(ghostWindow);
|
||||
}
|
||||
else {
|
||||
ghostWindowsByProcess[process][unsafeURL] = ghostWindow;
|
||||
}
|
||||
}
|
||||
|
||||
processMemoryReporters(ignoreReporter, ignoreReport, handleReport);
|
||||
|
||||
return ghostWindowsByProcess;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
function appendProcessAboutCompartmentsElementsHelper(aP, aEntries, aKindString)
|
||||
{
|
||||
// aEntries might be null or undefined, e.g. if there are no ghost windows
|
||||
// for this process.
|
||||
aEntries = aEntries ? aEntries : {};
|
||||
|
||||
appendElementWithText(aP, "h2", "", aKindString + "\n");
|
||||
|
||||
let uPre = appendElement(aP, "pre", "entries");
|
||||
|
||||
let lines = [];
|
||||
for (let name in aEntries) {
|
||||
let e = aEntries[name];
|
||||
let line = flipBackslashes(e._unsafeName);
|
||||
if (e._nMerged) {
|
||||
line += ' [' + e._nMerged + ']';
|
||||
}
|
||||
line += '\n';
|
||||
lines.push(line);
|
||||
}
|
||||
lines.sort();
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
appendElementWithText(uPre, "span", "", lines[i]);
|
||||
}
|
||||
|
||||
appendTextNode(aP, "\n"); // gives nice spacing when we cut and paste
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the elements for a single process.
|
||||
*
|
||||
* @param aP
|
||||
* The parent DOM node.
|
||||
* @param aProcess
|
||||
* The name of the process.
|
||||
* @param aCompartments
|
||||
* Table of Compartments for this process, indexed by _unsafeName.
|
||||
* @param aGhostWindows
|
||||
* Array of window URLs of ghost windows.
|
||||
*/
|
||||
function appendProcessAboutCompartmentsElements(aP, aProcess, aCompartments, aGhostWindows)
|
||||
{
|
||||
appendElementWithText(aP, "h1", "", aProcess + "\n\n");
|
||||
|
||||
let userCompartments = {};
|
||||
let systemCompartments = {};
|
||||
for (let name in aCompartments) {
|
||||
let c = aCompartments[name];
|
||||
if (c._isSystemCompartment) {
|
||||
systemCompartments[name] = c;
|
||||
}
|
||||
else {
|
||||
userCompartments[name] = c;
|
||||
}
|
||||
}
|
||||
|
||||
appendProcessAboutCompartmentsElementsHelper(aP, userCompartments, "User Compartments");
|
||||
appendProcessAboutCompartmentsElementsHelper(aP, systemCompartments, "System Compartments");
|
||||
appendProcessAboutCompartmentsElementsHelper(aP, aGhostWindows, "Ghost Windows");
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
- 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/. -->
|
||||
|
||||
<!-- This file is used for both about:memory and about:compartments. -->
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<!-- the <title> is filled in by aboutMemory.js -->
|
||||
<title>about:memory</title>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
<link rel="stylesheet" href="chrome://global/skin/aboutMemory.css" type="text/css"/>
|
||||
<script type="text/javascript;version=1.8" src="chrome://global/content/aboutMemory.js"/>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
toolkit.jar:
|
||||
+ content/global/aboutCompartments.xhtml (content/aboutCompartments.xhtml)
|
||||
+ content/global/aboutMemory.js (content/aboutMemory.js)
|
||||
+ content/global/aboutMemory.xhtml (content/aboutMemory.xhtml)
|
||||
+ content/global/aboutMemory.css (content/aboutMemory.css)
|
||||
|
|
|
@ -8,7 +8,6 @@ MOCHITEST_CHROME_FILES = \
|
|||
memory-reports-bad.json \
|
||||
memory-reports-diff1.json \
|
||||
memory-reports-diff2.json \
|
||||
test_aboutcompartments.xul \
|
||||
test_aboutmemory.xul \
|
||||
test_aboutmemory2.xul \
|
||||
test_aboutmemory3.xul \
|
||||
|
|
|
@ -1,224 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:compartments"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- This file uses fake memory reporters to test the presentation of
|
||||
compartment memory reports in about:memory. test_memoryReporters.xul
|
||||
uses the real memory reporters to test whether the memory reporters
|
||||
are producing sensible results. -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
// Remove all the real reporters; save them to restore at the end.
|
||||
mgr.blockRegistration();
|
||||
var e = mgr.enumerateReporters();
|
||||
var realReporters = [];
|
||||
while (e.hasMoreElements()) {
|
||||
var r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||
mgr.unregisterReporter(r);
|
||||
realReporters.push(r);
|
||||
}
|
||||
|
||||
// Setup various fake-but-deterministic reporters.
|
||||
const KB = 1024;
|
||||
const MB = KB * KB;
|
||||
const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP;
|
||||
const HEAP = Ci.nsIMemoryReporter.KIND_HEAP;
|
||||
const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
|
||||
|
||||
const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
|
||||
const COUNT = Ci.nsIMemoryReporter.UNITS_COUNT;
|
||||
|
||||
var fakeReporters = [
|
||||
{ name: "fake1",
|
||||
collectReports: function(aCbObj, aClosure) {
|
||||
function f(aP1, aP2, aK, aU, aA) {
|
||||
aCbObj.callback(aP1, aP2, aK, aU, aA, "Desc.", aClosure);
|
||||
}
|
||||
// These should be ignored.
|
||||
f("", "explicit/a", HEAP, BYTES, 222 * MB);
|
||||
f("", "explicit/b/a", HEAP, BYTES, 85 * MB);
|
||||
f("", "explicit/b/b", NONHEAP, BYTES, 85 * MB);
|
||||
f("", "other1", OTHER, BYTES, 111 * MB);
|
||||
f("", "other2", OTHER, COUNT, 888);
|
||||
}
|
||||
},
|
||||
{ name: "fake2",
|
||||
collectReports: function(aCbObj, aClosure) {
|
||||
function f(aP, aK, aU, aA) {
|
||||
aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
|
||||
}
|
||||
// These shouldn't show up.
|
||||
f("explicit/a/d", HEAP, BYTES, 13 * MB);
|
||||
f("explicit/b/c", NONHEAP, BYTES, 10 * MB);
|
||||
}
|
||||
},
|
||||
{ name: "content-child",
|
||||
collectReports: function(aCbObj, aClosure) {
|
||||
function f(aP1, aP2, aK, aU, aA, aD) {
|
||||
aCbObj.callback(aP1, aP2, aK, aU, aA, aD, aClosure);
|
||||
}
|
||||
f("2nd", "explicit/c", HEAP, BYTES, 333 * MB, "Desc.");
|
||||
f("2nd", "compartments/user/child-user-compartment", OTHER, COUNT, 1, "");
|
||||
f("2nd", "compartments/system/child-system-compartment", OTHER, COUNT, 1, "");
|
||||
}
|
||||
},
|
||||
{ name: "compartments",
|
||||
collectReports: function(aCbObj, aClosure) {
|
||||
function f(aP) {
|
||||
aCbObj.callback("", aP, OTHER, COUNT, 1, "", aClosure);
|
||||
}
|
||||
f("compartments/user/http:\\\\foo.com\\");
|
||||
f("compartments/user/https:\\\\bar.com\\bar?baz");
|
||||
f("compartments/user/https:\\\\very-long-url.com\\very-long\\oh-so-long\\really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789");
|
||||
// This moz-nullprincipal one is shown under "System Compartments" even
|
||||
// though its path indicates it's a user compartment.
|
||||
f("compartments/user/moz-nullprincipal:{7ddefdaf-34f1-473f-9b03-50a4568ccb06}");
|
||||
// This should show up once with a "[3]" suffix
|
||||
f("compartments/system/[System Principal]");
|
||||
f("compartments/system/[System Principal]");
|
||||
f("compartments/system/[System Principal]");
|
||||
f("compartments/system/atoms");
|
||||
}
|
||||
},
|
||||
{ name: "ghost-windows",
|
||||
collectReports: function(aCbObj, aClosure) {
|
||||
function f(aP) {
|
||||
aCbObj.callback("", aP, OTHER, COUNT, 1, "", aClosure);
|
||||
}
|
||||
f("ghost-windows/https:\\\\very-long-url.com\\very-long\\oh-so-long\\really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789");
|
||||
f("ghost-windows/http:\\\\foobar.com\\foo?bar#baz");
|
||||
}
|
||||
},
|
||||
// These shouldn't show up.
|
||||
{ name: "smaps",
|
||||
collectReports: function(aCbObj, aClosure) {
|
||||
// The amounts are given in pages, so multiply here by 4kb.
|
||||
function f(aP, aA) {
|
||||
aCbObj.callback("", aP, NONHEAP, BYTES, aA * 4 * KB, "Desc.", aClosure);
|
||||
}
|
||||
f("smaps/vsize/a", 24);
|
||||
f("smaps/swap/a", 1);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
for (var i = 0; i < fakeReporters.length; i++) {
|
||||
mgr.registerReporterEvenIfBlocked(fakeReporters[i]);
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<!-- vary the capitalization to make sure that works -->
|
||||
<iframe id="acFrame" height="400" src="abouT:compartMENTS"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
var acExpectedText =
|
||||
"\
|
||||
Main Process\n\
|
||||
User Compartments\n\
|
||||
\n\
|
||||
http://foo.com/\n\
|
||||
https://bar.com/bar?baz\n\
|
||||
https://very-long-url.com/very-long/oh-so-long/really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789\n\
|
||||
\n\
|
||||
System Compartments\n\
|
||||
\n\
|
||||
[System Principal] [3]\n\
|
||||
atoms\n\
|
||||
moz-nullprincipal:{7ddefdaf-34f1-473f-9b03-50a4568ccb06}\n\
|
||||
\n\
|
||||
Ghost Windows\n\
|
||||
\n\
|
||||
http://foobar.com/foo?bar#baz\n\
|
||||
https://very-long-url.com/very-long/oh-so-long/really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789\n\
|
||||
\n\
|
||||
2nd\n\
|
||||
User Compartments\n\
|
||||
\n\
|
||||
child-user-compartment\n\
|
||||
\n\
|
||||
System Compartments\n\
|
||||
\n\
|
||||
child-system-compartment\n\
|
||||
\n\
|
||||
Ghost Windows\n\
|
||||
\n\
|
||||
";
|
||||
|
||||
function finish()
|
||||
{
|
||||
// Unregister fake reporters and re-register the real reporters, just in
|
||||
// case subsequent tests rely on them.
|
||||
for (var i = 0; i < fakeReporters.length; i++) {
|
||||
mgr.unregisterReporter(fakeReporters[i]);
|
||||
}
|
||||
for (var i = 0; i < realReporters.length; i++) {
|
||||
mgr.registerReporterEvenIfBlocked(realReporters[i]);
|
||||
}
|
||||
mgr.unblockRegistration();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// Cut+paste the entire page and check that the cut text matches what we
|
||||
// expect. This tests the output in general and also that the cutting and
|
||||
// pasting works as expected.
|
||||
function test(aFrameId, aExpected, aNext) {
|
||||
ok(document.title === "about:compartments", "document.title is correct");
|
||||
let frame = document.getElementById(aFrameId);
|
||||
SimpleTest.executeSoon(function() {
|
||||
frame.focus();
|
||||
SimpleTest.waitForClipboard(
|
||||
function(aActual) {
|
||||
mostRecentActual = aActual;
|
||||
return aActual === aExpected;
|
||||
},
|
||||
function() {
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
},
|
||||
aNext,
|
||||
function() {
|
||||
ok(false, "pasted text doesn't match for " + aFrameId);
|
||||
dump("******EXPECTED******\n");
|
||||
dump(aExpected);
|
||||
dump("*******ACTUAL*******\n");
|
||||
dump(mostRecentActual);
|
||||
dump("********************\n");
|
||||
finish();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(function() {
|
||||
test(
|
||||
"acFrame",
|
||||
acExpectedText,
|
||||
function() {
|
||||
finish()
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -113,6 +113,7 @@
|
|||
f("other2", OTHER, BYTES, 222 * MB);
|
||||
f("perc2", OTHER, PERCENTAGE, 10000);
|
||||
f("perc1", OTHER, PERCENTAGE, 4567);
|
||||
f("compartments/user/https:\\\\very-long-url.com\\very-long\\oh-so-long\\really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789", OTHER, COUNT, 1);
|
||||
}
|
||||
},
|
||||
{ name: "smaps",
|
||||
|
@ -133,7 +134,7 @@
|
|||
{ name: "compartments",
|
||||
collectReports: function(aCbObj, aClosure) {
|
||||
function f(aP) {
|
||||
aCbObj.callback("", aP, OTHER, COUNT, 1, "", aClosure);
|
||||
aCbObj.callback("", aP, OTHER, COUNT, 1, "Desc.", aClosure);
|
||||
}
|
||||
f("compartments/user/bar");
|
||||
f("compartments/system/bar");
|
||||
|
@ -272,6 +273,15 @@ Explicit Allocations\n\
|
|||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
5 (100.0%) -- compartments\n\
|
||||
├──3 (60.00%) -- user\n\
|
||||
│ ├──1 (20.00%) ── bar\n\
|
||||
│ ├──1 (20.00%) ── foo\n\
|
||||
│ └──1 (20.00%) ── https://very-long-url.com/very-long/oh-so-long/really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789\n\
|
||||
└──2 (40.00%) -- system\n\
|
||||
├──1 (20.00%) ── bar\n\
|
||||
└──1 (20.00%) ── foo\n\
|
||||
\n\
|
||||
166.00 MB (100.0%) -- other1\n\
|
||||
├──111.00 MB (66.87%) ── a/b\n\
|
||||
└───55.00 MB (33.13%) -- c\n\
|
||||
|
@ -445,6 +455,15 @@ Swap Breakdown\n\
|
|||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
5 (100.0%) -- compartments\n\
|
||||
├──3 (60.00%) -- user\n\
|
||||
│ ├──1 (20.00%) ── bar\n\
|
||||
│ ├──1 (20.00%) ── foo\n\
|
||||
│ └──1 (20.00%) ── https://very-long-url.com/very-long/oh-so-long/really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789\n\
|
||||
└──2 (40.00%) -- system\n\
|
||||
├──1 (20.00%) ── bar\n\
|
||||
└──1 (20.00%) ── foo\n\
|
||||
\n\
|
||||
174,063,616 B (100.0%) -- other1\n\
|
||||
├──116,391,936 B (66.87%) ── a/b\n\
|
||||
└───57,671,680 B (33.13%) -- c\n\
|
||||
|
|
|
@ -54,9 +54,9 @@ const TELEMETRY_DELAY = 60000;
|
|||
// We used to measure "explicit" too, but it could cause hangs, and the data
|
||||
// was always really noisy anyway. See bug 859657.
|
||||
const MEM_HISTOGRAMS = {
|
||||
"js-gc-heap": "MEMORY_JS_GC_HEAP",
|
||||
"js-compartments/system": "MEMORY_JS_COMPARTMENTS_SYSTEM",
|
||||
"js-compartments/user": "MEMORY_JS_COMPARTMENTS_USER",
|
||||
"js-main-runtime-gc-heap": "MEMORY_JS_GC_HEAP",
|
||||
"js-main-runtime-compartments-count/system": "MEMORY_JS_COMPARTMENTS_SYSTEM",
|
||||
"js-main-runtime-compartments-count/user": "MEMORY_JS_COMPARTMENTS_USER",
|
||||
"js-main-runtime-temporary-peak": "MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK",
|
||||
"resident-fast": "MEMORY_RESIDENT",
|
||||
"vsize": "MEMORY_VSIZE",
|
||||
|
|
|
@ -148,11 +148,6 @@ interface nsIMemoryReporterCallback : nsISupports
|
|||
* Reporters in this category must have kind NONHEAP, units BYTES, and a
|
||||
* non-empty description.
|
||||
*
|
||||
* - The "compartments" and "ghost-windows" trees are optional. They are
|
||||
* used by about:compartments. Reporters in these trees must have kind
|
||||
* OTHER, units COUNT, an amount of 1, and a description that's an empty
|
||||
* string.
|
||||
*
|
||||
* - All other reports are unconstrained except that they must have a
|
||||
* description that is a sentence.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче