Merge mozilla-central to autoland

This commit is contained in:
Carsten "Tomcat" Book 2017-03-14 14:27:38 +01:00
commit 8fd069a1f2
163 changed files with 1600 additions and 1093 deletions

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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.

View File

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

View File

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

View File

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

View File

@ -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]

View File

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

View File

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

View File

@ -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,

View File

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

View File

@ -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]

View File

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

View File

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

View File

@ -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

View File

@ -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,

View File

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

View File

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

Binary file not shown.

View File

@ -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]

View File

@ -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");
});

View File

@ -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");
}
});

View File

@ -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]

View File

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

View File

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

View File

@ -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 = {
}
}
};

View File

@ -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 };

View File

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

View File

@ -16,7 +16,6 @@ DevToolsModules(
'eye-dropper.js',
'geometry-editor.js',
'measuring-tool.js',
'rect.js',
'rulers.js',
'selector.js',
'simple-outline.js'

View File

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

View File

@ -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" });

View File

@ -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);
};
/**

View File

@ -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}`);
}

View File

@ -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}`;
};

View File

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

View 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,
}
};

View File

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

View File

@ -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.");

View File

@ -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>

View File

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

View File

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

View File

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

View File

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

View File

@ -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",

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -69,7 +69,8 @@ const expected = [
}
}),
makeTestDominatorTreeNode({ nodeId: 3000,
makeTestDominatorTreeNode({
nodeId: 3000,
shortestPaths: {
nodes: [
{ id: 3000, label: ["SomeType-3000"] },

View File

@ -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.

View File

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

View File

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

View File

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

View File

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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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) {

View File

@ -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]);
}

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

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

View File

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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

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

View File

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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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),

View File

@ -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.

View File

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

View File

@ -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`!

View File

@ -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.

View File

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

View File

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

View File

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

View File

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

View File

@ -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.");

View File

@ -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" }
}
}));

View File

@ -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("ಠ_ಠ");
} }
});
}, "ಠ_ಠ");

View File

@ -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
//

View File

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

View File

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

View File

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

View File

@ -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

View File

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

View File

@ -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