зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
Коммит
19b5d2e16c
|
@ -1436,9 +1436,6 @@ var gMainPane = {
|
|||
handleEvent(aEvent) {
|
||||
if (aEvent.type == "unload") {
|
||||
this.destroy();
|
||||
if (AppConstants.MOZ_UPDATER) {
|
||||
onUnload();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -114,7 +114,8 @@ bool nsJSPrincipals::ReadPrincipals(JSContext* aCx,
|
|||
|
||||
if (!(tag == SCTAG_DOM_NULL_PRINCIPAL || tag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
|
||||
tag == SCTAG_DOM_CONTENT_PRINCIPAL ||
|
||||
tag == SCTAG_DOM_EXPANDED_PRINCIPAL)) {
|
||||
tag == SCTAG_DOM_EXPANDED_PRINCIPAL ||
|
||||
tag == SCTAG_DOM_WORKER_PRINCIPAL)) {
|
||||
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return false;
|
||||
}
|
||||
|
@ -286,6 +287,19 @@ static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader, uint32_t aTag,
|
|||
return true;
|
||||
}
|
||||
|
||||
static StaticRefPtr<nsIPrincipal> sActiveWorkerPrincipal;
|
||||
|
||||
nsJSPrincipals::AutoSetActiveWorkerPrincipal::AutoSetActiveWorkerPrincipal
|
||||
(nsIPrincipal* aPrincipal) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_RELEASE_ASSERT(!sActiveWorkerPrincipal);
|
||||
sActiveWorkerPrincipal = aPrincipal;
|
||||
}
|
||||
|
||||
nsJSPrincipals::AutoSetActiveWorkerPrincipal::~AutoSetActiveWorkerPrincipal() {
|
||||
sActiveWorkerPrincipal = nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool nsJSPrincipals::ReadKnownPrincipalType(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
|
@ -294,13 +308,26 @@ bool nsJSPrincipals::ReadKnownPrincipalType(JSContext* aCx,
|
|||
MOZ_ASSERT(aTag == SCTAG_DOM_NULL_PRINCIPAL ||
|
||||
aTag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
|
||||
aTag == SCTAG_DOM_CONTENT_PRINCIPAL ||
|
||||
aTag == SCTAG_DOM_EXPANDED_PRINCIPAL);
|
||||
aTag == SCTAG_DOM_EXPANDED_PRINCIPAL ||
|
||||
aTag == SCTAG_DOM_WORKER_PRINCIPAL);
|
||||
|
||||
if (NS_WARN_IF(!NS_IsMainThread())) {
|
||||
xpc::Throw(aCx, NS_ERROR_UNCATCHABLE_EXCEPTION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_WORKER_PRINCIPAL) {
|
||||
// When reading principals which were written on a worker thread, we need to
|
||||
// know the principal of the worker which did the write.
|
||||
if (!sActiveWorkerPrincipal) {
|
||||
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return false;
|
||||
}
|
||||
RefPtr<nsJSPrincipals> retval = get(sActiveWorkerPrincipal);
|
||||
retval.forget(aOutPrincipals);
|
||||
return true;
|
||||
}
|
||||
|
||||
PrincipalInfo info;
|
||||
if (!ReadPrincipalInfo(aReader, aTag, info)) {
|
||||
return false;
|
||||
|
|
|
@ -24,6 +24,17 @@ class nsJSPrincipals : public nsIPrincipal, public JSPrincipals {
|
|||
uint32_t aTag,
|
||||
JSPrincipals** aOutPrincipals);
|
||||
|
||||
// This class is used on the main thread to specify which principal to use
|
||||
// when reading principals data that was set on a DOM worker thread.
|
||||
// DOM workers do not use principals from Gecko's point of view, and any
|
||||
// JSPrincipals used internally will be a shared singleton object. When that
|
||||
// singleton is written out and later read on the main thread, we substitute
|
||||
// the principal specified with this class.
|
||||
struct MOZ_RAII AutoSetActiveWorkerPrincipal {
|
||||
explicit AutoSetActiveWorkerPrincipal(nsIPrincipal* aPrincipal);
|
||||
~AutoSetActiveWorkerPrincipal();
|
||||
};
|
||||
|
||||
bool write(JSContext* aCx, JSStructuredCloneWriter* aWriter) final;
|
||||
|
||||
/*
|
||||
|
|
|
@ -37,7 +37,7 @@ export function removeEditor() {
|
|||
}
|
||||
|
||||
function getCodeMirror() {
|
||||
return editor && editor.codeMirror;
|
||||
return editor && editor.hasCodeMirror ? editor.codeMirror : null;
|
||||
}
|
||||
|
||||
export function startOperation() {
|
||||
|
|
|
@ -9,6 +9,9 @@ import { isDevelopment } from "devtools-environment";
|
|||
import Services from "devtools-services";
|
||||
import { asyncStoreHelper } from "./asyncStoreHelper";
|
||||
|
||||
// Schema version to bump when the async store format has changed incompatibly
|
||||
// and old stores should be cleared. This needs to match the prefs schema
|
||||
// version in devtools/client/preferences/debugger.js.
|
||||
const prefsSchemaVersion = "1.0.9";
|
||||
const pref = Services.pref;
|
||||
|
||||
|
@ -43,7 +46,7 @@ if (isDevelopment()) {
|
|||
pref("devtools.debugger.file-search-regex-match", false);
|
||||
pref("devtools.debugger.project-directory-root", "");
|
||||
pref("devtools.debugger.map-scopes-enabled", false);
|
||||
pref("devtools.debugger.prefs-schema-version", "1.0.1");
|
||||
pref("devtools.debugger.prefs-schema-version", prefsSchemaVersion);
|
||||
pref("devtools.debugger.skip-pausing", false);
|
||||
pref("devtools.debugger.features.workers", true);
|
||||
pref("devtools.debugger.features.async-stepping", true);
|
||||
|
|
|
@ -789,3 +789,4 @@ skip-if = true
|
|||
[browser_dbg-event-handler.js]
|
||||
[browser_dbg-eval-throw.js]
|
||||
[browser_dbg-sourceURL-breakpoint.js]
|
||||
[browser_dbg-old-breakpoint.js]
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that we show a breakpoint in the UI when there is an old pending
|
||||
// breakpoint with an invalid original location.
|
||||
add_task(async function() {
|
||||
clearDebuggerPreferences();
|
||||
|
||||
const pending = {
|
||||
bp1: {
|
||||
location: {
|
||||
sourceId: "",
|
||||
sourceUrl: EXAMPLE_URL + "nowhere2.js",
|
||||
line: 5
|
||||
},
|
||||
generatedLocation: {
|
||||
sourceUrl: EXAMPLE_URL + "simple1.js",
|
||||
line: 4
|
||||
},
|
||||
options: {},
|
||||
disabled: false
|
||||
},
|
||||
bp2: {
|
||||
location: {
|
||||
sourceId: "",
|
||||
sourceUrl: EXAMPLE_URL + "nowhere.js",
|
||||
line: 5
|
||||
},
|
||||
generatedLocation: {
|
||||
sourceUrl: EXAMPLE_URL + "simple3.js",
|
||||
line: 2
|
||||
},
|
||||
options: {},
|
||||
disabled: false
|
||||
},
|
||||
};
|
||||
asyncStorage.setItem("debugger.pending-breakpoints", pending);
|
||||
|
||||
const toolbox = await openNewTabAndToolbox(EXAMPLE_URL + "doc-scripts.html", "jsdebugger");
|
||||
const dbg = createDebuggerContext(toolbox);
|
||||
|
||||
// Pending breakpoints are installed asynchronously, keep invoking the entry
|
||||
// function until the debugger pauses.
|
||||
await waitUntil(() => {
|
||||
invokeInTab("main");
|
||||
return isPaused(dbg);
|
||||
});
|
||||
|
||||
ok(true, "paused at unmapped breakpoint");
|
||||
await waitForState(dbg, state => dbg.selectors.getBreakpointCount(state) == 2);
|
||||
ok(true, "unmapped breakpoints shown in UI");
|
||||
});
|
||||
|
||||
// Test that if we show a breakpoint with an old generated location, it is
|
||||
// removed after we load the original source and find the new generated
|
||||
// location.
|
||||
add_task(async function() {
|
||||
clearDebuggerPreferences();
|
||||
|
||||
const pending = {
|
||||
bp1: {
|
||||
location: {
|
||||
sourceId: "",
|
||||
sourceUrl: "webpack:///entry.js",
|
||||
line: 15,
|
||||
column: 0
|
||||
},
|
||||
generatedLocation: {
|
||||
sourceUrl: EXAMPLE_URL + "sourcemaps/bundle.js",
|
||||
line: 47,
|
||||
column: 16
|
||||
},
|
||||
astLocation: {},
|
||||
options: {},
|
||||
disabled: false
|
||||
},
|
||||
};
|
||||
asyncStorage.setItem("debugger.pending-breakpoints", pending);
|
||||
|
||||
const toolbox = await openNewTabAndToolbox(EXAMPLE_URL + "doc-sourcemaps.html", "jsdebugger");
|
||||
const dbg = createDebuggerContext(toolbox);
|
||||
|
||||
await waitForState(dbg, state => {
|
||||
const bps = dbg.selectors.getBreakpointsList(state);
|
||||
return bps.length == 1
|
||||
&& bps[0].location.sourceUrl.includes("entry.js")
|
||||
&& bps[0].location.line == 15;
|
||||
});
|
||||
ok(true, "removed old breakpoint during sync");
|
||||
});
|
|
@ -19,7 +19,8 @@ pref("devtools.debugger.auto-black-box", true);
|
|||
pref("devtools.debugger.workers", false);
|
||||
|
||||
// The default Debugger UI settings
|
||||
pref("devtools.debugger.prefs-schema-version", "1.0.0");
|
||||
// This schema version needs to match that in devtools/client/debugger/src/utils/prefs.js.
|
||||
pref("devtools.debugger.prefs-schema-version", "1.0.9");
|
||||
pref("devtools.debugger.ui.panes-workers-and-sources-width", 200);
|
||||
pref("devtools.debugger.ui.panes-instruments-width", 300);
|
||||
pref("devtools.debugger.ui.panes-visible-on-startup", false);
|
||||
|
|
|
@ -262,6 +262,13 @@ Editor.prototype = {
|
|||
return editors.get(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return whether there is a CodeMirror instance associated with this Editor.
|
||||
*/
|
||||
get hasCodeMirror() {
|
||||
return editors.has(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends the current Editor instance to the element specified by
|
||||
* 'el'. You can also provide your own iframe to host the editor as
|
||||
|
|
|
@ -205,7 +205,7 @@ stubPreparedMessages.set(`throw ""`, new ConsoleMessage({
|
|||
"category": "content javascript",
|
||||
"messageText": "uncaught exception: ",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"uncaught exception: \",\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null,\"private\":false,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html\",\"sourceId\":\"server1.conn0.child1/source24\",\"lineNumber\":1,\"columnNumber\":1,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js line 59 > eval\",\"sourceId\":null,\"lineNumber\":7,\"columnNumber\":31,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js\",\"sourceId\":null,\"lineNumber\":60,\"columnNumber\":29,\"functionName\":null}]}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html\",\"sourceId\":null,\"line\":1,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"uncaught exception: \",\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null,\"private\":false,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html\",\"sourceId\":\"server1.conn0.child1/source24\",\"lineNumber\":1,\"columnNumber\":1,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js line 59 > eval\",\"sourceId\":null,\"lineNumber\":7,\"columnNumber\":31,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js\",\"sourceId\":null,\"lineNumber\":60,\"columnNumber\":29,\"functionName\":null}]}",
|
||||
"stacktrace": [
|
||||
{
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html",
|
||||
|
@ -229,7 +229,12 @@ stubPreparedMessages.set(`throw ""`, new ConsoleMessage({
|
|||
"functionName": null
|
||||
}
|
||||
],
|
||||
"frame": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html",
|
||||
"sourceId": null,
|
||||
"line": 1,
|
||||
"column": 1
|
||||
},
|
||||
"groupId": null,
|
||||
"errorMessageName": "JSMSG_UNCAUGHT_EXCEPTION",
|
||||
"userProvidedStyles": null,
|
||||
|
@ -252,7 +257,7 @@ stubPreparedMessages.set(`throw "tomato"`, new ConsoleMessage({
|
|||
"category": "content javascript",
|
||||
"messageText": "uncaught exception: tomato",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"uncaught exception: tomato\",\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null,\"private\":false,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html\",\"sourceId\":\"server1.conn0.child1/source24\",\"lineNumber\":1,\"columnNumber\":1,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js line 59 > eval\",\"sourceId\":null,\"lineNumber\":7,\"columnNumber\":31,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js\",\"sourceId\":null,\"lineNumber\":60,\"columnNumber\":29,\"functionName\":null}]}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html\",\"sourceId\":null,\"line\":1,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"uncaught exception: tomato\",\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null,\"private\":false,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html\",\"sourceId\":\"server1.conn0.child1/source24\",\"lineNumber\":1,\"columnNumber\":1,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js line 59 > eval\",\"sourceId\":null,\"lineNumber\":7,\"columnNumber\":31,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js\",\"sourceId\":null,\"lineNumber\":60,\"columnNumber\":29,\"functionName\":null}]}",
|
||||
"stacktrace": [
|
||||
{
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html",
|
||||
|
@ -276,7 +281,12 @@ stubPreparedMessages.set(`throw "tomato"`, new ConsoleMessage({
|
|||
"functionName": null
|
||||
}
|
||||
],
|
||||
"frame": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html",
|
||||
"sourceId": null,
|
||||
"line": 1,
|
||||
"column": 1
|
||||
},
|
||||
"groupId": null,
|
||||
"errorMessageName": "JSMSG_UNCAUGHT_EXCEPTION",
|
||||
"userProvidedStyles": null,
|
||||
|
@ -459,11 +469,11 @@ stubPackets.set(`throw ""`, {
|
|||
"pageError": {
|
||||
"errorMessage": "uncaught exception: ",
|
||||
"errorMessageName": "JSMSG_UNCAUGHT_EXCEPTION",
|
||||
"sourceName": "",
|
||||
"sourceName": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html",
|
||||
"sourceId": null,
|
||||
"lineText": "",
|
||||
"lineNumber": 0,
|
||||
"columnNumber": 0,
|
||||
"lineNumber": 1,
|
||||
"columnNumber": 1,
|
||||
"category": "content javascript",
|
||||
"innerWindowID": 6442450949,
|
||||
"timeStamp": 1517942398629,
|
||||
|
@ -507,11 +517,11 @@ stubPackets.set(`throw "tomato"`, {
|
|||
"pageError": {
|
||||
"errorMessage": "uncaught exception: tomato",
|
||||
"errorMessageName": "JSMSG_UNCAUGHT_EXCEPTION",
|
||||
"sourceName": "",
|
||||
"sourceName": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-console-api.html",
|
||||
"sourceId": null,
|
||||
"lineText": "",
|
||||
"lineNumber": 0,
|
||||
"columnNumber": 0,
|
||||
"lineNumber": 1,
|
||||
"columnNumber": 1,
|
||||
"category": "content javascript",
|
||||
"innerWindowID": 6442450949,
|
||||
"timeStamp": 1517942398637,
|
||||
|
|
|
@ -45,6 +45,9 @@ support-files =
|
|||
test-dynamic-import.html
|
||||
test-dynamic-import.js
|
||||
test-error.html
|
||||
test-error-worker.html
|
||||
test-error-worker.js
|
||||
test-error-worker2.js
|
||||
test-eval-in-stackframe.html
|
||||
test-eval-sources.html
|
||||
test-external-script-errors.html
|
||||
|
@ -408,3 +411,4 @@ tags = trackingprotection
|
|||
[browser_webconsole_warning_groups_outside_console_group.js]
|
||||
[browser_webconsole_warning_groups.js]
|
||||
[browser_webconsole_websocket.js]
|
||||
[browser_webconsole_worker_error.js]
|
||||
|
|
|
@ -15,19 +15,6 @@ const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
|
|||
add_task(async function() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
await checkMessage("hello", 14, 3);
|
||||
await checkMessage("1,2,3", 20, 1);
|
||||
|
||||
async function checkMessage(text, line, numFrames) {
|
||||
const msgNode = await waitFor(() => findMessage(hud, text));
|
||||
ok(!msgNode.classList.contains("open"), `Error logged not expanded`);
|
||||
|
||||
const button = msgNode.querySelector(".collapse-button");
|
||||
button.click();
|
||||
|
||||
const framesNode = await waitFor(() => msgNode.querySelector(".frames"));
|
||||
const frameNodes = framesNode.querySelectorAll(".frame");
|
||||
ok(frameNodes.length == numFrames);
|
||||
ok(frameNodes[0].querySelector(".line").textContent == "" + line);
|
||||
}
|
||||
await checkMessageStack(hud, "hello", [14, 10, 7]);
|
||||
await checkMessageStack(hud, "1,2,3", [20]);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/ */
|
||||
|
||||
// Tests that throwing uncaught errors and primitive values in workers shows a
|
||||
// stack in the console.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
|
||||
"test/mochitest/test-error-worker.html";
|
||||
|
||||
add_task(async function() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
await checkMessageStack(hud, "hello", [11, 3]);
|
||||
await checkMessageStack(hud, "there", [14, 3]);
|
||||
await checkMessageStack(hud, "dom", [16, 3]);
|
||||
await checkMessageStack(hud, "worker2", [6, 3]);
|
||||
});
|
|
@ -1320,3 +1320,28 @@ function checkConsoleOutputForWarningGroup(hud, expectedMessages) {
|
|||
`the expected "${expectedMessage}" content - "${message.textContent.trim()}"`);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that there is a message with the specified text that has the specified
|
||||
* stack information.
|
||||
* @param {WebConsole} hud
|
||||
* @param {string} text
|
||||
* message substring to look for
|
||||
* @param {Array<number>} frameLines
|
||||
* line numbers of the frames expected in the stack
|
||||
*/
|
||||
async function checkMessageStack(hud, text, frameLines) {
|
||||
const msgNode = await waitFor(() => findMessage(hud, text));
|
||||
ok(!msgNode.classList.contains("open"), `Error logged not expanded`);
|
||||
|
||||
const button = msgNode.querySelector(".collapse-button");
|
||||
button.click();
|
||||
|
||||
const framesNode = await waitFor(() => msgNode.querySelector(".frames"));
|
||||
const frameNodes = framesNode.querySelectorAll(".frame");
|
||||
ok(frameNodes.length == frameLines.length, `Found ${frameLines.length} frames`);
|
||||
for (let i = 0; i < frameLines.length; i++) {
|
||||
ok(frameNodes[i].querySelector(".line").textContent == "" + frameLines[i],
|
||||
`Found line ${frameLines[i]} for frame #${i}`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<script>
|
||||
"use strict";
|
||||
var w = new Worker("test-error-worker.js");
|
||||
w.postMessage(1);
|
||||
w.postMessage(2);
|
||||
w.postMessage(3);
|
||||
</script>
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
|
||||
self.addEventListener("message", ({ data }) => foo(data));
|
||||
|
||||
var w = new Worker("test-error-worker2.js");
|
||||
w.postMessage({});
|
||||
|
||||
function foo(data) {
|
||||
switch (data) {
|
||||
case 1:
|
||||
throw new Error("hello");
|
||||
case 2:
|
||||
/* eslint-disable */
|
||||
throw "there";
|
||||
case 3:
|
||||
throw new DOMException("dom");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
self.addEventListener("message", ({ data }) => foo(data));
|
||||
|
||||
function foo(data) {
|
||||
throw new Error("worker2");
|
||||
}
|
|
@ -1515,15 +1515,30 @@ WebConsoleActor.prototype =
|
|||
}
|
||||
}
|
||||
|
||||
// If there is no location information in the error but we have a stack,
|
||||
// fill in the location with the first frame on the stack.
|
||||
let {
|
||||
sourceName,
|
||||
sourceId,
|
||||
lineNumber,
|
||||
columnNumber,
|
||||
} = pageError;
|
||||
if (!sourceName && !sourceId && !lineNumber && !columnNumber && stack) {
|
||||
sourceName = stack[0].filename;
|
||||
sourceId = stack[0].sourceId;
|
||||
lineNumber = stack[0].lineNumber;
|
||||
columnNumber = stack[0].columnNumber;
|
||||
}
|
||||
|
||||
return {
|
||||
errorMessage: this._createStringGrip(pageError.errorMessage),
|
||||
errorMessageName: pageError.errorMessageName,
|
||||
exceptionDocURL: ErrorDocs.GetURL(pageError),
|
||||
sourceName: pageError.sourceName,
|
||||
sourceId: this.getActorIdForInternalSourceId(pageError.sourceId),
|
||||
lineText: lineText,
|
||||
lineNumber: pageError.lineNumber,
|
||||
columnNumber: pageError.columnNumber,
|
||||
sourceName,
|
||||
sourceId: this.getActorIdForInternalSourceId(sourceId),
|
||||
lineText,
|
||||
lineNumber,
|
||||
columnNumber,
|
||||
category: pageError.category,
|
||||
innerWindowID: pageError.innerWindowID,
|
||||
timeStamp: pageError.timeStamp,
|
||||
|
|
|
@ -72,7 +72,12 @@ enum StructuredCloneTags {
|
|||
|
||||
SCTAG_DOM_MAX,
|
||||
|
||||
SCTAG_DOM_STRUCTURED_CLONE_TESTER
|
||||
SCTAG_DOM_STRUCTURED_CLONE_TESTER,
|
||||
|
||||
// Principal written out by worker threads when serializing objects. When
|
||||
// reading on the main thread this principal will be converted to a normal
|
||||
// principal object using nsJSPrincipals::AutoSetActiveWorkerPrincipal.
|
||||
SCTAG_DOM_WORKER_PRINCIPAL
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -7687,7 +7687,7 @@ nsresult QuotaClient::InitOrigin(PersistenceType aPersistenceType,
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(usage >= 0);
|
||||
MOZ_ASSERT(usage >= 0);
|
||||
|
||||
InitUsageForOrigin(aOrigin, usage);
|
||||
|
||||
|
|
|
@ -528,7 +528,7 @@ void AutoJSAPI::ReportException() {
|
|||
// because it may want to put it in its error events and has no other way
|
||||
// to get hold of it. After we invoke ReportError, clear the exception on
|
||||
// cx(), just in case ReportError didn't.
|
||||
JS_SetPendingException(cx(), exn);
|
||||
JS::SetPendingExceptionAndStack(cx(), exn, exnStack);
|
||||
worker->ReportError(cx(), jsReport.toStringResult(), jsReport.report());
|
||||
ClearException();
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct WorkerPrincipal final : public JSPrincipals {
|
||||
bool write(JSContext* aCx, JSStructuredCloneWriter* aWriter) override {
|
||||
MOZ_CRASH("WorkerPrincipal::write not implemented");
|
||||
return false;
|
||||
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_WORKER_PRINCIPAL, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -437,10 +437,16 @@ void WorkerDebugger::ReportErrorToDebuggerOnMainThread(
|
|||
listeners[index]->OnError(aFilename, aLineno, aMessage);
|
||||
}
|
||||
|
||||
WorkerErrorReport report;
|
||||
// We need a JSContext to be able to read any stack associated with the error.
|
||||
// This will not run any scripts.
|
||||
AutoJSAPI jsapi;
|
||||
DebugOnly<bool> ok = jsapi.Init(xpc::UnprivilegedJunkScope());
|
||||
MOZ_ASSERT(ok, "UnprivilegedJunkScope should exist");
|
||||
|
||||
WorkerErrorReport report(nullptr);
|
||||
report.mMessage = aMessage;
|
||||
report.mFilename = aFilename;
|
||||
WorkerErrorReport::LogErrorToConsole(report, 0);
|
||||
WorkerErrorReport::LogErrorToConsole(jsapi.cx(), report, 0);
|
||||
}
|
||||
|
||||
RefPtr<PerformanceInfoPromise> WorkerDebugger::ReportPerformanceInfo() {
|
||||
|
|
|
@ -28,135 +28,12 @@ namespace dom {
|
|||
namespace {
|
||||
|
||||
class ReportErrorRunnable final : public WorkerDebuggeeRunnable {
|
||||
WorkerErrorReport mReport;
|
||||
UniquePtr<WorkerErrorReport> mReport;
|
||||
|
||||
public:
|
||||
// aWorkerPrivate is the worker thread we're on (or the main thread, if null)
|
||||
// aTarget is the worker object that we are going to fire an error at
|
||||
// (if any).
|
||||
static void ReportError(
|
||||
JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aFireAtScope,
|
||||
DOMEventTargetHelper* aTarget, const WorkerErrorReport& aReport,
|
||||
uint64_t aInnerWindowId,
|
||||
JS::Handle<JS::Value> aException = JS::NullHandleValue) {
|
||||
if (aWorkerPrivate) {
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
} else {
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
// We should not fire error events for warnings but instead make sure that
|
||||
// they show up in the error console.
|
||||
if (!JSREPORT_IS_WARNING(aReport.mFlags)) {
|
||||
// First fire an ErrorEvent at the worker.
|
||||
RootedDictionary<ErrorEventInit> init(aCx);
|
||||
|
||||
if (aReport.mMutedError) {
|
||||
init.mMessage.AssignLiteral("Script error.");
|
||||
} else {
|
||||
init.mMessage = aReport.mMessage;
|
||||
init.mFilename = aReport.mFilename;
|
||||
init.mLineno = aReport.mLineNumber;
|
||||
init.mError = aException;
|
||||
}
|
||||
|
||||
init.mCancelable = true;
|
||||
init.mBubbles = false;
|
||||
|
||||
if (aTarget) {
|
||||
RefPtr<ErrorEvent> event =
|
||||
ErrorEvent::Constructor(aTarget, NS_LITERAL_STRING("error"), init);
|
||||
event->SetTrusted(true);
|
||||
|
||||
bool defaultActionEnabled =
|
||||
aTarget->DispatchEvent(*event, CallerType::System, IgnoreErrors());
|
||||
if (!defaultActionEnabled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now fire an event at the global object, but don't do that if the error
|
||||
// code is too much recursion and this is the same script threw the error.
|
||||
// XXXbz the interaction of this with worker errors seems kinda broken.
|
||||
// An overrecursion in the debugger or debugger sandbox will get turned
|
||||
// into an error event on our parent worker!
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks making this
|
||||
// better.
|
||||
if (aFireAtScope &&
|
||||
(aTarget || aReport.mErrorNumber != JSMSG_OVER_RECURSED)) {
|
||||
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
NS_ASSERTION(global, "This should never be null!");
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
|
||||
if (aWorkerPrivate) {
|
||||
WorkerGlobalScope* globalScope = nullptr;
|
||||
UNWRAP_OBJECT(WorkerGlobalScope, &global, globalScope);
|
||||
|
||||
if (!globalScope) {
|
||||
WorkerDebuggerGlobalScope* globalScope = nullptr;
|
||||
UNWRAP_OBJECT(WorkerDebuggerGlobalScope, &global, globalScope);
|
||||
|
||||
MOZ_ASSERT_IF(globalScope,
|
||||
globalScope->GetWrapperPreserveColor() == global);
|
||||
if (globalScope || IsWorkerDebuggerSandbox(global)) {
|
||||
aWorkerPrivate->ReportErrorToDebugger(
|
||||
aReport.mFilename, aReport.mLineNumber, aReport.mMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(SimpleGlobalObject::SimpleGlobalType(global) ==
|
||||
SimpleGlobalObject::GlobalType::BindingDetail);
|
||||
// XXXbz We should really log this to console, but unwinding out of
|
||||
// this stuff without ending up firing any events is ... hard. Just
|
||||
// return for now.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks
|
||||
// making this better.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(globalScope->GetWrapperPreserveColor() == global);
|
||||
|
||||
RefPtr<ErrorEvent> event = ErrorEvent::Constructor(
|
||||
aTarget, NS_LITERAL_STRING("error"), init);
|
||||
event->SetTrusted(true);
|
||||
|
||||
if (NS_FAILED(EventDispatcher::DispatchDOMEvent(
|
||||
ToSupports(globalScope), nullptr, event, nullptr, &status))) {
|
||||
NS_WARNING("Failed to dispatch worker thread error event!");
|
||||
status = nsEventStatus_eIgnore;
|
||||
}
|
||||
} else if (nsGlobalWindowInner* win = xpc::WindowOrNull(global)) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!win->HandleScriptError(init, &status)) {
|
||||
NS_WARNING("Failed to dispatch main thread error event!");
|
||||
status = nsEventStatus_eIgnore;
|
||||
}
|
||||
}
|
||||
|
||||
// Was preventDefault() called?
|
||||
if (status == nsEventStatus_eConsumeNoDefault) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now fire a runnable to do the same on the parent's thread if we can.
|
||||
if (aWorkerPrivate) {
|
||||
RefPtr<ReportErrorRunnable> runnable =
|
||||
new ReportErrorRunnable(aWorkerPrivate, aReport);
|
||||
runnable->Dispatch();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise log an error to the error console.
|
||||
WorkerErrorReport::LogErrorToConsole(aReport, aInnerWindowId);
|
||||
}
|
||||
|
||||
ReportErrorRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
const WorkerErrorReport& aReport)
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate), mReport(aReport) {}
|
||||
UniquePtr<WorkerErrorReport> aReport)
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate), mReport(std::move(aReport)) {}
|
||||
|
||||
private:
|
||||
virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||
|
@ -194,7 +71,7 @@ class ReportErrorRunnable final : public WorkerDebuggeeRunnable {
|
|||
|
||||
if (aWorkerPrivate->IsSharedWorker()) {
|
||||
aWorkerPrivate->GetRemoteWorkerController()
|
||||
->ErrorPropagationOnMainThread(&mReport,
|
||||
->ErrorPropagationOnMainThread(mReport.get(),
|
||||
/* isErrorEvent */ true);
|
||||
return true;
|
||||
}
|
||||
|
@ -207,10 +84,10 @@ class ReportErrorRunnable final : public WorkerDebuggeeRunnable {
|
|||
if (swm) {
|
||||
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
|
||||
aWorkerPrivate->ServiceWorkerScope(),
|
||||
aWorkerPrivate->ScriptURL(), mReport.mMessage,
|
||||
mReport.mFilename, mReport.mLine,
|
||||
mReport.mLineNumber, mReport.mColumnNumber,
|
||||
mReport.mFlags, mReport.mExnType);
|
||||
aWorkerPrivate->ScriptURL(), mReport->mMessage,
|
||||
mReport->mFilename, mReport->mLine,
|
||||
mReport->mLineNumber, mReport->mColumnNumber,
|
||||
mReport->mFlags, mReport->mExnType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -230,8 +107,9 @@ class ReportErrorRunnable final : public WorkerDebuggeeRunnable {
|
|||
return true;
|
||||
}
|
||||
|
||||
ReportError(aCx, parent, fireAtScope,
|
||||
aWorkerPrivate->ParentEventTargetRef(), mReport, innerWindowId);
|
||||
WorkerErrorReport::ReportError(aCx, parent, fireAtScope,
|
||||
aWorkerPrivate->ParentEventTargetRef(),
|
||||
std::move(mReport), innerWindowId);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -321,6 +199,19 @@ void WorkerErrorNote::AssignErrorNote(JSErrorNotes::Note* aNote) {
|
|||
xpc::ErrorNote::ErrorNoteToMessageString(aNote, mMessage);
|
||||
}
|
||||
|
||||
WorkerErrorReport::WorkerErrorReport(WorkerPrivate* aWorkerPrivate)
|
||||
: StructuredCloneHolder(CloningSupported, TransferringNotSupported,
|
||||
StructuredCloneScope::SameProcessDifferentThread),
|
||||
mFlags(0), mExnType(JSEXN_ERR), mMutedError(false) {
|
||||
if (aWorkerPrivate) {
|
||||
RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
|
||||
aWorkerPrivate, "WorkerErrorReport");
|
||||
if (workerRef) {
|
||||
mWorkerRef = new ThreadSafeWorkerRef(workerRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerErrorReport::AssignErrorReport(JSErrorReport* aReport) {
|
||||
WorkerErrorBase::AssignErrorBase(aReport);
|
||||
xpc::ErrorReport::ErrorReportToMessageString(aReport, mMessage);
|
||||
|
@ -350,7 +241,7 @@ void WorkerErrorReport::AssignErrorReport(JSErrorReport* aReport) {
|
|||
/* static */
|
||||
void WorkerErrorReport::ReportError(
|
||||
JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aFireAtScope,
|
||||
DOMEventTargetHelper* aTarget, const WorkerErrorReport& aReport,
|
||||
DOMEventTargetHelper* aTarget, UniquePtr<WorkerErrorReport> aReport,
|
||||
uint64_t aInnerWindowId, JS::Handle<JS::Value> aException) {
|
||||
if (aWorkerPrivate) {
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
@ -360,16 +251,16 @@ void WorkerErrorReport::ReportError(
|
|||
|
||||
// We should not fire error events for warnings but instead make sure that
|
||||
// they show up in the error console.
|
||||
if (!JSREPORT_IS_WARNING(aReport.mFlags)) {
|
||||
if (!JSREPORT_IS_WARNING(aReport->mFlags)) {
|
||||
// First fire an ErrorEvent at the worker.
|
||||
RootedDictionary<ErrorEventInit> init(aCx);
|
||||
|
||||
if (aReport.mMutedError) {
|
||||
if (aReport->mMutedError) {
|
||||
init.mMessage.AssignLiteral("Script error.");
|
||||
} else {
|
||||
init.mMessage = aReport.mMessage;
|
||||
init.mFilename = aReport.mFilename;
|
||||
init.mLineno = aReport.mLineNumber;
|
||||
init.mMessage = aReport->mMessage;
|
||||
init.mFilename = aReport->mFilename;
|
||||
init.mLineno = aReport->mLineNumber;
|
||||
init.mError = aException;
|
||||
}
|
||||
|
||||
|
@ -396,7 +287,7 @@ void WorkerErrorReport::ReportError(
|
|||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks making this
|
||||
// better.
|
||||
if (aFireAtScope &&
|
||||
(aTarget || aReport.mErrorNumber != JSMSG_OVER_RECURSED)) {
|
||||
(aTarget || aReport->mErrorNumber != JSMSG_OVER_RECURSED)) {
|
||||
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
NS_ASSERTION(global, "This should never be null!");
|
||||
|
||||
|
@ -414,7 +305,7 @@ void WorkerErrorReport::ReportError(
|
|||
globalScope->GetWrapperPreserveColor() == global);
|
||||
if (globalScope || IsWorkerDebuggerSandbox(global)) {
|
||||
aWorkerPrivate->ReportErrorToDebugger(
|
||||
aReport.mFilename, aReport.mLineNumber, aReport.mMessage);
|
||||
aReport->mFilename, aReport->mLineNumber, aReport->mMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -458,17 +349,18 @@ void WorkerErrorReport::ReportError(
|
|||
// Now fire a runnable to do the same on the parent's thread if we can.
|
||||
if (aWorkerPrivate) {
|
||||
RefPtr<ReportErrorRunnable> runnable =
|
||||
new ReportErrorRunnable(aWorkerPrivate, aReport);
|
||||
new ReportErrorRunnable(aWorkerPrivate, std::move(aReport));
|
||||
runnable->Dispatch();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise log an error to the error console.
|
||||
WorkerErrorReport::LogErrorToConsole(aReport, aInnerWindowId);
|
||||
WorkerErrorReport::LogErrorToConsole(aCx, *aReport, aInnerWindowId);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void WorkerErrorReport::LogErrorToConsole(const WorkerErrorReport& aReport,
|
||||
void WorkerErrorReport::LogErrorToConsole(JSContext* aCx,
|
||||
WorkerErrorReport& aReport,
|
||||
uint64_t aInnerWindowId) {
|
||||
nsTArray<ErrorDataNote> notes;
|
||||
for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) {
|
||||
|
@ -477,18 +369,42 @@ void WorkerErrorReport::LogErrorToConsole(const WorkerErrorReport& aReport,
|
|||
note.mMessage, note.mFilename));
|
||||
}
|
||||
|
||||
// Read any stack associated with the report.
|
||||
JS::RootedValue stackValue(aCx);
|
||||
if (aReport.HasData() && aReport.mWorkerRef) {
|
||||
nsIPrincipal* principal = aReport.mWorkerRef->Private()->GetPrincipal();
|
||||
nsJSPrincipals::AutoSetActiveWorkerPrincipal set(principal);
|
||||
aReport.Read(xpc::CurrentNativeGlobal(aCx), aCx, &stackValue,
|
||||
IgnoreErrors());
|
||||
}
|
||||
JS::RootedObject stack(aCx);
|
||||
JS::RootedObject stackGlobal(aCx);
|
||||
if (stackValue.isObject()) {
|
||||
stack = &stackValue.toObject();
|
||||
stackGlobal = JS::CurrentGlobalOrNull(aCx);
|
||||
MOZ_ASSERT(stackGlobal);
|
||||
}
|
||||
|
||||
ErrorData errorData(aReport.mLineNumber, aReport.mColumnNumber,
|
||||
aReport.mFlags, aReport.mMessage, aReport.mFilename,
|
||||
aReport.mLine, notes);
|
||||
LogErrorToConsole(errorData, aInnerWindowId);
|
||||
LogErrorToConsole(errorData, aInnerWindowId, stack, stackGlobal);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void WorkerErrorReport::LogErrorToConsole(const ErrorData& aReport,
|
||||
uint64_t aInnerWindowId) {
|
||||
uint64_t aInnerWindowId,
|
||||
JS::HandleObject aStack,
|
||||
JS::HandleObject aStackGlobal) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
RefPtr<nsScriptErrorBase> scriptError = new nsScriptError();
|
||||
RefPtr<nsScriptErrorBase> scriptError;
|
||||
if (aStack) {
|
||||
scriptError = new nsScriptErrorWithStack(aStack, aStackGlobal);
|
||||
} else {
|
||||
scriptError = new nsScriptError();
|
||||
}
|
||||
|
||||
NS_WARNING_ASSERTION(scriptError, "Failed to create script error!");
|
||||
|
||||
if (scriptError) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "mozilla/dom/WorkerCommon.h"
|
||||
#include "jsapi.h"
|
||||
#include "WorkerRef.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -37,7 +38,9 @@ class WorkerErrorNote : public WorkerErrorBase {
|
|||
|
||||
class WorkerPrivate;
|
||||
|
||||
class WorkerErrorReport : public WorkerErrorBase {
|
||||
// The StructuredCloneHolder superclass is used to encode the error's stack
|
||||
// data, if there is any.
|
||||
class WorkerErrorReport : public WorkerErrorBase, public StructuredCloneHolder {
|
||||
public:
|
||||
nsString mLine;
|
||||
uint32_t mFlags;
|
||||
|
@ -45,7 +48,13 @@ class WorkerErrorReport : public WorkerErrorBase {
|
|||
bool mMutedError;
|
||||
nsTArray<WorkerErrorNote> mNotes;
|
||||
|
||||
WorkerErrorReport() : mFlags(0), mExnType(JSEXN_ERR), mMutedError(false) {}
|
||||
// Hold a reference on the originating worker until the error has been
|
||||
// processed.
|
||||
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
||||
|
||||
// Create a new error report. aWorkerPrivate represents the worker where the
|
||||
// error originated.
|
||||
explicit WorkerErrorReport(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
void AssignErrorReport(JSErrorReport* aReport);
|
||||
|
||||
|
@ -54,15 +63,17 @@ class WorkerErrorReport : public WorkerErrorBase {
|
|||
// (if any).
|
||||
static void ReportError(
|
||||
JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aFireAtScope,
|
||||
DOMEventTargetHelper* aTarget, const WorkerErrorReport& aReport,
|
||||
DOMEventTargetHelper* aTarget, UniquePtr<WorkerErrorReport> aReport,
|
||||
uint64_t aInnerWindowId,
|
||||
JS::Handle<JS::Value> aException = JS::NullHandleValue);
|
||||
|
||||
static void LogErrorToConsole(const WorkerErrorReport& aReport,
|
||||
static void LogErrorToConsole(JSContext* aCx, WorkerErrorReport& aReport,
|
||||
uint64_t aInnerWindowId);
|
||||
|
||||
static void LogErrorToConsole(const mozilla::dom::ErrorData& aReport,
|
||||
uint64_t aInnerWindowId);
|
||||
uint64_t aInnerWindowId,
|
||||
JS::HandleObject aStack = nullptr,
|
||||
JS::HandleObject aStackGlobal = nullptr);
|
||||
|
||||
static void CreateAndDispatchGenericErrorRunnableToParent(
|
||||
WorkerPrivate* aWorkerPrivate);
|
||||
|
|
|
@ -4048,18 +4048,27 @@ void WorkerPrivate::ReportError(JSContext* aCx,
|
|||
// for lack of anything better.
|
||||
exn.setNull();
|
||||
}
|
||||
JS::RootedObject exnStack(aCx, JS::GetPendingExceptionStack(aCx));
|
||||
JS_ClearPendingException(aCx);
|
||||
|
||||
WorkerErrorReport report;
|
||||
UniquePtr<WorkerErrorReport> report = MakeUnique<WorkerErrorReport>(this);
|
||||
if (aReport) {
|
||||
report.AssignErrorReport(aReport);
|
||||
report->AssignErrorReport(aReport);
|
||||
} else {
|
||||
report.mFlags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
|
||||
report->mFlags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
|
||||
}
|
||||
|
||||
if (report.mMessage.IsEmpty() && aToStringResult) {
|
||||
JS::RootedObject stack(aCx), stackGlobal(aCx);
|
||||
xpc::FindExceptionStackForConsoleReport(nullptr, exn, exnStack, &stack, &stackGlobal);
|
||||
|
||||
if (stack) {
|
||||
JS::RootedValue stackValue(aCx, JS::ObjectValue(*stack));
|
||||
report->Write(aCx, stackValue, IgnoreErrors());
|
||||
}
|
||||
|
||||
if (report->mMessage.IsEmpty() && aToStringResult) {
|
||||
nsDependentCString toStringResult(aToStringResult.c_str());
|
||||
if (!AppendUTF8toUTF16(toStringResult, report.mMessage,
|
||||
if (!AppendUTF8toUTF16(toStringResult, report->mMessage,
|
||||
mozilla::fallible)) {
|
||||
// Try again, with only a 1 KB string. Do this infallibly this time.
|
||||
// If the user doesn't have 1 KB to spare we're done anyways.
|
||||
|
@ -4070,7 +4079,7 @@ void WorkerPrivate::ReportError(JSContext* aCx,
|
|||
|
||||
nsDependentCString truncatedToStringResult(aToStringResult.c_str(),
|
||||
index);
|
||||
AppendUTF8toUTF16(truncatedToStringResult, report.mMessage);
|
||||
AppendUTF8toUTF16(truncatedToStringResult, report->mMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4079,11 +4088,11 @@ void WorkerPrivate::ReportError(JSContext* aCx,
|
|||
// Don't want to run the scope's error handler if this is a recursive error or
|
||||
// if we ran out of memory.
|
||||
bool fireAtScope = data->mErrorHandlerRecursionCount == 1 &&
|
||||
report.mErrorNumber != JSMSG_OUT_OF_MEMORY &&
|
||||
report->mErrorNumber != JSMSG_OUT_OF_MEMORY &&
|
||||
JS::CurrentGlobalOrNull(aCx);
|
||||
|
||||
WorkerErrorReport::ReportError(aCx, this, fireAtScope, nullptr, report, 0,
|
||||
exn);
|
||||
WorkerErrorReport::ReportError(aCx, this, fireAtScope,
|
||||
nullptr, std::move(report), 0, exn);
|
||||
|
||||
data->mErrorHandlerRecursionCount--;
|
||||
}
|
||||
|
|
|
@ -5008,6 +5008,22 @@ JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx) {
|
|||
cx->clearPendingException();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void
|
||||
JS::SetPendingExceptionAndStack(JSContext* cx, HandleValue value,
|
||||
HandleObject stack)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
cx->releaseCheck(value);
|
||||
cx->releaseCheck(stack);
|
||||
|
||||
RootedSavedFrame nstack(cx);
|
||||
if (stack) {
|
||||
nstack = &UncheckedUnwrap(stack)->as<SavedFrame>();
|
||||
}
|
||||
cx->setPendingException(value, nstack);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSObject* JS::GetPendingExceptionStack(JSContext* cx) {
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
|
|
|
@ -2848,6 +2848,11 @@ class JS_PUBLIC_API AutoSaveExceptionState {
|
|||
void restore();
|
||||
};
|
||||
|
||||
// Set both the exception and its associated stack on the context. The stack
|
||||
// must be a SavedFrame.
|
||||
JS_PUBLIC_API void SetPendingExceptionAndStack(JSContext* cx, HandleValue value,
|
||||
HandleObject stack);
|
||||
|
||||
/**
|
||||
* Get the SavedFrame stack object captured when the pending exception was set
|
||||
* on the JSContext. This fuzzily correlates with a `throw` statement in JS,
|
||||
|
|
|
@ -253,11 +253,10 @@ class DebugScript {
|
|||
friend class JS::Realm;
|
||||
|
||||
/*
|
||||
* When non-zero, compile script in single-step mode. The top bit is set and
|
||||
* cleared by setStepMode, as used by JSD. The lower bits are a count,
|
||||
* adjusted by changeStepModeCount, used by the Debugger object. Only
|
||||
* when the bit is clear and the count is zero may we compile the script
|
||||
* without single-step support.
|
||||
* When greater than zero, compile script in single-step mode, with VM calls
|
||||
* to HandleDebugTrap before each bytecode instruction's code. This is a
|
||||
* counter, adjusted by the incrementStepModeCount and decrementStepModeCount
|
||||
* methods.
|
||||
*/
|
||||
uint32_t stepMode;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче