mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Merge mozilla-central to autoland
This commit is contained in:
commit
8fd069a1f2
11
.cron.yml
11
.cron.yml
@ -59,3 +59,14 @@ jobs:
|
||||
- mozilla-central
|
||||
when:
|
||||
- {hour: 18, minute: 0}
|
||||
|
||||
- name: nightly-stylo-talos
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: T
|
||||
target-tasks-method: stylo_talos
|
||||
run-on-projects:
|
||||
- mozilla-central
|
||||
when:
|
||||
- {hour: 4, minute: 0}
|
||||
|
||||
|
@ -132,7 +132,6 @@ devtools/server/tests/browser/storage-*.html
|
||||
devtools/server/tests/browser/stylesheets-nested-iframes.html
|
||||
devtools/server/tests/mochitest/**
|
||||
devtools/server/tests/unit/**
|
||||
devtools/shared/heapsnapshot/**
|
||||
devtools/shared/platform/content/test/test_clipboard.html
|
||||
devtools/shared/qrcode/tests/mochitest/test_decode.html
|
||||
devtools/shared/tests/mochitest/*.html
|
||||
|
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Merge day clobber
|
||||
Bug 1345336 - Crash in icu_58::TimeZoneFormat::initGMTOffsetPatterns
|
||||
|
@ -1204,6 +1204,11 @@ pref("full-screen-api.enabled", true);
|
||||
// (this pref has no effect if more than 6 hours have passed since the last crash)
|
||||
pref("toolkit.startup.max_resumed_crashes", 3);
|
||||
|
||||
// Whether we use pdfium to view content with the pdf mime type.
|
||||
// Note: if the pref is set to false while Firefox is open, it won't
|
||||
// take effect until there are no open pdfium tabs.
|
||||
pref("pdfium.enabled", false);
|
||||
|
||||
// Completely disable pdf.js as an option to preview pdfs within firefox.
|
||||
// Note: if this is not disabled it does not necessarily mean pdf.js is the pdf
|
||||
// handler just that it is an option.
|
||||
|
@ -249,6 +249,10 @@ let gDecoderDoctorHandler = {
|
||||
// resolution of that issue, to be reported as telemetry.
|
||||
let {type, isSolved, decoderDoctorReportId, formats} = parsedData;
|
||||
type = type.toLowerCase();
|
||||
// Error out early on invalid ReportId
|
||||
if (!(/^\w+$/mi).test(decoderDoctorReportId)) {
|
||||
return
|
||||
}
|
||||
let title = gDecoderDoctorHandler.getLabelForNotificationBox(type);
|
||||
if (!title) {
|
||||
return;
|
||||
|
@ -28,7 +28,7 @@ add_task(function* checkCaptivePortalCertErrorUI() {
|
||||
let tab = gBrowser.addTab(BAD_CERT_PAGE);
|
||||
gBrowser.selectedTab = tab;
|
||||
browser = gBrowser.selectedBrowser;
|
||||
certErrorLoaded = waitForCertErrorLoad(browser);
|
||||
certErrorLoaded = BrowserTestUtils.waitForContentEvent(browser, "DOMContentLoaded");
|
||||
return tab;
|
||||
}, false);
|
||||
|
||||
@ -65,7 +65,7 @@ add_task(function* checkCaptivePortalCertErrorUI() {
|
||||
is(portalTab2, portalTab, "The existing portal tab should be focused.");
|
||||
|
||||
let portalTabRemoved = BrowserTestUtils.removeTab(portalTab, {dontRemove: true});
|
||||
let errorTabReloaded = waitForCertErrorLoad(browser);
|
||||
let errorTabReloaded = BrowserTestUtils.waitForErrorPage(browser);
|
||||
|
||||
Services.obs.notifyObservers(null, "captive-portal-login-success", null);
|
||||
yield portalTabRemoved;
|
||||
|
@ -169,13 +169,3 @@ function* openWindowAndWaitForFocus() {
|
||||
yield SimpleTest.promiseFocus(win);
|
||||
return win;
|
||||
}
|
||||
|
||||
function waitForCertErrorLoad(browser) {
|
||||
return new Promise(resolve => {
|
||||
info("Waiting for DOMContentLoaded event");
|
||||
browser.addEventListener("DOMContentLoaded", function load() {
|
||||
browser.removeEventListener("DOMContentLoaded", load, false, true);
|
||||
resolve();
|
||||
}, false, true);
|
||||
});
|
||||
}
|
||||
|
@ -64,6 +64,8 @@ support-files =
|
||||
[browser_favicon_firstParty.js]
|
||||
[browser_favicon_userContextId.js]
|
||||
[browser_firstPartyIsolation.js]
|
||||
[browser_firstPartyIsolation_aboutPages.js]
|
||||
[browser_firstPartyIsolation_js_uri.js]
|
||||
[browser_localStorageIsolation.js]
|
||||
[browser_blobURLIsolation.js]
|
||||
[browser_imageCacheIsolation.js]
|
||||
|
@ -0,0 +1,184 @@
|
||||
add_task(function* setup() {
|
||||
Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("privacy.firstparty.isolate");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* For loading the initial about:blank in e10s mode, it will be loaded with
|
||||
* NullPrincipal, and we also test if the firstPartyDomain of the origin
|
||||
* attributes is NULL_PRINCIPAL_FIRST_PARTY_DOMAIN.
|
||||
*/
|
||||
add_task(function* test_remote_window_open_aboutBlank() {
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow({ remote: true });
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
||||
Assert.ok(browser.isRemoteBrowser, "should be a remote browser");
|
||||
|
||||
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
|
||||
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
|
||||
info("origin " + content.document.nodePrincipal.origin);
|
||||
|
||||
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
|
||||
"The principal of remote about:blank should be a NullPrincipal.");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
expectAttrs.firstPartyDomain,
|
||||
"remote about:blank should have firstPartyDomain set");
|
||||
});
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
/**
|
||||
* For loading the initial about:blank in non-e10s mode, it will be loaded with
|
||||
* codebase principal. So we test if it has correct firstPartyDomain set.
|
||||
*/
|
||||
add_task(function* test_nonremote_window_open_aboutBlank() {
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow({remote: false});
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
||||
Assert.ok(!browser.isRemoteBrowser, "shouldn't be a remote browser");
|
||||
|
||||
let attrs = { firstPartyDomain: "about.ef2a7dd5-93bc-417f-a698-142c3116864f.mozilla" };
|
||||
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
|
||||
Assert.ok(content.document.nodePrincipal.isCodebasePrincipal,
|
||||
"The principal of non-remote about:blank should be a codebase principal.");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
expectAttrs.firstPartyDomain,
|
||||
"non-remote about:blank should have firstPartyDomain set");
|
||||
});
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
function frame_script() {
|
||||
content.document.body.innerHTML = `
|
||||
<a href="data:text/plain,hello" id="test">hello</a>
|
||||
`;
|
||||
|
||||
let element = content.document.getElementById("test");
|
||||
element.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if data: URI inherits firstPartyDomain from about:blank correctly.
|
||||
*/
|
||||
add_task(function* test_remote_window_open_data_uri() {
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow({ remote: true });
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
let mm = browser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
|
||||
|
||||
yield BrowserTestUtils.browserLoaded(browser, false, function(url) {
|
||||
return url == "data:text/plain,hello";
|
||||
});
|
||||
|
||||
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
|
||||
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
|
||||
info("origin: " + content.document.nodePrincipal.origin);
|
||||
|
||||
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
|
||||
"The principal of data: document should be a NullPrincipal.");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
expectAttrs.firstPartyDomain,
|
||||
"data: URI should have firstPartyDomain set");
|
||||
});
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
/**
|
||||
* data: document contains an iframe, and we test that iframe should inherit
|
||||
* origin attributes from the data: document.
|
||||
*/
|
||||
add_task(function* test_remote_window_open_data_uri2() {
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow({ remote: true });
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
||||
// The iframe test2.html will fetch test2.js, which will have cookies.
|
||||
const DATA_URI = `data:text/html,
|
||||
<iframe id="iframe1" src="http://mochi.test:8888/browser/browser/components/originattributes/test/browser/test2.html"></iframe>`;
|
||||
browser.loadURI(DATA_URI);
|
||||
yield BrowserTestUtils.browserLoaded(browser, true);
|
||||
|
||||
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
|
||||
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
|
||||
info("origin " + content.document.nodePrincipal.origin);
|
||||
|
||||
let iframe = content.document.getElementById("iframe1");
|
||||
info("iframe principal: " + iframe.contentDocument.nodePrincipal.origin);
|
||||
|
||||
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
|
||||
"The principal of data: document should be a NullPrincipal.");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
expectAttrs.firstPartyDomain,
|
||||
"data: URI should have firstPartyDomain set");
|
||||
|
||||
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
expectAttrs.firstPartyDomain,
|
||||
"iframe should inherit firstPartyDomain from parent document.");
|
||||
Assert.equal(iframe.contentDocument.cookie, "test2=foo", "iframe should have cookies");
|
||||
});
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
/**
|
||||
* about: pages should have firstPartyDomain set when we enable first party isolation.
|
||||
*/
|
||||
add_task(function* test_aboutURL() {
|
||||
let aboutURLs = [];
|
||||
|
||||
// List of about: URLs that will initiate network requests.
|
||||
let networkURLs = [
|
||||
"credits",
|
||||
];
|
||||
|
||||
let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
for (let cid in Cc) {
|
||||
let result = cid.match(/@mozilla.org\/network\/protocol\/about;1\?what\=(.*)$/);
|
||||
if (!result) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let aboutType = result[1];
|
||||
let contract = "@mozilla.org/network/protocol/about;1?what=" + aboutType;
|
||||
try {
|
||||
let am = Cc[contract].getService(Ci.nsIAboutModule);
|
||||
let uri = ios.newURI("about:" + aboutType);
|
||||
let flags = am.getURIFlags(uri);
|
||||
|
||||
// We load pages with URI_SAFE_FOR_UNTRUSTED_CONTENT set, this means they
|
||||
// are not loaded with System Principal but with codebase principal.
|
||||
// Also we skip pages with HIDE_FROM_ABOUTABOUT, some of them may have
|
||||
// errors while loading.
|
||||
if ((flags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) &&
|
||||
!(flags & Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT) &&
|
||||
networkURLs.indexOf(aboutType) == -1) {
|
||||
aboutURLs.push(aboutType);
|
||||
}
|
||||
} catch (e) {
|
||||
// getService might have thrown if the component doesn't actually
|
||||
// implement nsIAboutModule
|
||||
}
|
||||
}
|
||||
|
||||
for (let url of aboutURLs) {
|
||||
let tab = gBrowser.addTab("about:" + url);
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
let attrs = { firstPartyDomain: "about.ef2a7dd5-93bc-417f-a698-142c3116864f.mozilla" };
|
||||
yield ContentTask.spawn(tab.linkedBrowser, { attrs, url }, function* (args) {
|
||||
info("loading page about:" + args.url + ", origin is " + content.document.nodePrincipal.origin);
|
||||
info("principal " + content.document.nodePrincipal);
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
args.attrs.firstPartyDomain, "The about page should have firstPartyDomain set");
|
||||
Assert.ok(content.document.nodePrincipal.isCodebasePrincipal,
|
||||
"The principal should be a codebase principal.");
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
});
|
@ -0,0 +1,65 @@
|
||||
add_task(function* setup() {
|
||||
Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("privacy.firstparty.isolate");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_remote_window_open_js_uri() {
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow({ remote: true });
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
||||
Assert.ok(browser.isRemoteBrowser, "should be a remote browser");
|
||||
|
||||
browser.loadURI(`javascript:1;`);
|
||||
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
|
||||
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
|
||||
info("origin " + content.document.nodePrincipal.origin);
|
||||
|
||||
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
|
||||
"The principal of remote javascript: should be a NullPrincipal.");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
expectAttrs.firstPartyDomain,
|
||||
"remote javascript: should have firstPartyDomain set");
|
||||
});
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
add_task(function* test_remote_window_open_js_uri2() {
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow({ remote: true });
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
||||
Assert.ok(browser.isRemoteBrowser, "should be a remote browser");
|
||||
|
||||
browser.loadURI(`javascript:
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.src = "http://example.com";
|
||||
iframe.id = "iframe1";
|
||||
document.body.appendChild(iframe);
|
||||
alert("connect to http://example.com");
|
||||
`);
|
||||
|
||||
yield BrowserTestUtils.browserLoaded(browser, true, function(url) {
|
||||
info("URL:" + url);
|
||||
return url == "http://example.com/";
|
||||
});
|
||||
|
||||
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
|
||||
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
|
||||
info("origin " + content.document.nodePrincipal.origin);
|
||||
|
||||
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
|
||||
"The principal of remote javascript: should be a NullPrincipal.");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
expectAttrs.firstPartyDomain,
|
||||
"remote javascript: should have firstPartyDomain set");
|
||||
|
||||
let iframe = content.document.getElementById("iframe1");
|
||||
info("iframe principal: " + iframe.contentDocument.nodePrincipal.origin);
|
||||
});
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
@ -3553,7 +3553,9 @@ var SessionStoreInternal = {
|
||||
|
||||
// Update the persistent tab state cache with |tabData| information.
|
||||
TabStateCache.update(browser, {
|
||||
history: {entries: tabData.entries, index: tabData.index},
|
||||
// NOTE: Copy the entries array shallowly, so as to not screw with the
|
||||
// original tabData's history when getting history updates.
|
||||
history: {entries: [...tabData.entries], index: tabData.index},
|
||||
scroll: tabData.scroll || null,
|
||||
storage: tabData.storage || null,
|
||||
formdata: tabData.formdata || null,
|
||||
|
@ -178,7 +178,10 @@ var TabStateInternal = {
|
||||
}
|
||||
|
||||
if (key === "history") {
|
||||
tabData.entries = value.entries;
|
||||
// Make a shallow copy of the entries array. We (currently) don't update
|
||||
// entries in place, so we don't have to worry about performing a deep
|
||||
// copy.
|
||||
tabData.entries = [...value.entries];
|
||||
|
||||
if (value.hasOwnProperty("userContextId")) {
|
||||
tabData.userContextId = value.userContextId;
|
||||
|
@ -243,3 +243,4 @@ skip-if = !e10s # GroupedSHistory is e10s-only
|
||||
|
||||
[browser_closed_objects_changed_notifications_tabs.js]
|
||||
[browser_closed_objects_changed_notifications_windows.js]
|
||||
[browser_duplicate_history.js]
|
||||
|
@ -0,0 +1,22 @@
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
|
||||
"resource:///modules/sessionstore/SessionStore.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "TabStateCache",
|
||||
"resource:///modules/sessionstore/TabStateCache.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "TabStateFlusher",
|
||||
"resource:///modules/sessionstore/TabStateFlusher.jsm");
|
||||
|
||||
add_task(function* () {
|
||||
yield BrowserTestUtils.withNewTab("http://example.com", function* (aBrowser) {
|
||||
let tab = gBrowser.getTabForBrowser(aBrowser);
|
||||
yield TabStateFlusher.flush(aBrowser);
|
||||
let before = TabStateCache.get(aBrowser);
|
||||
|
||||
let newTab = SessionStore.duplicateTab(window, tab);
|
||||
yield BrowserTestUtils.browserLoaded(newTab.linkedBrowser);
|
||||
let after = TabStateCache.get(newTab.linkedBrowser);
|
||||
|
||||
isnot(before.history.entries, after.history.entries,
|
||||
"The entry objects should not be shared");
|
||||
yield BrowserTestUtils.removeTab(newTab);
|
||||
});
|
||||
});
|
27
browser/extensions/mortar/host/pdf/bootstrap.js
vendored
27
browser/extensions/mortar/host/pdf/bootstrap.js
vendored
@ -6,15 +6,27 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const messageGenerateRandomBytes = "ppapi.js:generateRandomBytes";
|
||||
const handlerURI = "chrome://ppapipdf.js/content/viewer.html";
|
||||
const prefPdfiumEnable = "pdfium.enabled";
|
||||
|
||||
function sandboxScript(sandbox)
|
||||
{
|
||||
dump("sandboxScript " + sandbox.pluginElement + "\n");
|
||||
Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader).loadSubScript("resource://ppapipdf.js/ppapi-content-sandbox.js", sandbox);
|
||||
}
|
||||
|
||||
const handlerURI = "chrome://ppapipdf.js/content/viewer.html";
|
||||
function prefObserver(aSubject, aTopic, aData) {
|
||||
if (Services.prefs.getBoolPref(prefPdfiumEnable)) {
|
||||
pdfium.init();
|
||||
} else {
|
||||
pdfium.uninit();
|
||||
}
|
||||
}
|
||||
|
||||
let bootstrapData;
|
||||
let pdfium = {
|
||||
init(bootstrapData) {
|
||||
init() {
|
||||
let root = bootstrapData.installPath.parent.parent;
|
||||
let rpclib = root.clone();
|
||||
let pluginlib = root.clone();
|
||||
@ -54,12 +66,10 @@ let pdfium = {
|
||||
ppapiProcessArgs: [ rpclib, pluginlib ],
|
||||
});
|
||||
plugin.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
|
||||
Services.ppmm.addMessageListener("ppapi.js:generateRandomBytes", this.generateRandomBytesListener);
|
||||
},
|
||||
uninit() {
|
||||
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
pluginHost.unregisterFakePlugin(handlerURI);
|
||||
Services.ppmm.removeMessageListener("ppapi.js:generateRandomBytes", this.generateRandomBytesListener);
|
||||
},
|
||||
generateRandomBytesListener(data) {
|
||||
let rng = Cc["@mozilla.org/security/random-generator;1"].createInstance(Ci.nsIRandomGenerator);
|
||||
@ -69,10 +79,17 @@ let pdfium = {
|
||||
|
||||
function startup(aData) {
|
||||
dump(">>>STARTED!!!\n");
|
||||
pdfium.init(aData);
|
||||
bootstrapData = aData;
|
||||
if (Services.prefs.getBoolPref(prefPdfiumEnable)) {
|
||||
pdfium.init();
|
||||
}
|
||||
Services.prefs.addObserver(prefPdfiumEnable, prefObserver, false);
|
||||
Services.ppmm.addMessageListener(messageGenerateRandomBytes, pdfium.generateRandomBytesListener);
|
||||
dump("<<<STARTED!!!\n");
|
||||
}
|
||||
function shutdown() {
|
||||
dump("SHUTDOWN!!!\n");
|
||||
pdfium.uninit();
|
||||
Services.prefs.removeObserver(prefPdfiumEnable, prefObserver);
|
||||
Services.ppmm.removeMessageListener(messageGenerateRandomBytes, pdfium.generateRandomBytesListener);
|
||||
}
|
||||
|
@ -56,20 +56,44 @@ OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
|
||||
{
|
||||
bool isFirstPartyEnabled = IsFirstPartyEnabled();
|
||||
|
||||
// When the pref is on, we also compute the firstPartyDomain attribute
|
||||
// if this is for top-level document.
|
||||
if (isFirstPartyEnabled && aIsTopLevelDocument) {
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(tldService);
|
||||
if (!tldService) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString baseDomain;
|
||||
tldService->GetBaseDomain(aURI, 0, baseDomain);
|
||||
mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
|
||||
// If the pref is off or this is not a top level load, bail out.
|
||||
if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(tldService);
|
||||
if (!tldService) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString baseDomain;
|
||||
nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsAutoCString scheme;
|
||||
rv = aURI->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (scheme.EqualsLiteral("about")) {
|
||||
baseDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN);
|
||||
}
|
||||
}
|
||||
|
||||
mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
|
||||
}
|
||||
|
||||
void
|
||||
OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
|
||||
const nsACString& aDomain)
|
||||
{
|
||||
bool isFirstPartyEnabled = IsFirstPartyEnabled();
|
||||
|
||||
// If the pref is off or this is not a top level load, bail out.
|
||||
if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFirstPartyDomain = NS_ConvertUTF8toUTF16(aDomain);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
{}
|
||||
|
||||
void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI);
|
||||
void SetFirstPartyDomain(const bool aIsTopLevelDocument, const nsACString& aDomain);
|
||||
|
||||
enum {
|
||||
STRIP_FIRST_PARTY_DOMAIN = 0x01,
|
||||
|
@ -46,11 +46,13 @@ nsNullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom)
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<nsNullPrincipal>
|
||||
nsNullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell)
|
||||
nsNullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty)
|
||||
{
|
||||
OriginAttributes attrs = nsDocShell::Cast(aDocShell)->GetOriginAttributes();
|
||||
attrs.SetFirstPartyDomain(aIsFirstParty, NS_LITERAL_CSTRING(NULL_PRINCIPAL_FIRST_PARTY_DOMAIN));
|
||||
|
||||
RefPtr<nsNullPrincipal> nullPrin = new nsNullPrincipal();
|
||||
nsresult rv =
|
||||
nullPrin->Init(nsDocShell::Cast(aDocShell)->GetOriginAttributes());
|
||||
nsresult rv = nullPrin->Init(attrs);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
return nullPrin.forget();
|
||||
}
|
||||
|
@ -54,7 +54,11 @@ public:
|
||||
|
||||
static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom);
|
||||
|
||||
static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIDocShell* aDocShell);
|
||||
// Create NullPrincipal with origin attributes from docshell.
|
||||
// If aIsFirstParty is true, and the pref 'privacy.firstparty.isolate' is also
|
||||
// enabled, the mFirstPartyDomain value of the origin attributes will be set
|
||||
// to NULL_PRINCIPAL_FIRST_PARTY_DOMAIN.
|
||||
static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty = false);
|
||||
|
||||
static already_AddRefed<nsNullPrincipal>
|
||||
Create(const mozilla::OriginAttributes& aOriginAttributes = mozilla::OriginAttributes(),
|
||||
|
BIN
config/external/icu/data/icudt58l.dat
vendored
BIN
config/external/icu/data/icudt58l.dat
vendored
Binary file not shown.
@ -231,6 +231,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
||||
[browser_rules_strict-search-filter_02.js]
|
||||
[browser_rules_strict-search-filter_03.js]
|
||||
[browser_rules_style-editor-link.js]
|
||||
[browser_rules_url-click-opens-new-tab.js]
|
||||
[browser_rules_urls-clickable.js]
|
||||
[browser_rules_user-agent-styles.js]
|
||||
[browser_rules_user-agent-styles-uneditable.js]
|
||||
|
@ -0,0 +1,29 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Bug 1326626 - Tests that clicking a background url opens a new tab
|
||||
// even when the devtools is opened in a separate window.
|
||||
|
||||
const TEST_URL = "data:text/html,<style>body{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGD4DwABBAEAfbLI3wAAAABJRU5ErkJggg==) no-repeat}";
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL(TEST_URL, "window");
|
||||
let view = selectRuleView(inspector);
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
|
||||
let anchor = view.styleDocument.querySelector(".ruleview-propertyvaluecontainer a");
|
||||
ok(anchor, "Link exists for style tag node");
|
||||
|
||||
let onTabOpened = waitForTab();
|
||||
anchor.click();
|
||||
|
||||
info("Wait for the image to open in a new tab");
|
||||
let tab = yield onTabOpened;
|
||||
ok(tab, "A new tab opened");
|
||||
|
||||
is(tab.linkedBrowser.currentURI.spec, anchor.href, "The new tab has the expected URL");
|
||||
});
|
@ -280,7 +280,8 @@ TextPropertyEditor.prototype = {
|
||||
if (target.nodeName === "a") {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.browserWindow.openUILinkIn(target.href, "tab");
|
||||
let browserWin = this.ruleView.inspector.target.tab.ownerDocument.defaultView;
|
||||
browserWin.openUILinkIn(target.href, "tab");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -104,8 +104,6 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
||||
[browser_inspector_highlighter-measure_02.js]
|
||||
[browser_inspector_highlighter-options.js]
|
||||
[browser_inspector_highlighter-preview.js]
|
||||
[browser_inspector_highlighter-rect_01.js]
|
||||
[browser_inspector_highlighter-rect_02.js]
|
||||
[browser_inspector_highlighter-rulers_01.js]
|
||||
[browser_inspector_highlighter-rulers_02.js]
|
||||
[browser_inspector_highlighter-selector_01.js]
|
||||
|
@ -1,121 +0,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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the custom rect highlighter provides the right API, ensures that
|
||||
// the input is valid and that it does create a box with the right dimensions,
|
||||
// at the right position.
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,Rect Highlighter Test";
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
|
||||
let front = inspector.inspector;
|
||||
let highlighter = yield front.getHighlighterByType("RectHighlighter");
|
||||
let body = yield getNodeFront("body", inspector);
|
||||
|
||||
info("Make sure the highlighter returned is correct");
|
||||
|
||||
ok(highlighter, "The RectHighlighter custom type was created");
|
||||
is(highlighter.typeName, "customhighlighter",
|
||||
"The RectHighlighter has the right type");
|
||||
ok(highlighter.show && highlighter.hide,
|
||||
"The RectHighlighter has the expected show/hide methods");
|
||||
|
||||
info("Check that the highlighter is hidden by default");
|
||||
|
||||
let hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
is(hidden, "true", "The highlighter is hidden by default");
|
||||
|
||||
info("Check that nothing is shown if no rect is passed");
|
||||
|
||||
yield highlighter.show(body);
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
is(hidden, "true", "The highlighter is hidden when no rect is passed");
|
||||
|
||||
info("Check that nothing is shown if rect is incomplete or invalid");
|
||||
|
||||
yield highlighter.show(body, {
|
||||
rect: {x: 0, y: 0}
|
||||
});
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
is(hidden, "true", "The highlighter is hidden when the rect is incomplete");
|
||||
|
||||
yield highlighter.show(body, {
|
||||
rect: {x: 0, y: 0, width: -Infinity, height: 0}
|
||||
});
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
is(hidden, "true", "The highlighter is hidden when the rect is invalid (1)");
|
||||
|
||||
yield highlighter.show(body, {
|
||||
rect: {x: 0, y: 0, width: 5, height: -45}
|
||||
});
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
is(hidden, "true", "The highlighter is hidden when the rect is invalid (2)");
|
||||
|
||||
yield highlighter.show(body, {
|
||||
rect: {x: "test", y: 0, width: 5, height: 5}
|
||||
});
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
is(hidden, "true", "The highlighter is hidden when the rect is invalid (3)");
|
||||
|
||||
info("Check that the highlighter is displayed when valid options are passed");
|
||||
|
||||
yield highlighter.show(body, {
|
||||
rect: {x: 5, y: 5, width: 50, height: 50}
|
||||
});
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
ok(!hidden, "The highlighter is displayed");
|
||||
let style = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "style", highlighter);
|
||||
is(style, "left:5px;top:5px;width:50px;height:50px;",
|
||||
"The highlighter is positioned correctly");
|
||||
|
||||
info("Check that the highlighter can be displayed at x=0 y=0");
|
||||
|
||||
yield highlighter.show(body, {
|
||||
rect: {x: 0, y: 0, width: 50, height: 50}
|
||||
});
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
ok(!hidden, "The highlighter is displayed when x=0 and y=0");
|
||||
style = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "style", highlighter);
|
||||
is(style, "left:0px;top:0px;width:50px;height:50px;",
|
||||
"The highlighter is positioned correctly");
|
||||
|
||||
info("Check that the highlighter is hidden when dimensions are 0");
|
||||
|
||||
yield highlighter.show(body, {
|
||||
rect: {x: 0, y: 0, width: 0, height: 0}
|
||||
});
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
is(hidden, "true", "The highlighter is hidden width and height are 0");
|
||||
|
||||
info("Check that a fill color can be passed");
|
||||
|
||||
yield highlighter.show(body, {
|
||||
rect: {x: 100, y: 200, width: 500, height: 200},
|
||||
fill: "red"
|
||||
});
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "hidden", highlighter);
|
||||
ok(!hidden, "The highlighter is displayed");
|
||||
style = yield testActor.getHighlighterNodeAttribute(
|
||||
"highlighted-rect", "style", highlighter);
|
||||
is(style, "left:100px;top:200px;width:500px;height:200px;background:red;",
|
||||
"The highlighter has the right background color");
|
||||
|
||||
yield highlighter.hide();
|
||||
yield highlighter.finalize();
|
||||
});
|
@ -1,37 +0,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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the custom rect highlighter positions the rectangle relative to the
|
||||
// viewport of the context node we pass to it.
|
||||
|
||||
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_rect.html";
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
|
||||
let front = inspector.inspector;
|
||||
let highlighter = yield front.getHighlighterByType("RectHighlighter");
|
||||
|
||||
info("Showing the rect highlighter in the context of the iframe");
|
||||
|
||||
// Get the reference to a context node inside the iframe
|
||||
let childBody = yield getNodeFrontInFrame("body", "iframe", inspector);
|
||||
yield highlighter.show(childBody, {
|
||||
rect: {x: 50, y: 50, width: 100, height: 100}
|
||||
});
|
||||
|
||||
let style = yield testActor.getHighlighterNodeAttribute("highlighted-rect",
|
||||
"style", highlighter);
|
||||
|
||||
// The parent body has margin=50px and border=10px
|
||||
// The parent iframe also has margin=50px and border=10px
|
||||
// = 50 + 10 + 50 + 10 = 120px
|
||||
// The rect is aat x=50 and y=50, so left and top should be 170px
|
||||
is(style, "left:170px;top:170px;width:100px;height:100px;",
|
||||
"The highlighter is correctly positioned");
|
||||
|
||||
yield highlighter.hide();
|
||||
yield highlighter.finalize();
|
||||
});
|
@ -30,7 +30,17 @@
|
||||
* 6. When your tool is closed call:
|
||||
* this._telemetry.toolClosed("mytoolname");
|
||||
*
|
||||
* Note:
|
||||
* Note 1:
|
||||
* Most of the top level panels already have toolOpened called for them by
|
||||
* the toolbox tab code. If you add a new tool, you probably won't need to
|
||||
* follow steps 3 to 6 as they're done for you already (look at onClick
|
||||
* handler in devtools/client/framework/components/toolbox-tab.js).
|
||||
*
|
||||
* You will still need to call toolOpened for "subpanels" such as the rules,
|
||||
* computed, and animations inspectors inside the HTML inspector tool, as these
|
||||
* are not called automatically by the code that renders their tabs.
|
||||
*
|
||||
* Note 2:
|
||||
* You can view telemetry stats for your local Firefox instance via
|
||||
* about:telemetry.
|
||||
*
|
||||
@ -135,6 +145,10 @@ Telemetry.prototype = {
|
||||
histogram: "DEVTOOLS_STORAGE_OPENED_COUNT",
|
||||
timerHistogram: "DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
dom: {
|
||||
histogram: "DEVTOOLS_DOM_OPENED_COUNT",
|
||||
timerHistogram: "DEVTOOLS_DOM_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
paintflashing: {
|
||||
histogram: "DEVTOOLS_PAINTFLASHING_OPENED_COUNT",
|
||||
timerHistogram: "DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS"
|
||||
@ -344,3 +358,4 @@ Telemetry.prototype = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -32,7 +32,7 @@ exports.CssPropertiesActor = ActorClassWithSpec(cssPropertiesSpec, {
|
||||
const pseudoElements = DOMUtils.getCSSPseudoElementNames();
|
||||
const supportedFeature = {
|
||||
// checking for css-color-4 color function support.
|
||||
"css-color-4-color-function": DOMUtils.isValidCSSColor("rgb(1 1 1 / 100%"),
|
||||
"css-color-4-color-function": DOMUtils.isValidCSSColor("rgb(1 1 1 / 100%)"),
|
||||
};
|
||||
|
||||
return { properties, pseudoElements, supportedFeature };
|
||||
|
@ -486,9 +486,8 @@ exports.CustomHighlighterActor = protocol.ActorClassWithSpec(customHighlighterSp
|
||||
* NodeActor argument (NodeActor as in
|
||||
* devtools/server/actor/inspector).
|
||||
* Note however that some highlighters use this argument merely as a context
|
||||
* node: the RectHighlighter for instance uses it to calculate the absolute
|
||||
* position of the provided rect. The SelectHighlighter uses it as a base node
|
||||
* to run the provided CSS selector on.
|
||||
* node: The SelectHighlighter for instance uses it as a base node to run the
|
||||
* provided CSS selector on.
|
||||
*
|
||||
* @param {NodeActor} The node to be highlighted
|
||||
* @param {Object} Options for the custom highlighter
|
||||
@ -711,10 +710,6 @@ const { SelectorHighlighter } = require("./highlighters/selector");
|
||||
register(SelectorHighlighter);
|
||||
exports.SelectorHighlighter = SelectorHighlighter;
|
||||
|
||||
const { RectHighlighter } = require("./highlighters/rect");
|
||||
register(RectHighlighter);
|
||||
exports.RectHighlighter = RectHighlighter;
|
||||
|
||||
const { GeometryEditorHighlighter } = require("./highlighters/geometry-editor");
|
||||
register(GeometryEditorHighlighter);
|
||||
exports.GeometryEditorHighlighter = GeometryEditorHighlighter;
|
||||
|
@ -16,7 +16,6 @@ DevToolsModules(
|
||||
'eye-dropper.js',
|
||||
'geometry-editor.js',
|
||||
'measuring-tool.js',
|
||||
'rect.js',
|
||||
'rulers.js',
|
||||
'selector.js',
|
||||
'simple-outline.js'
|
||||
|
@ -1,102 +0,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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { CanvasFrameAnonymousContentHelper } = require("./utils/markup");
|
||||
const { getAdjustedQuads } = require("devtools/shared/layout/utils");
|
||||
/**
|
||||
* The RectHighlighter is a class that draws a rectangle highlighter at specific
|
||||
* coordinates.
|
||||
* It does *not* highlight DOM nodes, but rects.
|
||||
* It also does *not* update dynamically, it only highlights a rect and remains
|
||||
* there as long as it is shown.
|
||||
*/
|
||||
function RectHighlighter(highlighterEnv) {
|
||||
this.win = highlighterEnv.window;
|
||||
this.markup = new CanvasFrameAnonymousContentHelper(highlighterEnv,
|
||||
this._buildMarkup.bind(this));
|
||||
}
|
||||
|
||||
RectHighlighter.prototype = {
|
||||
typeName: "RectHighlighter",
|
||||
|
||||
_buildMarkup: function () {
|
||||
let doc = this.win.document;
|
||||
|
||||
let container = doc.createElement("div");
|
||||
container.className = "highlighter-container";
|
||||
container.innerHTML = "<div id=\"highlighted-rect\" " +
|
||||
"class=\"highlighted-rect\" hidden=\"true\">";
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.win = null;
|
||||
this.markup.destroy();
|
||||
},
|
||||
|
||||
getElement: function (id) {
|
||||
return this.markup.getElement(id);
|
||||
},
|
||||
|
||||
_hasValidOptions: function (options) {
|
||||
let isValidNb = n => typeof n === "number" && n >= 0 && isFinite(n);
|
||||
return options && options.rect &&
|
||||
isValidNb(options.rect.x) &&
|
||||
isValidNb(options.rect.y) &&
|
||||
options.rect.width && isValidNb(options.rect.width) &&
|
||||
options.rect.height && isValidNb(options.rect.height);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {DOMNode} node The highlighter rect is relatively positioned to the
|
||||
* viewport this node is in. Using the provided node, the highligther will get
|
||||
* the parent documentElement and use it as context to position the
|
||||
* highlighter correctly.
|
||||
* @param {Object} options Accepts the following options:
|
||||
* - rect: mandatory object that should have the x, y, width, height
|
||||
* properties
|
||||
* - fill: optional fill color for the rect
|
||||
*/
|
||||
show: function (node, options) {
|
||||
if (!this._hasValidOptions(options) || !node || !node.ownerDocument) {
|
||||
this.hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
let contextNode = node.ownerDocument.documentElement;
|
||||
|
||||
// Caculate the absolute rect based on the context node's adjusted quads.
|
||||
let quads = getAdjustedQuads(this.win, contextNode);
|
||||
if (!quads.length) {
|
||||
this.hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
let {bounds} = quads[0];
|
||||
let x = "left:" + (bounds.x + options.rect.x) + "px;";
|
||||
let y = "top:" + (bounds.y + options.rect.y) + "px;";
|
||||
let width = "width:" + options.rect.width + "px;";
|
||||
let height = "height:" + options.rect.height + "px;";
|
||||
|
||||
let style = x + y + width + height;
|
||||
if (options.fill) {
|
||||
style += "background:" + options.fill + ";";
|
||||
}
|
||||
|
||||
// Set the coordinates of the highlighter and show it
|
||||
let rect = this.getElement("highlighted-rect");
|
||||
rect.setAttribute("style", style);
|
||||
rect.removeAttribute("hidden");
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
this.getElement("highlighted-rect").setAttribute("hidden", "true");
|
||||
}
|
||||
};
|
||||
exports.RectHighlighter = RectHighlighter;
|
@ -141,8 +141,9 @@ function recursiveWalk(breakdown, edge, report, visitor) {
|
||||
visitor.exit(breakdown, report, edge);
|
||||
} else {
|
||||
visitor.enter(breakdown, report, edge);
|
||||
for (let { edge, referent, breakdown: subBreakdown } of getReportEdges(breakdown, report)) {
|
||||
recursiveWalk(subBreakdown, edge, referent, visitor);
|
||||
for (let { edge: ed, referent, breakdown: subBreakdown }
|
||||
of getReportEdges(breakdown, report)) {
|
||||
recursiveWalk(subBreakdown, ed, referent, visitor);
|
||||
}
|
||||
visitor.exit(breakdown, report, edge);
|
||||
}
|
||||
@ -236,8 +237,6 @@ DiffVisitor.prototype._set = function (report, edge, val) {
|
||||
* @overrides Visitor.prototype.enter
|
||||
*/
|
||||
DiffVisitor.prototype.enter = function (breakdown, report, edge) {
|
||||
const isFirstTimeEntering = this._results === null;
|
||||
|
||||
const newResults = breakdown.by === "allocationStack" ? new Map() : {};
|
||||
let newOther;
|
||||
|
||||
@ -274,8 +273,8 @@ DiffVisitor.prototype.exit = function (breakdown, report, edge) {
|
||||
.map(e => e.edge)
|
||||
.filter(e => !visited.has(e));
|
||||
const results = this._resultsStack[this._resultsStack.length - 1];
|
||||
for (let edge of unvisited) {
|
||||
this._set(results, edge, this._get(other, edge));
|
||||
for (let edg of unvisited) {
|
||||
this._set(results, edg, this._get(other, edg));
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,9 +375,7 @@ exports.diff = diff;
|
||||
*
|
||||
* @return {Object<number, TreeNode>}
|
||||
*/
|
||||
const createParentMap = exports.createParentMap = function (node,
|
||||
getId = node => node.id,
|
||||
aggregator = Object.create(null)) {
|
||||
const createParentMap = function (node, getId = n => n.id, aggregator = {}) {
|
||||
if (node.children) {
|
||||
for (let i = 0, length = node.children.length; i < length; i++) {
|
||||
const child = node.children[i];
|
||||
@ -386,9 +383,9 @@ const createParentMap = exports.createParentMap = function (node,
|
||||
createParentMap(child, getId, aggregator);
|
||||
}
|
||||
}
|
||||
|
||||
return aggregator;
|
||||
};
|
||||
exports.createParentMap = createParentMap;
|
||||
|
||||
const BUCKET = Object.freeze({ by: "bucket" });
|
||||
|
||||
|
@ -237,7 +237,7 @@ DominatorTreeNode.partialTraversal = function (dominatorTree,
|
||||
*
|
||||
* @returns {DominatorTreeNode}
|
||||
*/
|
||||
DominatorTreeNode.insert = function (tree, path, newChildren, moreChildrenAvailable) {
|
||||
DominatorTreeNode.insert = function (nodeTree, path, newChildren, moreChildrenAvailable) {
|
||||
function insert(tree, i) {
|
||||
if (tree.nodeId !== path[i]) {
|
||||
return tree;
|
||||
@ -257,7 +257,7 @@ DominatorTreeNode.insert = function (tree, path, newChildren, moreChildrenAvaila
|
||||
: tree;
|
||||
}
|
||||
|
||||
return insert(tree, 0);
|
||||
return insert(nodeTree, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,8 @@
|
||||
// HeapAnalysesWorker is owned and communicated with by a HeapAnalysesClient
|
||||
// instance. See HeapAnalysesClient.js.
|
||||
|
||||
/* global importScripts, workerHelper, self */
|
||||
|
||||
"use strict";
|
||||
|
||||
importScripts("resource://gre/modules/workers/require.js");
|
||||
@ -70,7 +72,8 @@ workerHelper.createTask(self, "deleteHeapSnapshot", ({ snapshotFilePath }) => {
|
||||
/**
|
||||
* @see HeapAnalysesClient.prototype.takeCensus
|
||||
*/
|
||||
workerHelper.createTask(self, "takeCensus", ({ snapshotFilePath, censusOptions, requestOptions }) => {
|
||||
workerHelper.createTask(self, "takeCensus", (
|
||||
{ snapshotFilePath, censusOptions, requestOptions }) => {
|
||||
if (!snapshots[snapshotFilePath]) {
|
||||
throw new Error(`No known heap snapshot for '${snapshotFilePath}'`);
|
||||
}
|
||||
@ -206,7 +209,7 @@ workerHelper.createTask(self, "getDominatorTree", request => {
|
||||
maxRetainingPaths,
|
||||
} = request;
|
||||
|
||||
if (!(0 <= dominatorTreeId && dominatorTreeId < dominatorTrees.length)) {
|
||||
if (!(dominatorTreeId >= 0 && dominatorTreeId < dominatorTrees.length)) {
|
||||
throw new Error(
|
||||
`There does not exist a DominatorTree with the id ${dominatorTreeId}`);
|
||||
}
|
||||
@ -252,7 +255,7 @@ workerHelper.createTask(self, "getImmediatelyDominated", request => {
|
||||
maxRetainingPaths,
|
||||
} = request;
|
||||
|
||||
if (!(0 <= dominatorTreeId && dominatorTreeId < dominatorTrees.length)) {
|
||||
if (!(dominatorTreeId >= 0 && dominatorTreeId < dominatorTrees.length)) {
|
||||
throw new Error(
|
||||
`There does not exist a DominatorTree with the id ${dominatorTreeId}`);
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ CensusTreeNodeCacheValue.prototype = null;
|
||||
* The unique string that can be used as a key in a CensusTreeNodeCache.
|
||||
*/
|
||||
CensusTreeNodeCache.hashFrame = function (frame) {
|
||||
// eslint-disable-next-line max-len
|
||||
return `FRAME,${frame.functionDisplayName},${frame.source},${frame.line},${frame.column},${frame.asyncCause}`;
|
||||
};
|
||||
|
||||
|
@ -48,6 +48,7 @@ exports.deduplicatePaths = function (target, paths) {
|
||||
nameSet.add(name);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-labels
|
||||
outer: for (let path of paths) {
|
||||
const pathLength = path.length;
|
||||
|
||||
@ -57,6 +58,7 @@ exports.deduplicatePaths = function (target, paths) {
|
||||
predecessorsSeen.add(target);
|
||||
for (let i = 0; i < pathLength; i++) {
|
||||
if (predecessorsSeen.has(path[i].predecessor)) {
|
||||
// eslint-disable-next-line no-labels
|
||||
continue outer;
|
||||
}
|
||||
predecessorsSeen.add(path[i].predecessor);
|
||||
|
10
devtools/shared/heapsnapshot/tests/mochitest/.eslintrc.js
Normal file
10
devtools/shared/heapsnapshot/tests/mochitest/.eslintrc.js
Normal file
@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
// Extend from the shared list of defined globals for mochitests.
|
||||
"extends": "../../../../.eslintrc.mochitests.js",
|
||||
"globals": {
|
||||
"ChromeUtils": true,
|
||||
"sendAsyncMessage": true,
|
||||
}
|
||||
};
|
@ -12,8 +12,11 @@ Sanity test that we can compute dominator trees from a heap snapshot in a web wi
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script>
|
||||
"use strict";
|
||||
/* global window, ChromeUtils, DominatorTree */
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.onload = function() {
|
||||
window.onload = function () {
|
||||
const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
|
||||
const snapshot = ChromeUtils.readHeapSnapshot(path);
|
||||
|
||||
|
@ -12,8 +12,10 @@ Bug 1024774 - Sanity test that we can take a heap snapshot in a web window.
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.onload = function() {
|
||||
window.onload = function () {
|
||||
ok(ChromeUtils, "The ChromeUtils interface should be exposed in chrome windows.");
|
||||
ChromeUtils.saveHeapSnapshot({ runtime: true });
|
||||
ok(true, "Should save a heap snapshot and shouldn't throw.");
|
||||
|
@ -12,70 +12,70 @@ Bug 1201597 - Sanity test that we can take a heap snapshot in an e10s child proc
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
window.onerror = function (msg, url, line, col, err) {
|
||||
ok(false, "@" + url + ":" + line + ":" + col + ": " + msg + "\n" + err.stack);
|
||||
};
|
||||
"use strict";
|
||||
window.onerror = function (msg, url, line, col, err) {
|
||||
ok(false, "@" + url + ":" + line + ":" + col + ": " + msg + "\n" + err.stack);
|
||||
};
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var childFrameURL = "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
|
||||
var childFrameURL = "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
|
||||
|
||||
// This function is stringified and loaded in the child process as a frame
|
||||
// script.
|
||||
function childFrameScript() {
|
||||
try {
|
||||
ChromeUtils.saveHeapSnapshot({ runtime: true });
|
||||
} catch (err) {
|
||||
sendAsyncMessage("testSaveHeapSnapshot:error",
|
||||
{ error: err.toString() });
|
||||
return;
|
||||
}
|
||||
// This function is stringified and loaded in the child process as a frame
|
||||
// script.
|
||||
function childFrameScript() {
|
||||
try {
|
||||
ChromeUtils.saveHeapSnapshot({ runtime: true });
|
||||
} catch (err) {
|
||||
sendAsyncMessage("testSaveHeapSnapshot:error",
|
||||
{ error: err.toString() });
|
||||
return;
|
||||
}
|
||||
|
||||
sendAsyncMessage("testSaveHeapSnapshot:done", {});
|
||||
}
|
||||
sendAsyncMessage("testSaveHeapSnapshot:done", {});
|
||||
}
|
||||
|
||||
// Kick everything off on load.
|
||||
window.onload = function () {
|
||||
info("window.onload fired");
|
||||
SpecialPowers.addPermission("browser", true, document);
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, function () {
|
||||
var iframe = document.createElement("iframe");
|
||||
SpecialPowers.wrap(iframe).mozbrowser = true;
|
||||
iframe.id = "iframe";
|
||||
iframe.src = childFrameURL;
|
||||
// Kick everything off on load.
|
||||
window.onload = function () {
|
||||
info("window.onload fired");
|
||||
SpecialPowers.addPermission("browser", true, document);
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, function () {
|
||||
let iframe = document.createElement("iframe");
|
||||
SpecialPowers.wrap(iframe).mozbrowser = true;
|
||||
iframe.id = "iframe";
|
||||
iframe.src = childFrameURL;
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", function () {
|
||||
info("iframe done loading");
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", function () {
|
||||
info("iframe done loading");
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
|
||||
var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
function onError(e) {
|
||||
ok(false, e.data.error);
|
||||
}
|
||||
mm.addMessageListener("testSaveHeapSnapshot:error", onError);
|
||||
|
||||
function onError(e) {
|
||||
ok(false, e.data.error);
|
||||
}
|
||||
mm.addMessageListener("testSaveHeapSnapshot:error", onError);
|
||||
mm.addMessageListener("testSaveHeapSnapshot:done", function onMsg() {
|
||||
mm.removeMessageListener("testSaveHeapSnapshot:done", onMsg);
|
||||
mm.removeMessageListener("testSaveHeapSnapshot:error", onError);
|
||||
ok(true, "Saved heap snapshot in child process");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
mm.addMessageListener("testSaveHeapSnapshot:done", function onMsg() {
|
||||
mm.removeMessageListener("testSaveHeapSnapshot:done", onMsg);
|
||||
mm.removeMessageListener("testSaveHeapSnapshot:error", onError);
|
||||
ok(true, "Saved heap snapshot in child process");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
info("Loading frame script to save heap snapshot");
|
||||
mm.loadFrameScript("data:,(" + encodeURI(childFrameScript.toString()) + ")();",
|
||||
false);
|
||||
}, {once: true});
|
||||
|
||||
info("Loading frame script to save heap snapshot");
|
||||
mm.loadFrameScript("data:,(" + encodeURI(childFrameScript.toString()) + ")();",
|
||||
false);
|
||||
}, {once: true});
|
||||
|
||||
info("Loading iframe");
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
info("Loading iframe");
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</window>
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Debugger.Memory.prototype.takeCensus and
|
||||
// HeapSnapshot.prototype.takeCensus. Adapted from js/src/jit-test/lib/census.js.
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Census"];
|
||||
|
||||
this.Census = (function () {
|
||||
@ -62,7 +64,11 @@ this.Census = (function () {
|
||||
Census.assertAllZeros = {
|
||||
enter: () => Census.assertAllZeros,
|
||||
done: () => undefined,
|
||||
check: elt => { if (elt !== 0) throw new Error("Census mismatch: expected zero, found " + elt); }
|
||||
check: elt => {
|
||||
if (elt !== 0) {
|
||||
throw new Error("Census mismatch: expected zero, found " + elt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function expectedObject() {
|
||||
@ -89,27 +95,27 @@ this.Census = (function () {
|
||||
function makeBasisChecker({compare, missing, extra}) {
|
||||
return function makeWalker(basis) {
|
||||
if (typeof basis === "object") {
|
||||
var unvisited = new Set(Object.getOwnPropertyNames(basis));
|
||||
let unvisited = new Set(Object.getOwnPropertyNames(basis));
|
||||
return {
|
||||
enter: prop => {
|
||||
unvisited.delete(prop);
|
||||
if (prop in basis) {
|
||||
return makeWalker(basis[prop]);
|
||||
} else {
|
||||
return extra(prop);
|
||||
}
|
||||
|
||||
return extra(prop);
|
||||
},
|
||||
|
||||
done: () => unvisited.forEach(prop => missing(prop, basis[prop])),
|
||||
check: expectedObject
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
enter: expectedLeaf,
|
||||
done: expectedLeaf,
|
||||
check: elt => compare(elt, basis)
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
enter: expectedLeaf,
|
||||
done: expectedLeaf,
|
||||
check: elt => compare(elt, basis)
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -118,13 +124,18 @@ this.Census = (function () {
|
||||
}
|
||||
|
||||
function extraProp(prop) {
|
||||
throw new Error("Census mismatch: subject has property not present in basis: " + prop);
|
||||
throw new Error("Census mismatch: subject has property not present in basis: "
|
||||
+ prop);
|
||||
}
|
||||
|
||||
// Return a walker that checks that the subject census has counts all equal to
|
||||
// |basis|.
|
||||
Census.assertAllEqual = makeBasisChecker({
|
||||
compare: (a, b) => { if (a !== b) throw new Error("Census mismatch: expected " + a + " got " + b);},
|
||||
compare: (a, b) => {
|
||||
if (a !== b) {
|
||||
throw new Error("Census mismatch: expected " + a + " got " + b);
|
||||
}
|
||||
},
|
||||
missing: missingProp,
|
||||
extra: extraProp
|
||||
});
|
||||
@ -155,7 +166,7 @@ this.Census = (function () {
|
||||
// items of each category of the count in |basis|.
|
||||
Census.assertAllWithin = function (fudge, basis) {
|
||||
return makeBasisChecker({
|
||||
compare: (subject, basis) => ok(Math.abs(subject - basis) <= fudge),
|
||||
compare: (subject, base) => ok(Math.abs(subject - base) <= fudge),
|
||||
missing: missingProp,
|
||||
extra: () => Census.walkAnything
|
||||
})(basis);
|
||||
|
@ -3,188 +3,212 @@
|
||||
// Ported from js/src/tests/js1_8_5/reflect-parse/Match.js for use with devtools
|
||||
// server xpcshell tests.
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Match"];
|
||||
|
||||
this.Match = (function() {
|
||||
|
||||
function Pattern(template) {
|
||||
// act like a constructor even as a function
|
||||
if (!(this instanceof Pattern))
|
||||
return new Pattern(template);
|
||||
|
||||
this.template = template;
|
||||
this.Match = (function () {
|
||||
function Pattern(template) {
|
||||
// act like a constructor even as a function
|
||||
if (!(this instanceof Pattern)) {
|
||||
return new Pattern(template);
|
||||
}
|
||||
|
||||
Pattern.prototype = {
|
||||
match: function(act) {
|
||||
return match(act, this.template);
|
||||
},
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
matches: function(act) {
|
||||
try {
|
||||
return this.match(act);
|
||||
}
|
||||
catch (e if e instanceof MatchError) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
Pattern.prototype = {
|
||||
match: function (act) {
|
||||
return match(act, this.template);
|
||||
},
|
||||
|
||||
assert: function(act, message) {
|
||||
try {
|
||||
return this.match(act);
|
||||
}
|
||||
catch (e if e instanceof MatchError) {
|
||||
throw new Error((message || "failed match") + ": " + e.message);
|
||||
}
|
||||
},
|
||||
|
||||
toString: () => "[object Pattern]"
|
||||
};
|
||||
|
||||
Pattern.ANY = new Pattern;
|
||||
Pattern.ANY.template = Pattern.ANY;
|
||||
|
||||
Pattern.NUMBER = new Pattern;
|
||||
Pattern.NUMBER.match = function (act) {
|
||||
if (typeof act !== 'number') {
|
||||
throw new MatchError("Expected number, got: " + quote(act));
|
||||
matches: function (act) {
|
||||
try {
|
||||
return this.match(act);
|
||||
} catch (e) {
|
||||
if (e instanceof MatchError) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
Pattern.NATURAL = new Pattern
|
||||
Pattern.NATURAL.match = function (act) {
|
||||
if (typeof act !== 'number' || act !== Math.floor(act) || act < 0) {
|
||||
throw new MatchError("Expected natural number, got: " + quote(act));
|
||||
assert: function (act, message) {
|
||||
try {
|
||||
return this.match(act);
|
||||
} catch (e) {
|
||||
if (e instanceof MatchError) {
|
||||
throw new Error((message || "failed match") + ": " + e.message);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
toString: () => "[object Pattern]"
|
||||
};
|
||||
|
||||
Pattern.ANY = new Pattern();
|
||||
Pattern.ANY.template = Pattern.ANY;
|
||||
|
||||
Pattern.NUMBER = new Pattern();
|
||||
Pattern.NUMBER.match = function (act) {
|
||||
if (typeof act !== "number") {
|
||||
throw new MatchError("Expected number, got: " + quote(act));
|
||||
}
|
||||
};
|
||||
|
||||
Pattern.NATURAL = new Pattern();
|
||||
Pattern.NATURAL.match = function (act) {
|
||||
if (typeof act !== "number" || act !== Math.floor(act) || act < 0) {
|
||||
throw new MatchError("Expected natural number, got: " + quote(act));
|
||||
}
|
||||
};
|
||||
|
||||
let quote = uneval;
|
||||
|
||||
function MatchError(msg) {
|
||||
this.message = msg;
|
||||
}
|
||||
|
||||
MatchError.prototype = {
|
||||
toString: function () {
|
||||
return "match error: " + this.message;
|
||||
}
|
||||
};
|
||||
|
||||
function isAtom(x) {
|
||||
return (typeof x === "number") ||
|
||||
(typeof x === "string") ||
|
||||
(typeof x === "boolean") ||
|
||||
(x === null) ||
|
||||
(typeof x === "object" && x instanceof RegExp);
|
||||
}
|
||||
|
||||
function isObject(x) {
|
||||
return (x !== null) && (typeof x === "object");
|
||||
}
|
||||
|
||||
function isFunction(x) {
|
||||
return typeof x === "function";
|
||||
}
|
||||
|
||||
function isArrayLike(x) {
|
||||
return isObject(x) && ("length" in x);
|
||||
}
|
||||
|
||||
function matchAtom(act, exp) {
|
||||
if ((typeof exp) === "number" && isNaN(exp)) {
|
||||
if ((typeof act) !== "number" || !isNaN(act)) {
|
||||
throw new MatchError("expected NaN, got: " + quote(act));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var quote = uneval;
|
||||
|
||||
function MatchError(msg) {
|
||||
this.message = msg;
|
||||
if (exp === null) {
|
||||
if (act !== null) {
|
||||
throw new MatchError("expected null, got: " + quote(act));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MatchError.prototype = {
|
||||
toString: function() {
|
||||
return "match error: " + this.message;
|
||||
if (exp instanceof RegExp) {
|
||||
if (!(act instanceof RegExp) || exp.source !== act.source) {
|
||||
throw new MatchError("expected " + quote(exp) + ", got: " + quote(act));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (typeof exp) {
|
||||
case "string":
|
||||
if (act !== exp) {
|
||||
throw new MatchError("expected " + quote(exp) + ", got " + quote(act));
|
||||
}
|
||||
};
|
||||
|
||||
function isAtom(x) {
|
||||
return (typeof x === "number") ||
|
||||
(typeof x === "string") ||
|
||||
(typeof x === "boolean") ||
|
||||
(x === null) ||
|
||||
(typeof x === "object" && x instanceof RegExp);
|
||||
}
|
||||
|
||||
function isObject(x) {
|
||||
return (x !== null) && (typeof x === "object");
|
||||
}
|
||||
|
||||
function isFunction(x) {
|
||||
return typeof x === "function";
|
||||
}
|
||||
|
||||
function isArrayLike(x) {
|
||||
return isObject(x) && ("length" in x);
|
||||
}
|
||||
|
||||
function matchAtom(act, exp) {
|
||||
if ((typeof exp) === "number" && isNaN(exp)) {
|
||||
if ((typeof act) !== "number" || !isNaN(act))
|
||||
throw new MatchError("expected NaN, got: " + quote(act));
|
||||
return true;
|
||||
return true;
|
||||
case "boolean":
|
||||
case "number":
|
||||
if (exp !== act) {
|
||||
throw new MatchError("expected " + exp + ", got " + quote(act));
|
||||
}
|
||||
|
||||
if (exp === null) {
|
||||
if (act !== null)
|
||||
throw new MatchError("expected null, got: " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exp instanceof RegExp) {
|
||||
if (!(act instanceof RegExp) || exp.source !== act.source)
|
||||
throw new MatchError("expected " + quote(exp) + ", got: " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (typeof exp) {
|
||||
case "string":
|
||||
if (act !== exp)
|
||||
throw new MatchError("expected " + quote(exp) + ", got " + quote(act));
|
||||
return true;
|
||||
case "boolean":
|
||||
case "number":
|
||||
if (exp !== act)
|
||||
throw new MatchError("expected " + exp + ", got " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Error("bad pattern: " + exp.toSource());
|
||||
}
|
||||
|
||||
function matchObject(act, exp) {
|
||||
if (!isObject(act))
|
||||
throw new MatchError("expected object, got " + quote(act));
|
||||
|
||||
for (var key in exp) {
|
||||
if (!(key in act))
|
||||
throw new MatchError("expected property " + quote(key) + " not found in " + quote(act));
|
||||
match(act[key], exp[key]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function matchFunction(act, exp) {
|
||||
if (!isFunction(act))
|
||||
throw new MatchError("expected function, got " + quote(act));
|
||||
throw new Error("bad pattern: " + exp.toSource());
|
||||
}
|
||||
|
||||
if (act !== exp)
|
||||
throw new MatchError("expected function: " + exp +
|
||||
"\nbut got different function: " + act);
|
||||
function matchObject(act, exp) {
|
||||
if (!isObject(act)) {
|
||||
throw new MatchError("expected object, got " + quote(act));
|
||||
}
|
||||
|
||||
function matchArray(act, exp) {
|
||||
if (!isObject(act) || !("length" in act))
|
||||
throw new MatchError("expected array-like object, got " + quote(act));
|
||||
for (let key in exp) {
|
||||
if (!(key in act)) {
|
||||
throw new MatchError("expected property " + quote(key)
|
||||
+ " not found in " + quote(act));
|
||||
}
|
||||
match(act[key], exp[key]);
|
||||
}
|
||||
|
||||
var length = exp.length;
|
||||
if (act.length !== exp.length)
|
||||
throw new MatchError("expected array-like object of length " + length + ", got " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (i in exp) {
|
||||
if (!(i in act))
|
||||
throw new MatchError("expected array property " + i + " not found in " + quote(act));
|
||||
match(act[i], exp[i]);
|
||||
}
|
||||
function matchFunction(act, exp) {
|
||||
if (!isFunction(act)) {
|
||||
throw new MatchError("expected function, got " + quote(act));
|
||||
}
|
||||
|
||||
if (act !== exp) {
|
||||
throw new MatchError("expected function: " + exp +
|
||||
"\nbut got different function: " + act);
|
||||
}
|
||||
}
|
||||
|
||||
function matchArray(act, exp) {
|
||||
if (!isObject(act) || !("length" in act)) {
|
||||
throw new MatchError("expected array-like object, got " + quote(act));
|
||||
}
|
||||
|
||||
let length = exp.length;
|
||||
if (act.length !== exp.length) {
|
||||
throw new MatchError("expected array-like object of length "
|
||||
+ length + ", got " + quote(act));
|
||||
}
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (i in exp) {
|
||||
if (!(i in act)) {
|
||||
throw new MatchError("expected array property " + i + " not found in "
|
||||
+ quote(act));
|
||||
}
|
||||
|
||||
return true;
|
||||
match(act[i], exp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function match(act, exp) {
|
||||
if (exp === Pattern.ANY)
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exp instanceof Pattern)
|
||||
return exp.match(act);
|
||||
|
||||
if (isAtom(exp))
|
||||
return matchAtom(act, exp);
|
||||
|
||||
if (isArrayLike(exp))
|
||||
return matchArray(act, exp);
|
||||
|
||||
if (isFunction(exp))
|
||||
return matchFunction(act, exp);
|
||||
|
||||
return matchObject(act, exp);
|
||||
function match(act, exp) {
|
||||
if (exp === Pattern.ANY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return { Pattern: Pattern,
|
||||
MatchError: MatchError };
|
||||
if (exp instanceof Pattern) {
|
||||
return exp.match(act);
|
||||
}
|
||||
|
||||
if (isAtom(exp)) {
|
||||
return matchAtom(act, exp);
|
||||
}
|
||||
|
||||
if (isArrayLike(exp)) {
|
||||
return matchArray(act, exp);
|
||||
}
|
||||
|
||||
if (isFunction(exp)) {
|
||||
return matchFunction(act, exp);
|
||||
}
|
||||
|
||||
return matchObject(act, exp);
|
||||
}
|
||||
|
||||
return { Pattern, MatchError };
|
||||
})();
|
||||
|
@ -1,6 +1,8 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
console.log("Initializing worker.");
|
||||
|
||||
self.onmessage = e => {
|
||||
@ -16,12 +18,12 @@ self.onmessage = e => {
|
||||
let threw = false;
|
||||
try {
|
||||
new DominatorTree();
|
||||
} catch (e) {
|
||||
} catch (excp) {
|
||||
threw = true;
|
||||
}
|
||||
ok(threw, "Constructor shouldn't be usable");
|
||||
} catch (e) {
|
||||
ok(false, "Unexpected error inside worker:\n" + e.toString() + "\n" + e.stack);
|
||||
} catch (ex) {
|
||||
ok(false, "Unexpected error inside worker:\n" + ex.toString() + "\n" + ex.stack);
|
||||
} finally {
|
||||
done();
|
||||
}
|
||||
|
@ -2,6 +2,12 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
/* exported Cr, CC, Match, Census, Task, DevToolsUtils, HeapAnalysesClient,
|
||||
assertThrows, getFilePath, saveHeapSnapshotAndTakeCensus,
|
||||
saveHeapSnapshotAndComputeDominatorTree, compareCensusViewData, assertDiff,
|
||||
assertLabelAndShallowSize, makeTestDominatorTreeNode,
|
||||
assertDominatorTreeNodeInsertion, assertDeduplicatedPaths,
|
||||
assertCountToBucketBreakdown, pathEntry */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
@ -14,7 +20,6 @@ const { Match } = Cu.import("resource://test/Match.jsm", {});
|
||||
const { Census } = Cu.import("resource://test/Census.jsm", {});
|
||||
const { addDebuggerToGlobal } =
|
||||
Cu.import("resource://gre/modules/jsdebugger.jsm", {});
|
||||
const { Task } = require("devtools/shared/task");
|
||||
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const flags = require("devtools/shared/flags");
|
||||
@ -27,7 +32,6 @@ const DominatorTreeNode = require("devtools/shared/heapsnapshot/DominatorTreeNod
|
||||
const { deduplicatePaths } = require("devtools/shared/heapsnapshot/shortest-paths");
|
||||
const { LabelAndShallowSizeVisitor } = DominatorTreeNode;
|
||||
|
||||
|
||||
// Always log packets when running tests. runxpcshelltests.py will throw
|
||||
// the output away anyway, unless you give it the --verbose flag.
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
@ -75,19 +79,24 @@ function newGlobal() {
|
||||
return global;
|
||||
}
|
||||
|
||||
function assertThrowsValue(f, val, msg) {
|
||||
var fullmsg;
|
||||
function assertThrows(f, val, msg) {
|
||||
let fullmsg;
|
||||
try {
|
||||
f();
|
||||
} catch (exc) {
|
||||
if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val))
|
||||
if ((exc === val) && (val !== 0 || 1 / exc === 1 / val)) {
|
||||
return;
|
||||
} else if (exc instanceof Error && exc.message === val) {
|
||||
return;
|
||||
}
|
||||
fullmsg = "Assertion failed: expected exception " + val + ", got " + exc;
|
||||
}
|
||||
if (fullmsg === undefined)
|
||||
if (fullmsg === undefined) {
|
||||
fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown";
|
||||
if (msg !== undefined)
|
||||
}
|
||||
if (msg !== undefined) {
|
||||
fullmsg += " - " + msg;
|
||||
}
|
||||
throw new Error(fullmsg);
|
||||
}
|
||||
|
||||
@ -95,9 +104,8 @@ function assertThrowsValue(f, val, msg) {
|
||||
* Returns the full path of the file with the specified name in a
|
||||
* platform-independent and URL-like form.
|
||||
*/
|
||||
function getFilePath(aName, aAllowMissing = false, aUsePlatformPathSeparator = false)
|
||||
{
|
||||
let file = do_get_file(aName, aAllowMissing);
|
||||
function getFilePath(name, allowMissing = false, usePlatformPathSeparator = false) {
|
||||
let file = do_get_file(name, allowMissing);
|
||||
let path = Services.io.newFileURI(file).spec;
|
||||
let filePrePath = "file://";
|
||||
if ("nsILocalFileWin" in Ci &&
|
||||
@ -107,7 +115,7 @@ function getFilePath(aName, aAllowMissing = false, aUsePlatformPathSeparator = f
|
||||
|
||||
path = path.slice(filePrePath.length);
|
||||
|
||||
if (aUsePlatformPathSeparator && path.match(/^\w:/)) {
|
||||
if (sePlatformPathSeparator && path.match(/^\w:/)) {
|
||||
path = path.replace(/\//g, "\\");
|
||||
}
|
||||
|
||||
@ -152,7 +160,8 @@ function saveHeapSnapshotAndTakeCensus(dbg = null, censusOptions = undefined) {
|
||||
const filePath = saveNewHeapSnapshot(snapshotOptions);
|
||||
const snapshot = readHeapSnapshot(filePath);
|
||||
|
||||
equal(typeof snapshot.takeCensus, "function", "snapshot should have a takeCensus method");
|
||||
equal(typeof snapshot.takeCensus, "function",
|
||||
"snapshot should have a takeCensus method");
|
||||
|
||||
return snapshot.takeCensus(censusOptions);
|
||||
}
|
||||
@ -190,9 +199,8 @@ function isSavedFrame(obj) {
|
||||
function savedFrameReplacer(key, val) {
|
||||
if (isSavedFrame(val)) {
|
||||
return `<SavedFrame '${val.toString().split(/\n/g).shift()}'>`;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -244,7 +252,7 @@ function assertStructurallyEquivalent(actual, expected, path = "root") {
|
||||
|
||||
for (let key of actual.keys()) {
|
||||
ok(expectedKeys.has(key),
|
||||
`${path}: every key in actual should exist in expected: ${String(key).slice(0, 10)}`);
|
||||
`${path}: every key in actual is expected: ${String(key).slice(0, 10)}`);
|
||||
expectedKeys.delete(key);
|
||||
|
||||
assertStructurallyEquivalent(actual.get(key), expected.get(key),
|
||||
@ -252,7 +260,8 @@ function assertStructurallyEquivalent(actual, expected, path = "root") {
|
||||
}
|
||||
|
||||
equal(expectedKeys.size, 0,
|
||||
`${path}: every key in expected should also exist in actual, did not see ${[...expectedKeys]}`);
|
||||
`${path}: every key in expected should also exist in actual,\
|
||||
did not see ${[...expectedKeys]}`);
|
||||
} else if (actualProtoString === "[object Set]") {
|
||||
const expectedItems = new Set([...expected]);
|
||||
|
||||
@ -263,7 +272,8 @@ function assertStructurallyEquivalent(actual, expected, path = "root") {
|
||||
}
|
||||
|
||||
equal(expectedItems.size, 0,
|
||||
`${path}: every set item in expected should also exist in actual, did not see ${[...expectedItems]}`);
|
||||
`${path}: every set item in expected should also exist in actual,\
|
||||
did not see ${[...expectedItems]}`);
|
||||
} else {
|
||||
const expectedKeys = new Set(Object.keys(expected));
|
||||
|
||||
@ -276,7 +286,8 @@ function assertStructurallyEquivalent(actual, expected, path = "root") {
|
||||
}
|
||||
|
||||
equal(expectedKeys.size, 0,
|
||||
`${path}: every key in expected should also exist in actual, did not see ${[...expectedKeys]}`);
|
||||
`${path}: every key in expected should also exist in actual,\
|
||||
did not see ${[...expectedKeys]}`);
|
||||
}
|
||||
} else {
|
||||
equal(actual, expected, `${path}: primitives should be equal`);
|
||||
@ -321,7 +332,8 @@ function assertDiff(breakdown, first, second, expected) {
|
||||
* @param {Number} expectedShallowSize
|
||||
* @param {Object} expectedLabel
|
||||
*/
|
||||
function assertLabelAndShallowSize(breakdown, givenDescription, expectedShallowSize, expectedLabel) {
|
||||
function assertLabelAndShallowSize(breakdown, givenDescription,
|
||||
expectedShallowSize, expectedLabel) {
|
||||
dumpn("Computing label and shallow size from node description:");
|
||||
dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4));
|
||||
dumpn("Given description: " + JSON.stringify(givenDescription, null, 4));
|
||||
@ -364,7 +376,7 @@ function makeTestDominatorTreeNode(opts, children) {
|
||||
}, opts);
|
||||
|
||||
if (children && children.length) {
|
||||
children.map(c => c.parentId = node.nodeId);
|
||||
children.map(c => (c.parentId = node.nodeId));
|
||||
}
|
||||
|
||||
return node;
|
||||
@ -375,7 +387,8 @@ function makeTestDominatorTreeNode(opts, children) {
|
||||
* `path` from the root to the node the `newChildren` should be inserted
|
||||
* beneath. Assert that the resulting tree matches `expected`.
|
||||
*/
|
||||
function assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected) {
|
||||
function assertDominatorTreeNodeInsertion(tree, path, newChildren,
|
||||
moreChildrenAvailable, expected) {
|
||||
dumpn("Inserting new children into a dominator tree:");
|
||||
dumpn("Dominator tree: " + JSON.stringify(tree, null, 2));
|
||||
dumpn("Path: " + JSON.stringify(path, null, 2));
|
||||
@ -425,7 +438,8 @@ function assertDeduplicatedPaths({ target, paths, expectedNodes, expectedEdges }
|
||||
}
|
||||
}
|
||||
equal(count, 1,
|
||||
"should have exactly one matching edge for the expected edge = " + JSON.stringify(edge));
|
||||
"should have exactly one matching edge for the expected edge = "
|
||||
+ JSON.stringify(edge));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
console.log("Initializing worker.");
|
||||
|
||||
self.onmessage = e => {
|
||||
self.onmessage = ex => {
|
||||
console.log("Starting test.");
|
||||
try {
|
||||
ok(typeof ChromeUtils === "undefined",
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can generate label structures from node description reports.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can generate label structures from node description reports.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can generate label structures from node description reports.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can generate label structures from node description reports.
|
||||
|
||||
|
@ -69,7 +69,8 @@ const expected = [
|
||||
}
|
||||
}),
|
||||
|
||||
makeTestDominatorTreeNode({ nodeId: 3000,
|
||||
makeTestDominatorTreeNode({
|
||||
nodeId: 3000,
|
||||
shortestPaths: {
|
||||
nodes: [
|
||||
{ id: 3000, label: ["SomeType-3000"] },
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can find the node with the given id along the specified path.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can insert new children into an existing DominatorTreeNode tree.
|
||||
|
||||
@ -108,5 +109,6 @@ const expected = {
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected);
|
||||
assertDominatorTreeNodeInsertion(tree, path, newChildren,
|
||||
moreChildrenAvailable, expected);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test attempting to insert new children into an existing DominatorTreeNode
|
||||
// tree with a bad path.
|
||||
@ -26,5 +27,6 @@ const moreChildrenAvailable = false;
|
||||
const expected = tree;
|
||||
|
||||
function run_test() {
|
||||
assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected);
|
||||
assertDominatorTreeNodeInsertion(tree, path, newChildren,
|
||||
moreChildrenAvailable, expected);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test inserting new children into an existing DominatorTreeNode at the root.
|
||||
|
||||
@ -113,5 +114,6 @@ const expected = {
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected);
|
||||
assertDominatorTreeNodeInsertion(tree, path, newChildren,
|
||||
moreChildrenAvailable, expected);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we correctly set `moreChildrenAvailable` when doing a partial
|
||||
// traversal of a dominator tree to create the initial incrementally loaded
|
||||
@ -154,8 +155,10 @@ function run_test() {
|
||||
const actual = DominatorTreeNode.partialTraversal(mockDominatorTree,
|
||||
mockSnapshot,
|
||||
breakdown,
|
||||
/* maxDepth = */ 4,
|
||||
/* siblings = */ 2);
|
||||
// maxDepth
|
||||
4,
|
||||
// siblings
|
||||
2);
|
||||
|
||||
dumpn("Expected = " + JSON.stringify(expected, null, 2));
|
||||
dumpn("Actual = " + JSON.stringify(actual, null, 2));
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Sanity test that we can compute dominator trees.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can compute dominator trees from a snapshot in a worker.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can get the root of dominator trees.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can get the retained sizes of dominator trees.
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can get the set of immediately dominated nodes for any given
|
||||
// node and that this forms a tree.
|
||||
|
||||
function run_test() {
|
||||
var dominatorTree = saveHeapSnapshotAndComputeDominatorTree();
|
||||
let dominatorTree = saveHeapSnapshotAndComputeDominatorTree();
|
||||
equal(typeof dominatorTree.getImmediatelyDominated, "function",
|
||||
"getImmediatelyDominated should be a function");
|
||||
|
||||
@ -16,33 +17,33 @@ function run_test() {
|
||||
// every one. This test would constantly time out and assertion messages would
|
||||
// overflow the log size.
|
||||
|
||||
var root = dominatorTree.root;
|
||||
let root = dominatorTree.root;
|
||||
equal(dominatorTree.getImmediateDominator(root), null,
|
||||
"The root should not have a parent");
|
||||
|
||||
var seen = new Set();
|
||||
var stack = [root];
|
||||
let seen = new Set();
|
||||
let stack = [root];
|
||||
while (stack.length > 0) {
|
||||
var top = stack.pop();
|
||||
let top = stack.pop();
|
||||
|
||||
if (seen.has(top)) {
|
||||
ok(false,
|
||||
"This is a tree, not a graph: we shouldn't have multiple edges to the same node");
|
||||
ok(false, "This is a tree, not a graph: we shouldn't have "
|
||||
+ "multiple edges to the same node");
|
||||
}
|
||||
seen.add(top);
|
||||
if (seen.size % 1000 === 0) {
|
||||
dumpn("Progress update: seen size = " + seen.size);
|
||||
}
|
||||
|
||||
var newNodes = dominatorTree.getImmediatelyDominated(top);
|
||||
let newNodes = dominatorTree.getImmediatelyDominated(top);
|
||||
if (Object.prototype.toString.call(newNodes) !== "[object Array]") {
|
||||
ok(false, "getImmediatelyDominated should return an array for known node ids");
|
||||
}
|
||||
|
||||
var topSize = dominatorTree.getRetainedSize(top);
|
||||
let topSize = dominatorTree.getRetainedSize(top);
|
||||
|
||||
var lastSize = Infinity;
|
||||
for (var i = 0; i < newNodes.length; i++) {
|
||||
let lastSize = Infinity;
|
||||
for (let i = 0; i < newNodes.length; i++) {
|
||||
if (typeof newNodes[i] !== "number") {
|
||||
ok(false, "Every dominated id should be a number");
|
||||
}
|
||||
@ -51,10 +52,11 @@ function run_test() {
|
||||
ok(false, "child's parent should be the expected parent");
|
||||
}
|
||||
|
||||
var thisSize = dominatorTree.getRetainedSize(newNodes[i]);
|
||||
let thisSize = dominatorTree.getRetainedSize(newNodes[i]);
|
||||
|
||||
if (thisSize >= topSize) {
|
||||
ok(false, "the size of children in the dominator tree should always be less than that of their parent");
|
||||
ok(false, "the size of children in the dominator tree should"
|
||||
+ " always be less than that of their parent");
|
||||
}
|
||||
|
||||
if (thisSize > lastSize) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the retained size of a node is the sum of its children retained
|
||||
// sizes plus its shallow size.
|
||||
@ -14,31 +15,31 @@ function fastAssert(cond, msg) {
|
||||
}
|
||||
}
|
||||
|
||||
var COUNT = { by: "count", count: false, bytes: true };
|
||||
let COUNT = { by: "count", count: false, bytes: true };
|
||||
|
||||
function run_test() {
|
||||
var path = saveNewHeapSnapshot();
|
||||
var snapshot = ChromeUtils.readHeapSnapshot(path);
|
||||
var dominatorTree = snapshot.computeDominatorTree();
|
||||
let path = saveNewHeapSnapshot();
|
||||
let snapshot = ChromeUtils.readHeapSnapshot(path);
|
||||
let dominatorTree = snapshot.computeDominatorTree();
|
||||
|
||||
// Do a traversal of the dominator tree and assert the relationship between
|
||||
// retained size, shallow size, and children's retained sizes.
|
||||
|
||||
var root = dominatorTree.root;
|
||||
var stack = [root];
|
||||
let root = dominatorTree.root;
|
||||
let stack = [root];
|
||||
while (stack.length > 0) {
|
||||
var top = stack.pop();
|
||||
let top = stack.pop();
|
||||
|
||||
var children = dominatorTree.getImmediatelyDominated(top);
|
||||
let children = dominatorTree.getImmediatelyDominated(top);
|
||||
|
||||
var topRetainedSize = dominatorTree.getRetainedSize(top);
|
||||
var topShallowSize = snapshot.describeNode(COUNT, top).bytes;
|
||||
let topRetainedSize = dominatorTree.getRetainedSize(top);
|
||||
let topShallowSize = snapshot.describeNode(COUNT, top).bytes;
|
||||
fastAssert(topShallowSize <= topRetainedSize,
|
||||
"The shallow size should be less than or equal to the " +
|
||||
"retained size");
|
||||
|
||||
var sumOfChildrensRetainedSizes = 0;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
let sumOfChildrensRetainedSizes = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
sumOfChildrensRetainedSizes += dominatorTree.getRetainedSize(children[i]);
|
||||
stack.push(children[i]);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test the HeapAnalyses{Client,Worker} "computeDominatorTree" request.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test the HeapAnalyses{Client,Worker} "computeDominatorTree" request with bad
|
||||
// file paths.
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can delete heap snapshots.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test deleteHeapSnapshot is a noop if the provided path matches no snapshot
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test other dominatorTrees can still be retrieved after deleting a snapshot
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can get census individuals.
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can get a HeapSnapshot's
|
||||
// creation time.
|
||||
|
||||
function waitForThirtyMilliseconds() {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < 30) ;
|
||||
while (Date.now() - start < 30) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test the HeapAnalyses{Client,Worker} "getDominatorTree" request.
|
||||
|
||||
@ -47,7 +48,8 @@ add_task(function* () {
|
||||
"each node should have a retained size");
|
||||
|
||||
ok(node.children === undefined || Array.isArray(node.children),
|
||||
"each node either has a list of children, or undefined meaning no children loaded");
|
||||
"each node either has a list of children, "
|
||||
+ "or undefined meaning no children loaded");
|
||||
equal(typeof node.moreChildrenAvailable, "boolean",
|
||||
"each node should indicate if there are more children available or not");
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test the HeapAnalyses{Client,Worker} "getDominatorTree" request with bad
|
||||
// dominator tree ids.
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test the HeapAnalyses{Client,Worker} "getImmediatelyDominated" request.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can read heap snapshots.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can take diffs between censuses.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can take diffs between censuses as
|
||||
// inverted trees.
|
||||
@ -43,10 +44,11 @@ add_task(function* () {
|
||||
secondSnapshotFilePath,
|
||||
{ breakdown: BREAKDOWN });
|
||||
|
||||
const { delta: deltaTreeNode } = yield client.takeCensusDiff(firstSnapshotFilePath,
|
||||
secondSnapshotFilePath,
|
||||
{ breakdown: BREAKDOWN },
|
||||
{ asInvertedTreeNode: true });
|
||||
const { delta: deltaTreeNode }
|
||||
= yield client.takeCensusDiff(firstSnapshotFilePath,
|
||||
secondSnapshotFilePath,
|
||||
{ breakdown: BREAKDOWN },
|
||||
{ asInvertedTreeNode: true });
|
||||
|
||||
// Have to manually set these because symbol properties aren't structured
|
||||
// cloned.
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can take censuses.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can take censuses with breakdown
|
||||
// options.
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} bubbles errors properly when things
|
||||
// go wrong.
|
||||
@ -27,7 +28,8 @@ add_task(function* () {
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
}
|
||||
ok(failed, "should not be able to read a file that is not a heap snapshot as a heap snapshot");
|
||||
ok(failed, "should not be able to read a file "
|
||||
+ "that is not a heap snapshot as a heap snapshot");
|
||||
|
||||
const snapshotFilePath = saveNewHeapSnapshot();
|
||||
yield client.readHeapSnapshot(snapshotFilePath);
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can send SavedFrame stacks from
|
||||
// by-allocation-stack reports from the worker.
|
||||
@ -20,7 +21,7 @@ add_task(function* test() {
|
||||
function f() { this.log.push(allocationMarker()); } // 3
|
||||
function g() { this.log.push(allocationMarker()); } // 4
|
||||
function h() { this.log.push(allocationMarker()); } // 5
|
||||
`); // 6
|
||||
`);
|
||||
|
||||
// Create one allocationMarker with tracking turned off,
|
||||
// so it will have no associated stack.
|
||||
@ -49,20 +50,26 @@ add_task(function* test() {
|
||||
// Run a census broken down by class name -> allocation stack so we can grab
|
||||
// only the AllocationMarker objects we have complete control over.
|
||||
|
||||
const { report } = yield client.takeCensus(snapshotFilePath, {
|
||||
breakdown: { by: "objectClass",
|
||||
then: { by: "allocationStack",
|
||||
then: { by: "count",
|
||||
bytes: true,
|
||||
count: true
|
||||
},
|
||||
noStack: { by: "count",
|
||||
bytes: true,
|
||||
count: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const { report } = yield client.takeCensus(
|
||||
snapshotFilePath,
|
||||
{
|
||||
breakdown: {
|
||||
by: "objectClass",
|
||||
then: {
|
||||
by: "allocationStack",
|
||||
then: {
|
||||
by: "count",
|
||||
bytes: true,
|
||||
count: true
|
||||
},
|
||||
noStack: {
|
||||
by: "count",
|
||||
bytes: true,
|
||||
count: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Test the generated report.
|
||||
|
||||
@ -72,7 +79,7 @@ add_task(function* test() {
|
||||
ok(map, "Should get AllocationMarkers in the report.");
|
||||
// From a module with a different global, and therefore a different Map
|
||||
// constructor, so we can't use instanceof.
|
||||
equal(map.__proto__.constructor.name, "Map");
|
||||
equal(Object.getPrototypeOf(map).constructor.name, "Map");
|
||||
|
||||
equal(map.size, 4, "Should have 4 allocation stacks (including the lack of a stack)");
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can take censuses and return
|
||||
// a CensusTreeNode.
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can take censuses by
|
||||
// "allocationStack" and return a CensusTreeNode.
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can take censuses and return
|
||||
// an inverted CensusTreeNode.
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Sanity test that we can compute shortest paths.
|
||||
//
|
||||
@ -21,7 +22,8 @@ function run_test() {
|
||||
|
||||
const targetSet = new Set(dominatedByRoot);
|
||||
|
||||
const shortestPaths = snapshot.computeShortestPaths(dominatorTree.root, dominatedByRoot, 2);
|
||||
const shortestPaths
|
||||
= snapshot.computeShortestPaths(dominatorTree.root, dominatedByRoot, 2);
|
||||
ok(shortestPaths);
|
||||
ok(shortestPaths instanceof Map);
|
||||
ok(shortestPaths.size === targetSet.size);
|
||||
@ -38,21 +40,21 @@ function run_test() {
|
||||
|
||||
dumpn("---------------------");
|
||||
dumpn("Shortest paths for 0x" + target.toString(16) + ":");
|
||||
for (let path of paths) {
|
||||
for (let pth of paths) {
|
||||
dumpn(" path =");
|
||||
for (let part of path) {
|
||||
for (let part of pth) {
|
||||
dumpn(" predecessor: 0x" + part.predecessor.toString(16) +
|
||||
"; edge: " + part.edge);
|
||||
}
|
||||
}
|
||||
dumpn("---------------------");
|
||||
|
||||
for (let path of paths) {
|
||||
ok(path.length > 0, "Cannot have zero length paths");
|
||||
ok(path[0].predecessor === dominatorTree.root,
|
||||
for (let path2 of paths) {
|
||||
ok(path2.length > 0, "Cannot have zero length paths");
|
||||
ok(path2[0].predecessor === dominatorTree.root,
|
||||
"The first predecessor is always our start node");
|
||||
|
||||
for (let part of path) {
|
||||
for (let part of path2) {
|
||||
ok(part.predecessor, "Each part of a path has a predecessor");
|
||||
ok(!!snapshot.describeNode({ by: "count", count: true, bytes: true},
|
||||
part.predecessor),
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test computing shortest paths with invalid arguments.
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// HeapSnapshot.prototype.creationTime returns the expected time.
|
||||
|
||||
function waitForThirtyMilliseconds() {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < 30) ;
|
||||
while (Date.now() - start < 30) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can save a core dump with very deep allocation stacks and read
|
||||
// it back into a HeapSnapshot.
|
||||
@ -20,8 +21,9 @@ function run_test() {
|
||||
debuggee.eval("this.objects = []");
|
||||
debuggee.eval(
|
||||
(function recursiveAllocate(n) {
|
||||
if (n <= 0)
|
||||
if (n <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure to recurse before pushing the object so that when TCO is
|
||||
// implemented sometime in the future, it doesn't invalidate this test.
|
||||
@ -46,7 +48,7 @@ function run_test() {
|
||||
breakdown: { by: "allocationStack",
|
||||
then: { by: "count", bytes: true, count: true },
|
||||
noStack: { by: "count", bytes: true, count: true }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Keep this synchronized with `HeapSnapshot::MAX_STACK_DEPTH`!
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can describe nodes with a breakdown.
|
||||
|
||||
|
@ -1,29 +1,31 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// HeapSnapshot.prototype.takeCensus returns a value of an appropriate
|
||||
// shape. Ported from js/src/jit-tests/debug/Memory-takeCensus-01.js
|
||||
|
||||
function run_test() {
|
||||
var dbg = new Debugger;
|
||||
let dbg = new Debugger();
|
||||
|
||||
function checkProperties(census) {
|
||||
equal(typeof census, "object");
|
||||
for (prop of Object.getOwnPropertyNames(census)) {
|
||||
var desc = Object.getOwnPropertyDescriptor(census, prop);
|
||||
for (let prop of Object.getOwnPropertyNames(census)) {
|
||||
let desc = Object.getOwnPropertyDescriptor(census, prop);
|
||||
equal(desc.enumerable, true);
|
||||
equal(desc.configurable, true);
|
||||
equal(desc.writable, true);
|
||||
if (typeof desc.value === "object")
|
||||
if (typeof desc.value === "object") {
|
||||
checkProperties(desc.value);
|
||||
else
|
||||
} else {
|
||||
equal(typeof desc.value, "number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkProperties(saveHeapSnapshotAndTakeCensus(dbg));
|
||||
|
||||
var g = newGlobal();
|
||||
let g = newGlobal();
|
||||
dbg.addDebuggee(g);
|
||||
checkProperties(saveHeapSnapshotAndTakeCensus(dbg));
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// HeapSnapshot.prototype.takeCensus behaves plausibly as we allocate objects.
|
||||
//
|
||||
@ -15,12 +16,12 @@
|
||||
|
||||
function run_test() {
|
||||
// A Debugger with no debuggees had better not find anything.
|
||||
var dbg = new Debugger;
|
||||
var census0 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
let dbg = new Debugger();
|
||||
let census0 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
Census.walkCensus(census0, "census0", Census.assertAllZeros);
|
||||
|
||||
function newGlobalWithDefs() {
|
||||
var g = newGlobal();
|
||||
let g = newGlobal();
|
||||
g.eval(`
|
||||
function times(n, fn) {
|
||||
var a=[];
|
||||
@ -34,7 +35,7 @@ function run_test() {
|
||||
|
||||
// Allocate a large number of various types of objects, and check that census
|
||||
// finds them.
|
||||
var g = newGlobalWithDefs();
|
||||
let g = newGlobalWithDefs();
|
||||
dbg.addDebuggee(g);
|
||||
|
||||
g.eval("var objs = times(100, () => ({}));");
|
||||
@ -42,16 +43,16 @@ function run_test() {
|
||||
g.eval("var ars = times(400, () => []);");
|
||||
g.eval("var fns = times(800, () => () => {});");
|
||||
|
||||
var census1 = dbg.memory.takeCensus(dbg);
|
||||
let census1 = dbg.memory.takeCensus(dbg);
|
||||
Census.walkCensus(census1, "census1",
|
||||
Census.assertAllNotLessThan(
|
||||
{ "objects":
|
||||
{ "Object": { count: 100 },
|
||||
"RegExp": { count: 200 },
|
||||
"Array": { count: 400 },
|
||||
"Function": { count: 800 }
|
||||
}
|
||||
}));
|
||||
Census.assertAllNotLessThan({
|
||||
"objects": {
|
||||
"Object": { count: 100 },
|
||||
"RegExp": { count: 200 },
|
||||
"Array": { count: 400 },
|
||||
"Function": { count: 800 }
|
||||
}
|
||||
}));
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// HeapSnapshot.prototype.takeCensus behaves plausibly as we add and remove
|
||||
// debuggees.
|
||||
@ -7,27 +8,27 @@
|
||||
// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-03.js
|
||||
|
||||
function run_test() {
|
||||
var dbg = new Debugger;
|
||||
let dbg = new Debugger();
|
||||
|
||||
var census0 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
let census0 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
Census.walkCensus(census0, "census0", Census.assertAllZeros);
|
||||
|
||||
var g1 = newGlobal();
|
||||
let g1 = newGlobal();
|
||||
dbg.addDebuggee(g1);
|
||||
var census1 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
let census1 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
Census.walkCensus(census1, "census1", Census.assertAllNotLessThan(census0));
|
||||
|
||||
var g2 = newGlobal();
|
||||
let g2 = newGlobal();
|
||||
dbg.addDebuggee(g2);
|
||||
var census2 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
let census2 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
Census.walkCensus(census2, "census2", Census.assertAllNotLessThan(census1));
|
||||
|
||||
dbg.removeDebuggee(g2);
|
||||
var census3 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
let census3 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
Census.walkCensus(census3, "census3", Census.assertAllEqual(census1));
|
||||
|
||||
dbg.removeDebuggee(g1);
|
||||
var census4 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
let census4 = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
Census.walkCensus(census4, "census4", Census.assertAllEqual(census0));
|
||||
|
||||
do_test_finished();
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that HeapSnapshot.prototype.takeCensus finds GC roots that are on the
|
||||
// stack.
|
||||
@ -7,8 +8,8 @@
|
||||
// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-04.js
|
||||
|
||||
function run_test() {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
let g = newGlobal();
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
g.eval(`
|
||||
function withAllocationMarkerOnStack(f) {
|
||||
@ -22,7 +23,7 @@ function withAllocationMarkerOnStack(f) {
|
||||
equal("AllocationMarker" in saveHeapSnapshotAndTakeCensus(dbg).objects, false,
|
||||
"There shouldn't exist any allocation markers in the census.");
|
||||
|
||||
var allocationMarkerCount;
|
||||
let allocationMarkerCount;
|
||||
g.withAllocationMarkerOnStack(() => {
|
||||
const census = saveHeapSnapshotAndTakeCensus(dbg);
|
||||
allocationMarkerCount = census.objects.AllocationMarker.count;
|
||||
|
@ -6,9 +6,10 @@
|
||||
//
|
||||
// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-05.js
|
||||
|
||||
/* eslint-disable strict */
|
||||
function run_test() {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
let g = newGlobal();
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
equal("AllocationMarker" in saveHeapSnapshotAndTakeCensus(dbg).objects, false,
|
||||
"No allocation markers should exist in the census.");
|
||||
|
@ -1,88 +1,91 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Check HeapSnapshot.prototype.takeCensus handling of 'breakdown' argument.
|
||||
//
|
||||
// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-06.js
|
||||
|
||||
function run_test() {
|
||||
var Pattern = Match.Pattern;
|
||||
let Pattern = Match.Pattern;
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
let g = newGlobal();
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
Pattern({ count: Pattern.NATURAL,
|
||||
bytes: Pattern.NATURAL })
|
||||
.assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count" } }));
|
||||
|
||||
let census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: false, bytes: false } });
|
||||
let census = saveHeapSnapshotAndTakeCensus(dbg,
|
||||
{ breakdown: { by: "count", count: false, bytes: false } });
|
||||
equal("count" in census, false);
|
||||
equal("bytes" in census, false);
|
||||
|
||||
census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: true, bytes: false } });
|
||||
census = saveHeapSnapshotAndTakeCensus(dbg,
|
||||
{ breakdown: { by: "count", count: true, bytes: false } });
|
||||
equal("count" in census, true);
|
||||
equal("bytes" in census, false);
|
||||
|
||||
census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: false, bytes: true } });
|
||||
census = saveHeapSnapshotAndTakeCensus(dbg,
|
||||
{ breakdown: { by: "count", count: false, bytes: true } });
|
||||
equal("count" in census, false);
|
||||
equal("bytes" in census, true);
|
||||
|
||||
census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: true, bytes: true } });
|
||||
census = saveHeapSnapshotAndTakeCensus(dbg,
|
||||
{ breakdown: { by: "count", count: true, bytes: true } });
|
||||
equal("count" in census, true);
|
||||
equal("bytes" in census, true);
|
||||
|
||||
|
||||
// Pattern doesn't mind objects with extra properties, so we'll restrict this
|
||||
// list to the object classes we're pretty sure are going to stick around for
|
||||
// the forseeable future.
|
||||
Pattern({
|
||||
Function: { count: Pattern.NATURAL },
|
||||
Object: { count: Pattern.NATURAL },
|
||||
Debugger: { count: Pattern.NATURAL },
|
||||
Sandbox: { count: Pattern.NATURAL },
|
||||
Function: { count: Pattern.NATURAL },
|
||||
Object: { count: Pattern.NATURAL },
|
||||
Debugger: { count: Pattern.NATURAL },
|
||||
Sandbox: { count: Pattern.NATURAL },
|
||||
|
||||
// The below are all Debugger prototype objects.
|
||||
Source: { count: Pattern.NATURAL },
|
||||
Environment: { count: Pattern.NATURAL },
|
||||
Script: { count: Pattern.NATURAL },
|
||||
Memory: { count: Pattern.NATURAL },
|
||||
Frame: { count: Pattern.NATURAL }
|
||||
Source: { count: Pattern.NATURAL },
|
||||
Environment: { count: Pattern.NATURAL },
|
||||
Script: { count: Pattern.NATURAL },
|
||||
Memory: { count: Pattern.NATURAL },
|
||||
Frame: { count: Pattern.NATURAL }
|
||||
})
|
||||
.assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "objectClass" } }));
|
||||
|
||||
Pattern({
|
||||
objects: { count: Pattern.NATURAL },
|
||||
scripts: { count: Pattern.NATURAL },
|
||||
strings: { count: Pattern.NATURAL },
|
||||
other: { count: Pattern.NATURAL }
|
||||
objects: { count: Pattern.NATURAL },
|
||||
scripts: { count: Pattern.NATURAL },
|
||||
strings: { count: Pattern.NATURAL },
|
||||
other: { count: Pattern.NATURAL }
|
||||
})
|
||||
.assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "coarseType" } }));
|
||||
|
||||
// As for { by: 'objectClass' }, restrict our pattern to the types
|
||||
// we predict will stick around for a long time.
|
||||
Pattern({
|
||||
JSString: { count: Pattern.NATURAL },
|
||||
"js::Shape": { count: Pattern.NATURAL },
|
||||
JSObject: { count: Pattern.NATURAL },
|
||||
JSScript: { count: Pattern.NATURAL }
|
||||
JSString: { count: Pattern.NATURAL },
|
||||
"js::Shape": { count: Pattern.NATURAL },
|
||||
JSObject: { count: Pattern.NATURAL },
|
||||
JSScript: { count: Pattern.NATURAL }
|
||||
})
|
||||
.assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "internalType" } }));
|
||||
|
||||
|
||||
// Nested breakdowns.
|
||||
|
||||
let coarseTypePattern = {
|
||||
objects: { count: Pattern.NATURAL },
|
||||
scripts: { count: Pattern.NATURAL },
|
||||
strings: { count: Pattern.NATURAL },
|
||||
other: { count: Pattern.NATURAL }
|
||||
objects: { count: Pattern.NATURAL },
|
||||
scripts: { count: Pattern.NATURAL },
|
||||
strings: { count: Pattern.NATURAL },
|
||||
other: { count: Pattern.NATURAL }
|
||||
};
|
||||
|
||||
Pattern({
|
||||
JSString: coarseTypePattern,
|
||||
JSString: coarseTypePattern,
|
||||
"js::Shape": coarseTypePattern,
|
||||
JSObject: coarseTypePattern,
|
||||
JSScript: coarseTypePattern,
|
||||
JSObject: coarseTypePattern,
|
||||
JSScript: coarseTypePattern,
|
||||
})
|
||||
.assert(saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "internalType",
|
||||
@ -91,16 +94,16 @@ function run_test() {
|
||||
}));
|
||||
|
||||
Pattern({
|
||||
Function: { count: Pattern.NATURAL },
|
||||
Object: { count: Pattern.NATURAL },
|
||||
Debugger: { count: Pattern.NATURAL },
|
||||
Sandbox: { count: Pattern.NATURAL },
|
||||
other: coarseTypePattern
|
||||
Function: { count: Pattern.NATURAL },
|
||||
Object: { count: Pattern.NATURAL },
|
||||
Debugger: { count: Pattern.NATURAL },
|
||||
Sandbox: { count: Pattern.NATURAL },
|
||||
other: coarseTypePattern
|
||||
})
|
||||
.assert(saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: {
|
||||
by: "objectClass",
|
||||
then: { by: "count" },
|
||||
then: { by: "count" },
|
||||
other: { by: "coarseType" }
|
||||
}
|
||||
}));
|
||||
@ -109,7 +112,7 @@ function run_test() {
|
||||
objects: { count: Pattern.NATURAL, label: "object" },
|
||||
scripts: { count: Pattern.NATURAL, label: "scripts" },
|
||||
strings: { count: Pattern.NATURAL, label: "strings" },
|
||||
other: { count: Pattern.NATURAL, label: "other" }
|
||||
other: { count: Pattern.NATURAL, label: "other" }
|
||||
})
|
||||
.assert(saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: {
|
||||
@ -117,7 +120,7 @@ function run_test() {
|
||||
objects: { by: "count", label: "object" },
|
||||
scripts: { by: "count", label: "scripts" },
|
||||
strings: { by: "count", label: "strings" },
|
||||
other: { by: "count", label: "other" }
|
||||
other: { by: "count", label: "other" }
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// HeapSnapshot.prototype.takeCensus breakdown: check error handling on property
|
||||
// gets.
|
||||
@ -7,74 +8,86 @@
|
||||
// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-07.js
|
||||
|
||||
function run_test() {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
let g = newGlobal();
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { get by() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { get by() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "count", get count() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "count", get count() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "count", get bytes() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "count", get bytes() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "objectClass", get then() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "objectClass", get then() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "objectClass", get other() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "objectClass", get other() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "coarseType", get objects() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "coarseType", get objects() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "coarseType", get scripts() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "coarseType", get scripts() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "coarseType", get strings() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "coarseType", get strings() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "coarseType", get other() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "coarseType", get other() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
|
||||
|
||||
assertThrowsValue(() => {
|
||||
assertThrows(() => {
|
||||
saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "internalType", get then() { throw "ಠ_ಠ"; } }
|
||||
breakdown: { by: "internalType", get then() {
|
||||
throw Error("ಠ_ಠ");
|
||||
} }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// HeapSnapshot.prototype.takeCensus: test by: 'count' breakdown
|
||||
//
|
||||
|
@ -1,20 +1,21 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// HeapSnapshot.prototype.takeCensus: by: allocationStack breakdown
|
||||
//
|
||||
// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-09.js
|
||||
|
||||
function run_test() {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
let g = newGlobal();
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
g.eval(` // 1
|
||||
var log = []; // 2
|
||||
function f() { log.push(allocationMarker()); } // 3
|
||||
function g() { f(); } // 4
|
||||
function h() { f(); } // 5
|
||||
`); // 6
|
||||
`);
|
||||
|
||||
// Create one allocationMarker with tracking turned off,
|
||||
// so it will have no associated stack.
|
||||
@ -22,7 +23,7 @@ function run_test() {
|
||||
|
||||
dbg.memory.allocationSamplingProbability = 1;
|
||||
|
||||
for ([func, n] of [[g.f, 20], [g.g, 10], [g.h, 5]]) {
|
||||
for (let [func, n] of [[g.f, 20], [g.g, 10], [g.h, 5]]) {
|
||||
for (let i = 0; i < n; i++) {
|
||||
dbg.memory.trackingAllocationSites = true;
|
||||
// All allocations of allocationMarker occur with this line as the oldest
|
||||
@ -32,17 +33,19 @@ function run_test() {
|
||||
}
|
||||
}
|
||||
|
||||
let census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "objectClass",
|
||||
then: { by: "allocationStack",
|
||||
then: { by: "count",
|
||||
label: "haz stack"
|
||||
},
|
||||
noStack: { by: "count",
|
||||
label: "no haz stack"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let census = saveHeapSnapshotAndTakeCensus(
|
||||
dbg, { breakdown: {
|
||||
by: "objectClass",
|
||||
then: {
|
||||
by: "allocationStack",
|
||||
then: { by: "count", label: "haz stack"},
|
||||
noStack: {
|
||||
by: "count",
|
||||
label: "no haz stack"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let map = census.AllocationMarker;
|
||||
ok(map instanceof Map, "Should be a Map instance");
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Check byte counts produced by takeCensus.
|
||||
//
|
||||
@ -25,7 +26,7 @@ function run_test() {
|
||||
for (let i = 0; i < 10; i++) // 5
|
||||
objs.push(allocationMarker()); // 6
|
||||
} // 7
|
||||
`); // 8
|
||||
`);
|
||||
|
||||
dbg.memory.allocationSamplingProbability = 1;
|
||||
dbg.memory.trackingAllocationSites = true;
|
||||
@ -35,7 +36,7 @@ function run_test() {
|
||||
census = saveHeapSnapshotAndTakeCensus(dbg, {
|
||||
breakdown: { by: "objectClass",
|
||||
then: { by: "allocationStack" }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let seen = 0;
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that Debugger.Memory.prototype.takeCensus and
|
||||
// HeapSnapshot.prototype.takeCensus return the same data for the same heap
|
||||
@ -14,7 +15,7 @@ function doLiveAndOfflineCensus(g, dbg, opts) {
|
||||
this.markers.push(allocationMarker()); // 4
|
||||
} // 5
|
||||
}()); // 6
|
||||
`); // 7
|
||||
`);
|
||||
dbg.memory.trackingAllocationSites = false;
|
||||
|
||||
return {
|
||||
@ -24,8 +25,8 @@ function doLiveAndOfflineCensus(g, dbg, opts) {
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
let g = newGlobal();
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
g.eval("this.markers = []");
|
||||
const markerSize = byteSize(allocationMarker());
|
||||
@ -36,7 +37,7 @@ function run_test() {
|
||||
let prevCount = 0;
|
||||
let prevBytes = 0;
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { live, offline } = doLiveAndOfflineCensus(g, dbg, {
|
||||
breakdown: { by: "objectClass",
|
||||
then: { by: "count"} }
|
||||
@ -96,9 +97,8 @@ function run_test() {
|
||||
return -1;
|
||||
} else if (a[0] > b[0]) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
liveEntries.sort(sortEntries);
|
||||
offlineEntries.sort(sortEntries);
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that when we take a census and get a bucket list of ids that matched the
|
||||
// given category, that the returned ids are all in the snapshot and their
|
||||
|
@ -2,7 +2,7 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that we can read core dumps into HeapSnapshot instances.
|
||||
|
||||
/* eslint-disable strict */
|
||||
if (typeof Debugger != "function") {
|
||||
const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
|
||||
addDebuggerToGlobal(this);
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that we can save a core dump with allocation stacks and read it back
|
||||
// into a HeapSnapshot.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user