mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
feat(ext/web): Add error events for event listener and timer errors (#14159)
- feat: Add handleable error event for even listener errors - feat: Add handleable error event for setTimeout()/setInterval() errors - feat: Add Deno.core.destructureError() - feat: Add Deno.core.terminate() - fix: Don't throw listener errors from dispatchEvent() - fix: Use biased mode when selecting between mod_evaluate() and run_event_loop() results
This commit is contained in:
parent
d621ce1cf0
commit
4d18f558e4
35 changed files with 439 additions and 130 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -236,7 +236,7 @@ jobs:
|
||||||
~/.cargo/registry/index
|
~/.cargo/registry/index
|
||||||
~/.cargo/registry/cache
|
~/.cargo/registry/cache
|
||||||
~/.cargo/git/db
|
~/.cargo/git/db
|
||||||
key: 5-cargo-home-${{ matrix.os }}-${{ hashFiles('Cargo.lock') }}
|
key: 7-cargo-home-${{ matrix.os }}-${{ hashFiles('Cargo.lock') }}
|
||||||
|
|
||||||
# In main branch, always creates fresh cache
|
# In main branch, always creates fresh cache
|
||||||
- name: Cache build output (main)
|
- name: Cache build output (main)
|
||||||
|
@ -252,7 +252,7 @@ jobs:
|
||||||
!./target/*/*.zip
|
!./target/*/*.zip
|
||||||
!./target/*/*.tar.gz
|
!./target/*/*.tar.gz
|
||||||
key: |
|
key: |
|
||||||
5-cargo-target-${{ matrix.os }}-${{ matrix.profile }}-${{ github.sha }}
|
7-cargo-target-${{ matrix.os }}-${{ matrix.profile }}-${{ github.sha }}
|
||||||
|
|
||||||
# Restore cache from the latest 'main' branch build.
|
# Restore cache from the latest 'main' branch build.
|
||||||
- name: Cache build output (PR)
|
- name: Cache build output (PR)
|
||||||
|
@ -268,7 +268,7 @@ jobs:
|
||||||
!./target/*/*.tar.gz
|
!./target/*/*.tar.gz
|
||||||
key: never_saved
|
key: never_saved
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
5-cargo-target-${{ matrix.os }}-${{ matrix.profile }}-
|
7-cargo-target-${{ matrix.os }}-${{ matrix.profile }}-
|
||||||
|
|
||||||
# Don't save cache after building PRs or branches other than 'main'.
|
# Don't save cache after building PRs or branches other than 'main'.
|
||||||
- name: Skip save cache (PR)
|
- name: Skip save cache (PR)
|
||||||
|
|
55
cli/dts/lib.deno.window.d.ts
vendored
55
cli/dts/lib.deno.window.d.ts
vendored
|
@ -7,10 +7,15 @@
|
||||||
/// <reference lib="deno.webstorage" />
|
/// <reference lib="deno.webstorage" />
|
||||||
/// <reference lib="esnext" />
|
/// <reference lib="esnext" />
|
||||||
|
|
||||||
|
interface WindowEventMap {
|
||||||
|
"error": ErrorEvent;
|
||||||
|
}
|
||||||
|
|
||||||
declare class Window extends EventTarget {
|
declare class Window extends EventTarget {
|
||||||
new(): Window;
|
new(): Window;
|
||||||
readonly window: Window & typeof globalThis;
|
readonly window: Window & typeof globalThis;
|
||||||
readonly self: Window & typeof globalThis;
|
readonly self: Window & typeof globalThis;
|
||||||
|
onerror: ((this: Window, ev: ErrorEvent) => any) | null;
|
||||||
onload: ((this: Window, ev: Event) => any) | null;
|
onload: ((this: Window, ev: Event) => any) | null;
|
||||||
onunload: ((this: Window, ev: Event) => any) | null;
|
onunload: ((this: Window, ev: Event) => any) | null;
|
||||||
close: () => void;
|
close: () => void;
|
||||||
|
@ -25,10 +30,38 @@ declare class Window extends EventTarget {
|
||||||
location: Location;
|
location: Location;
|
||||||
localStorage: Storage;
|
localStorage: Storage;
|
||||||
sessionStorage: Storage;
|
sessionStorage: Storage;
|
||||||
|
|
||||||
|
addEventListener<K extends keyof WindowEventMap>(
|
||||||
|
type: K,
|
||||||
|
listener: (
|
||||||
|
this: Window,
|
||||||
|
ev: WindowEventMap[K],
|
||||||
|
) => any,
|
||||||
|
options?: boolean | AddEventListenerOptions,
|
||||||
|
): void;
|
||||||
|
addEventListener(
|
||||||
|
type: string,
|
||||||
|
listener: EventListenerOrEventListenerObject,
|
||||||
|
options?: boolean | AddEventListenerOptions,
|
||||||
|
): void;
|
||||||
|
removeEventListener<K extends keyof WindowEventMap>(
|
||||||
|
type: K,
|
||||||
|
listener: (
|
||||||
|
this: Window,
|
||||||
|
ev: WindowEventMap[K],
|
||||||
|
) => any,
|
||||||
|
options?: boolean | EventListenerOptions,
|
||||||
|
): void;
|
||||||
|
removeEventListener(
|
||||||
|
type: string,
|
||||||
|
listener: EventListenerOrEventListenerObject,
|
||||||
|
options?: boolean | EventListenerOptions,
|
||||||
|
): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare var window: Window & typeof globalThis;
|
declare var window: Window & typeof globalThis;
|
||||||
declare var self: Window & typeof globalThis;
|
declare var self: Window & typeof globalThis;
|
||||||
|
declare var onerror: ((this: Window, ev: ErrorEvent) => any) | null;
|
||||||
declare var onload: ((this: Window, ev: Event) => any) | null;
|
declare var onload: ((this: Window, ev: Event) => any) | null;
|
||||||
declare var onunload: ((this: Window, ev: Event) => any) | null;
|
declare var onunload: ((this: Window, ev: Event) => any) | null;
|
||||||
declare var localStorage: Storage;
|
declare var localStorage: Storage;
|
||||||
|
@ -77,10 +110,17 @@ declare function prompt(message?: string, defaultValue?: string): string | null;
|
||||||
* dispatchEvent(new Event('unload'));
|
* dispatchEvent(new Event('unload'));
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
declare function addEventListener<
|
||||||
|
K extends keyof WindowEventMap,
|
||||||
|
>(
|
||||||
|
type: K,
|
||||||
|
listener: (this: Window, ev: WindowEventMap[K]) => any,
|
||||||
|
options?: boolean | AddEventListenerOptions,
|
||||||
|
): void;
|
||||||
declare function addEventListener(
|
declare function addEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback: EventListenerOrEventListenerObject | null,
|
listener: EventListenerOrEventListenerObject,
|
||||||
options?: boolean | AddEventListenerOptions | undefined,
|
options?: boolean | AddEventListenerOptions,
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
/** Remove a previously registered event listener from the global scope
|
/** Remove a previously registered event listener from the global scope
|
||||||
|
@ -91,10 +131,17 @@ declare function addEventListener(
|
||||||
* removeEventListener('load', listener);
|
* removeEventListener('load', listener);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
declare function removeEventListener<
|
||||||
|
K extends keyof WindowEventMap,
|
||||||
|
>(
|
||||||
|
type: K,
|
||||||
|
listener: (this: Window, ev: WindowEventMap[K]) => any,
|
||||||
|
options?: boolean | EventListenerOptions,
|
||||||
|
): void;
|
||||||
declare function removeEventListener(
|
declare function removeEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback: EventListenerOrEventListenerObject | null,
|
listener: EventListenerOrEventListenerObject,
|
||||||
options?: boolean | EventListenerOptions | undefined,
|
options?: boolean | EventListenerOptions,
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
// TODO(nayeemrmn): Move this to `extensions/web` where its implementation is.
|
// TODO(nayeemrmn): Move this to `extensions/web` where its implementation is.
|
||||||
|
|
|
@ -2685,3 +2685,32 @@ itest!(future_check2 {
|
||||||
output: "future_check2.out",
|
output: "future_check2.out",
|
||||||
envs: vec![("DENO_FUTURE_CHECK".to_string(), "1".to_string())],
|
envs: vec![("DENO_FUTURE_CHECK".to_string(), "1".to_string())],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itest!(event_listener_error {
|
||||||
|
args: "run --quiet event_listener_error.ts",
|
||||||
|
output: "event_listener_error.ts.out",
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(event_listener_error_handled {
|
||||||
|
args: "run --quiet event_listener_error_handled.ts",
|
||||||
|
output: "event_listener_error_handled.ts.out",
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://github.com/denoland/deno/pull/14159#issuecomment-1092285446
|
||||||
|
itest!(event_listener_error_immediate_exit {
|
||||||
|
args: "run --quiet event_listener_error_immediate_exit.ts",
|
||||||
|
output: "event_listener_error_immediate_exit.ts.out",
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(set_timeout_error {
|
||||||
|
args: "run --quiet set_timeout_error.ts",
|
||||||
|
output: "set_timeout_error.ts.out",
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(set_timeout_error_handled {
|
||||||
|
args: "run --quiet set_timeout_error_handled.ts",
|
||||||
|
output: "set_timeout_error_handled.ts.out",
|
||||||
|
});
|
||||||
|
|
6
cli/tests/testdata/event_listener_error.ts
vendored
Normal file
6
cli/tests/testdata/event_listener_error.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
addEventListener("foo", () => {
|
||||||
|
throw new Error("bar");
|
||||||
|
});
|
||||||
|
console.log(1);
|
||||||
|
dispatchEvent(new CustomEvent("foo"));
|
||||||
|
console.log(2);
|
7
cli/tests/testdata/event_listener_error.ts.out
vendored
Normal file
7
cli/tests/testdata/event_listener_error.ts.out
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
1
|
||||||
|
error: Uncaught Error: bar
|
||||||
|
throw new Error("bar");
|
||||||
|
^
|
||||||
|
at [WILDCARD]/event_listener_error.ts:2:9
|
||||||
|
at [WILDCARD]
|
||||||
|
at [WILDCARD]/event_listener_error.ts:5:1
|
23
cli/tests/testdata/event_listener_error_handled.ts
vendored
Normal file
23
cli/tests/testdata/event_listener_error_handled.ts
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
addEventListener("error", (event) => {
|
||||||
|
console.log({
|
||||||
|
cancelable: event.cancelable,
|
||||||
|
message: event.message,
|
||||||
|
filename: event.filename?.slice?.(-100),
|
||||||
|
lineno: event.lineno,
|
||||||
|
colno: event.colno,
|
||||||
|
error: event.error,
|
||||||
|
});
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
onerror = (event) => {
|
||||||
|
console.log("onerror() called", event.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
addEventListener("foo", () => {
|
||||||
|
throw new Error("bar");
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(1);
|
||||||
|
dispatchEvent(new CustomEvent("foo"));
|
||||||
|
console.log(2);
|
17
cli/tests/testdata/event_listener_error_handled.ts.out
vendored
Normal file
17
cli/tests/testdata/event_listener_error_handled.ts.out
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
1
|
||||||
|
{
|
||||||
|
cancelable: true,
|
||||||
|
message: "Uncaught Error: bar",
|
||||||
|
filename: "[WILDCARD]/event_listener_error_handled.ts",
|
||||||
|
lineno: 18,
|
||||||
|
colno: 9,
|
||||||
|
error: Error: bar
|
||||||
|
at [WILDCARD]/event_listener_error_handled.ts:18:9
|
||||||
|
at [WILDCARD]
|
||||||
|
at [WILDCARD]/event_listener_error_handled.ts:22:1
|
||||||
|
}
|
||||||
|
onerror() called Error: bar
|
||||||
|
at [WILDCARD]/event_listener_error_handled.ts:18:9
|
||||||
|
at [WILDCARD]
|
||||||
|
at [WILDCARD]/event_listener_error_handled.ts:22:1
|
||||||
|
2
|
12
cli/tests/testdata/event_listener_error_immediate_exit.ts
vendored
Normal file
12
cli/tests/testdata/event_listener_error_immediate_exit.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
addEventListener("foo", () => {
|
||||||
|
queueMicrotask(() => console.log("queueMicrotask"));
|
||||||
|
setTimeout(() => console.log("timer"), 0);
|
||||||
|
throw new Error("bar");
|
||||||
|
});
|
||||||
|
console.log(1);
|
||||||
|
// @ts-ignore Deno.core
|
||||||
|
Deno.core.setNextTickCallback(() => console.log("nextTick"));
|
||||||
|
// @ts-ignore Deno.core
|
||||||
|
Deno.core.setHasTickScheduled(true);
|
||||||
|
dispatchEvent(new CustomEvent("foo"));
|
||||||
|
console.log(2);
|
6
cli/tests/testdata/event_listener_error_immediate_exit.ts.out
vendored
Normal file
6
cli/tests/testdata/event_listener_error_immediate_exit.ts.out
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
1
|
||||||
|
error: Uncaught Error: bar
|
||||||
|
throw new Error("bar");
|
||||||
|
^
|
||||||
|
at [WILDCARD]/event_listener_error_immediate_exit.ts:4:9[WILDCARD]
|
||||||
|
at [WILDCARD]/event_listener_error_immediate_exit.ts:11:1
|
3
cli/tests/testdata/set_timeout_error.ts
vendored
Normal file
3
cli/tests/testdata/set_timeout_error.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
setTimeout(() => {
|
||||||
|
throw new Error("foo");
|
||||||
|
}, 0);
|
5
cli/tests/testdata/set_timeout_error.ts.out
vendored
Normal file
5
cli/tests/testdata/set_timeout_error.ts.out
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
error: Uncaught Error: foo
|
||||||
|
throw new Error("foo");
|
||||||
|
^
|
||||||
|
at [WILDCARD]/set_timeout_error.ts:2:9
|
||||||
|
at [WILDCARD]
|
19
cli/tests/testdata/set_timeout_error_handled.ts
vendored
Normal file
19
cli/tests/testdata/set_timeout_error_handled.ts
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
addEventListener("error", (event) => {
|
||||||
|
console.log({
|
||||||
|
cancelable: event.cancelable,
|
||||||
|
message: event.message,
|
||||||
|
filename: event.filename?.slice?.(-100),
|
||||||
|
lineno: event.lineno,
|
||||||
|
colno: event.colno,
|
||||||
|
error: event.error,
|
||||||
|
});
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
onerror = (event) => {
|
||||||
|
console.log("onerror() called", event.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
throw new Error("foo");
|
||||||
|
}, 0);
|
13
cli/tests/testdata/set_timeout_error_handled.ts.out
vendored
Normal file
13
cli/tests/testdata/set_timeout_error_handled.ts.out
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
cancelable: true,
|
||||||
|
message: "Uncaught Error: foo",
|
||||||
|
filename: "[WILDCARD]/set_timeout_error_handled.ts",
|
||||||
|
lineno: 18,
|
||||||
|
colno: 9,
|
||||||
|
error: Error: foo
|
||||||
|
at [WILDCARD]/set_timeout_error_handled.ts:18:9
|
||||||
|
at [WILDCARD]
|
||||||
|
}
|
||||||
|
onerror() called Error: foo
|
||||||
|
at [WILDCARD]/set_timeout_error_handled.ts:18:9
|
||||||
|
at [WILDCARD]
|
|
@ -4,5 +4,5 @@ error: Uncaught (in worker "") Error
|
||||||
at [WILDCARD]/workers/drop_handle_race.js:2:9
|
at [WILDCARD]/workers/drop_handle_race.js:2:9
|
||||||
at Object.action (deno:ext/web/02_timers.js:[WILDCARD])
|
at Object.action (deno:ext/web/02_timers.js:[WILDCARD])
|
||||||
at handleTimerMacrotask (deno:ext/web/02_timers.js:[WILDCARD])
|
at handleTimerMacrotask (deno:ext/web/02_timers.js:[WILDCARD])
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl (deno:runtime/js/11_workers.js:[WILDCARD])
|
at Worker.#pollControl (deno:runtime/js/11_workers.js:[WILDCARD])
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
Target from self.onmessage: [object DedicatedWorkerGlobalScope]
|
Target from self.onmessage: [object DedicatedWorkerGlobalScope]
|
||||||
Target from message event listener: [object DedicatedWorkerGlobalScope]
|
Target from message event listener: [object DedicatedWorkerGlobalScope]
|
||||||
Arguments from self.onerror: [
|
Arguments from self.onerror: [
|
||||||
"Some error message",
|
"Uncaught Error: Some error message",
|
||||||
"",
|
"[WILDCARD]/worker_event_handlers.js",
|
||||||
0,
|
9,
|
||||||
0,
|
9,
|
||||||
Error: Some error message
|
Error: Some error message
|
||||||
at [WILDCARD]
|
at [WILDCARD]
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[WILDCARD]error: Uncaught (in worker "") Module not found "file:///[WILDCARD]/workers/doesnt_exist.js".
|
[WILDCARD]error: Uncaught (in worker "") Module not found "file:///[WILDCARD]/workers/doesnt_exist.js".
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: Uncaught (in worker "") Requires read access to "[WILDCARD]local_file.ts", run again with the --allow-read flag
|
error: Uncaught (in worker "") Requires read access to "[WILDCARD]local_file.ts", run again with the --allow-read flag
|
||||||
at blob:null/[WILDCARD]:1:8
|
at blob:null/[WILDCARD]:1:8
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
|
error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
|
||||||
at blob:null/[WILDCARD]:1:8
|
at blob:null/[WILDCARD]:1:8
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: Uncaught (in worker "") Requires read access to "[WILDCARD]local_file.ts", run again with the --allow-read flag
|
error: Uncaught (in worker "") Requires read access to "[WILDCARD]local_file.ts", run again with the --allow-read flag
|
||||||
at data:application/javascript;base64,[WILDCARD]:1:8
|
at data:application/javascript;base64,[WILDCARD]:1:8
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
|
error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
|
||||||
at data:application/javascript;base64,aW1wb3J0ICJodHRwczovL2V4YW1wbGUuY29tL3NvbWUvZmlsZS50cyI7:1:8
|
at data:application/javascript;base64,aW1wb3J0ICJodHRwczovL2V4YW1wbGUuY29tL3NvbWUvZmlsZS50cyI7:1:8
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -2,5 +2,5 @@ error: Uncaught (in worker "") (in promise) TypeError: Requires net access to "e
|
||||||
await import("https://example.com/some/file.ts");
|
await import("https://example.com/some/file.ts");
|
||||||
^
|
^
|
||||||
at async http://localhost:4545/workers/dynamic_remote.ts:2:1
|
at async http://localhost:4545/workers/dynamic_remote.ts:2:1
|
||||||
[WILDCARD]error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
[WILDCARD]error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
|
error: Uncaught (in worker "") Requires net access to "example.com", run again with the --allow-net flag
|
||||||
at http://localhost:4545/workers/static_remote.ts:2:8
|
at http://localhost:4545/workers/static_remote.ts:2:8
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -3,5 +3,5 @@ error: Uncaught (in worker "foo") (in promise) Error: bar
|
||||||
^
|
^
|
||||||
at [WILDCARD]/async_error.ts:[WILDCARD]
|
at [WILDCARD]/async_error.ts:[WILDCARD]
|
||||||
at [WILDCARD]/async_error.ts:[WILDCARD]
|
at [WILDCARD]/async_error.ts:[WILDCARD]
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[WILDCARD]error: Uncaught (in worker "bar") Error: foo[WILDCARD]
|
[WILDCARD]error: Uncaught (in worker "bar") Error: foo[WILDCARD]
|
||||||
at foo ([WILDCARD])
|
at foo ([WILDCARD])
|
||||||
at [WILDCARD]
|
at [WILDCARD]
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
error: Uncaught (in worker "foo") (in promise) Error: bar
|
error: Uncaught (in worker "foo") Error: bar
|
||||||
throw new Error("bar");
|
throw new Error("bar");
|
||||||
^
|
^
|
||||||
at onmessage ([WILDCARD]/message_handler_error.ts:[WILDCARD])
|
at onmessage ([WILDCARD]/message_handler_error.ts:[WILDCARD])
|
||||||
at [WILDCARD]
|
at [WILDCARD]
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
^
|
^
|
||||||
at foo ([WILDCARD]/workers/error.ts:[WILDCARD])
|
at foo ([WILDCARD]/workers/error.ts:[WILDCARD])
|
||||||
at [WILDCARD]/workers/error.ts:[WILDCARD]
|
at [WILDCARD]/workers/error.ts:[WILDCARD]
|
||||||
error: Uncaught (in worker "baz") (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in worker "baz") (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
error: Uncaught (in promise) Error: Unhandled error event in child worker.
|
error: Uncaught (in promise) Error: Unhandled error in child worker.
|
||||||
at Worker.#pollControl ([WILDCARD])
|
at Worker.#pollControl ([WILDCARD])
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::error::is_instance_of_error;
|
use crate::error::is_instance_of_error;
|
||||||
|
use crate::error::JsError;
|
||||||
use crate::modules::get_module_type_from_assertions;
|
use crate::modules::get_module_type_from_assertions;
|
||||||
use crate::modules::parse_import_assertions;
|
use crate::modules::parse_import_assertions;
|
||||||
use crate::modules::validate_import_assertions;
|
use crate::modules::validate_import_assertions;
|
||||||
|
@ -102,6 +103,12 @@ pub static EXTERNAL_REFERENCES: Lazy<v8::ExternalReferences> =
|
||||||
v8::ExternalReference {
|
v8::ExternalReference {
|
||||||
function: abort_wasm_streaming.map_fn_to(),
|
function: abort_wasm_streaming.map_fn_to(),
|
||||||
},
|
},
|
||||||
|
v8::ExternalReference {
|
||||||
|
function: destructure_error.map_fn_to(),
|
||||||
|
},
|
||||||
|
v8::ExternalReference {
|
||||||
|
function: terminate.map_fn_to(),
|
||||||
|
},
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -228,6 +235,8 @@ pub fn initialize_context<'s>(
|
||||||
set_wasm_streaming_callback,
|
set_wasm_streaming_callback,
|
||||||
);
|
);
|
||||||
set_func(scope, core_val, "abortWasmStreaming", abort_wasm_streaming);
|
set_func(scope, core_val, "abortWasmStreaming", abort_wasm_streaming);
|
||||||
|
set_func(scope, core_val, "destructureError", destructure_error);
|
||||||
|
set_func(scope, core_val, "terminate", terminate);
|
||||||
// Direct bindings on `window`.
|
// Direct bindings on `window`.
|
||||||
set_func(scope, global, "queueMicrotask", queue_microtask);
|
set_func(scope, global, "queueMicrotask", queue_microtask);
|
||||||
|
|
||||||
|
@ -1293,6 +1302,28 @@ fn queue_microtask(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn destructure_error(
|
||||||
|
scope: &mut v8::HandleScope,
|
||||||
|
args: v8::FunctionCallbackArguments,
|
||||||
|
mut rv: v8::ReturnValue,
|
||||||
|
) {
|
||||||
|
let js_error = JsError::from_v8_exception(scope, args.get(0));
|
||||||
|
let object = serde_v8::to_v8(scope, js_error).unwrap();
|
||||||
|
rv.set(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn terminate(
|
||||||
|
scope: &mut v8::HandleScope,
|
||||||
|
args: v8::FunctionCallbackArguments,
|
||||||
|
_rv: v8::ReturnValue,
|
||||||
|
) {
|
||||||
|
let state_rc = JsRuntime::state(scope);
|
||||||
|
let mut state = state_rc.borrow_mut();
|
||||||
|
state.explicit_terminate_exception =
|
||||||
|
Some(v8::Global::new(scope, args.get(0)));
|
||||||
|
scope.terminate_execution();
|
||||||
|
}
|
||||||
|
|
||||||
fn create_host_object(
|
fn create_host_object(
|
||||||
scope: &mut v8::HandleScope,
|
scope: &mut v8::HandleScope,
|
||||||
_args: v8::FunctionCallbackArguments,
|
_args: v8::FunctionCallbackArguments,
|
||||||
|
|
|
@ -90,7 +90,8 @@ pub fn get_custom_error_class(error: &Error) -> Option<&'static str> {
|
||||||
/// A `JsError` represents an exception coming from V8, with stack frames and
|
/// A `JsError` represents an exception coming from V8, with stack frames and
|
||||||
/// line numbers. The deno_cli crate defines another `JsError` type, which wraps
|
/// line numbers. The deno_cli crate defines another `JsError` type, which wraps
|
||||||
/// the one defined here, that adds source map support and colorful formatting.
|
/// the one defined here, that adds source map support and colorful formatting.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone, serde::Deserialize, serde::Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct JsError {
|
pub struct JsError {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub cause: Option<Box<JsError>>,
|
pub cause: Option<Box<JsError>>,
|
||||||
|
@ -103,7 +104,7 @@ pub struct JsError {
|
||||||
pub stack: Option<String>,
|
pub stack: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, serde::Deserialize)]
|
#[derive(Debug, PartialEq, Clone, serde::Deserialize, serde::Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct JsStackFrame {
|
pub struct JsStackFrame {
|
||||||
pub type_name: Option<String>,
|
pub type_name: Option<String>,
|
||||||
|
@ -190,7 +191,6 @@ impl JsError {
|
||||||
|
|
||||||
let msg = v8::Exception::create_message(scope, exception);
|
let msg = v8::Exception::create_message(scope, exception);
|
||||||
|
|
||||||
let (message, frames, stack, cause) =
|
|
||||||
if is_instance_of_error(scope, exception) {
|
if is_instance_of_error(scope, exception) {
|
||||||
// The exception is a JS Error object.
|
// The exception is a JS Error object.
|
||||||
let exception: v8::Local<v8::Object> = exception.try_into().unwrap();
|
let exception: v8::Local<v8::Object> = exception.try_into().unwrap();
|
||||||
|
@ -235,24 +235,9 @@ impl JsError {
|
||||||
|
|
||||||
// Convert them into Vec<JsStackFrame>
|
// Convert them into Vec<JsStackFrame>
|
||||||
let frames: Vec<JsStackFrame> = match frames_v8 {
|
let frames: Vec<JsStackFrame> = match frames_v8 {
|
||||||
Some(frames_v8) => {
|
Some(frames_v8) => serde_v8::from_v8(scope, frames_v8.into()).unwrap(),
|
||||||
serde_v8::from_v8(scope, frames_v8.into()).unwrap()
|
|
||||||
}
|
|
||||||
None => vec![],
|
None => vec![],
|
||||||
};
|
};
|
||||||
(message, frames, stack, cause)
|
|
||||||
} else {
|
|
||||||
// The exception is not a JS Error object.
|
|
||||||
// Get the message given by V8::Exception::create_message(), and provide
|
|
||||||
// empty frames.
|
|
||||||
(
|
|
||||||
msg.get(scope).to_rust_string_lossy(scope),
|
|
||||||
vec![],
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
message,
|
message,
|
||||||
cause,
|
cause,
|
||||||
|
@ -269,6 +254,22 @@ impl JsError {
|
||||||
frames,
|
frames,
|
||||||
stack,
|
stack,
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// The exception is not a JS Error object.
|
||||||
|
// Get the message given by V8::Exception::create_message(), and provide
|
||||||
|
// empty frames.
|
||||||
|
Self {
|
||||||
|
message: msg.get(scope).to_rust_string_lossy(scope),
|
||||||
|
cause: None,
|
||||||
|
script_resource_name: None,
|
||||||
|
source_line: None,
|
||||||
|
line_number: None,
|
||||||
|
start_column: None,
|
||||||
|
end_column: None,
|
||||||
|
frames: vec![],
|
||||||
|
stack: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,6 +338,9 @@ pub(crate) fn is_instance_of_error<'s>(
|
||||||
let mut maybe_prototype =
|
let mut maybe_prototype =
|
||||||
value.to_object(scope).unwrap().get_prototype(scope);
|
value.to_object(scope).unwrap().get_prototype(scope);
|
||||||
while let Some(prototype) = maybe_prototype {
|
while let Some(prototype) = maybe_prototype {
|
||||||
|
if !prototype.is_object() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if prototype.strict_equals(error_prototype) {
|
if prototype.strict_equals(error_prototype) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,6 +169,10 @@ pub(crate) struct JsRuntimeState {
|
||||||
pub(crate) op_ctxs: Box<[OpCtx]>,
|
pub(crate) op_ctxs: Box<[OpCtx]>,
|
||||||
pub(crate) shared_array_buffer_store: Option<SharedArrayBufferStore>,
|
pub(crate) shared_array_buffer_store: Option<SharedArrayBufferStore>,
|
||||||
pub(crate) compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
|
pub(crate) compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
|
||||||
|
/// The error that was passed to an explicit `Deno.core.terminate` call.
|
||||||
|
/// It will be retrieved by `exception_to_err_result` and used as an error
|
||||||
|
/// instead of any other exceptions.
|
||||||
|
pub(crate) explicit_terminate_exception: Option<v8::Global<v8::Value>>,
|
||||||
waker: AtomicWaker,
|
waker: AtomicWaker,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,6 +388,7 @@ impl JsRuntime {
|
||||||
op_state: op_state.clone(),
|
op_state: op_state.clone(),
|
||||||
op_ctxs,
|
op_ctxs,
|
||||||
have_unpolled_ops: false,
|
have_unpolled_ops: false,
|
||||||
|
explicit_terminate_exception: None,
|
||||||
waker: AtomicWaker::new(),
|
waker: AtomicWaker::new(),
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
@ -1017,19 +1022,33 @@ pub(crate) fn exception_to_err_result<'s, T>(
|
||||||
exception: v8::Local<v8::Value>,
|
exception: v8::Local<v8::Value>,
|
||||||
in_promise: bool,
|
in_promise: bool,
|
||||||
) -> Result<T, Error> {
|
) -> Result<T, Error> {
|
||||||
|
let state_rc = JsRuntime::state(scope);
|
||||||
|
let mut state = state_rc.borrow_mut();
|
||||||
|
|
||||||
let is_terminating_exception = scope.is_execution_terminating();
|
let is_terminating_exception = scope.is_execution_terminating();
|
||||||
let mut exception = exception;
|
let mut exception = exception;
|
||||||
|
|
||||||
if is_terminating_exception {
|
if is_terminating_exception {
|
||||||
// TerminateExecution was called. Cancel exception termination so that the
|
// TerminateExecution was called. Cancel isolate termination so that the
|
||||||
// exception can be created..
|
// exception can be created..
|
||||||
scope.cancel_terminate_execution();
|
scope.cancel_terminate_execution();
|
||||||
|
|
||||||
|
// If the termination is the result of a `Deno.core.terminate` call, we want
|
||||||
|
// to use the exception that was passed to it rather than the exception that
|
||||||
|
// was passed to this function.
|
||||||
|
exception = state
|
||||||
|
.explicit_terminate_exception
|
||||||
|
.take()
|
||||||
|
.map(|exception| v8::Local::new(scope, exception))
|
||||||
|
.unwrap_or_else(|| {
|
||||||
// Maybe make a new exception object.
|
// Maybe make a new exception object.
|
||||||
if exception.is_null_or_undefined() {
|
if exception.is_null_or_undefined() {
|
||||||
let message = v8::String::new(scope, "execution terminated").unwrap();
|
let message = v8::String::new(scope, "execution terminated").unwrap();
|
||||||
exception = v8::Exception::error(scope, message);
|
v8::Exception::error(scope, message)
|
||||||
|
} else {
|
||||||
|
exception
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut js_error = JsError::from_v8_exception(scope, exception);
|
let mut js_error = JsError::from_v8_exception(scope, exception);
|
||||||
|
@ -1039,9 +1058,6 @@ pub(crate) fn exception_to_err_result<'s, T>(
|
||||||
js_error.message.trim_start_matches("Uncaught ")
|
js_error.message.trim_start_matches("Uncaught ")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let state_rc = JsRuntime::state(scope);
|
|
||||||
let state = state_rc.borrow();
|
|
||||||
let js_error = (state.js_error_create_fn)(js_error);
|
let js_error = (state.js_error_create_fn)(js_error);
|
||||||
|
|
||||||
if is_terminating_exception {
|
if is_terminating_exception {
|
||||||
|
@ -1222,7 +1238,14 @@ impl JsRuntime {
|
||||||
// Update status after evaluating.
|
// Update status after evaluating.
|
||||||
status = module.get_status();
|
status = module.get_status();
|
||||||
|
|
||||||
if let Some(value) = maybe_value {
|
let explicit_terminate_exception =
|
||||||
|
state_rc.borrow_mut().explicit_terminate_exception.take();
|
||||||
|
if let Some(exception) = explicit_terminate_exception {
|
||||||
|
let exception = v8::Local::new(tc_scope, exception);
|
||||||
|
sender
|
||||||
|
.send(exception_to_err_result(tc_scope, exception, false))
|
||||||
|
.expect("Failed to send module evaluation error.");
|
||||||
|
} else if let Some(value) = maybe_value {
|
||||||
assert!(
|
assert!(
|
||||||
status == v8::ModuleStatus::Evaluated
|
status == v8::ModuleStatus::Evaluated
|
||||||
|| status == v8::ModuleStatus::Errored
|
|| status == v8::ModuleStatus::Errored
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
((window) => {
|
((window) => {
|
||||||
|
const core = window.Deno.core;
|
||||||
const webidl = window.__bootstrap.webidl;
|
const webidl = window.__bootstrap.webidl;
|
||||||
const { DOMException } = window.__bootstrap.domException;
|
const { DOMException } = window.__bootstrap.domException;
|
||||||
const consoleInternal = window.__bootstrap.console;
|
const consoleInternal = window.__bootstrap.console;
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
ReflectDefineProperty,
|
ReflectDefineProperty,
|
||||||
SafeArrayIterator,
|
SafeArrayIterator,
|
||||||
|
StringPrototypeStartsWith,
|
||||||
Symbol,
|
Symbol,
|
||||||
SymbolFor,
|
SymbolFor,
|
||||||
SymbolToStringTag,
|
SymbolToStringTag,
|
||||||
|
@ -787,7 +789,11 @@
|
||||||
|
|
||||||
setCurrentTarget(eventImpl, tuple.item);
|
setCurrentTarget(eventImpl, tuple.item);
|
||||||
|
|
||||||
|
try {
|
||||||
innerInvokeEventListeners(eventImpl, getListeners(tuple.item));
|
innerInvokeEventListeners(eventImpl, getListeners(tuple.item));
|
||||||
|
} catch (error) {
|
||||||
|
reportException(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeAddEventHandlerOptions(
|
function normalizeAddEventHandlerOptions(
|
||||||
|
@ -1317,6 +1323,49 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reportExceptionStackedCalls = 0;
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/#report-the-exception
|
||||||
|
function reportException(error) {
|
||||||
|
reportExceptionStackedCalls++;
|
||||||
|
const jsError = core.destructureError(error);
|
||||||
|
const message = jsError.message;
|
||||||
|
let filename = "";
|
||||||
|
let lineno = 0;
|
||||||
|
let colno = 0;
|
||||||
|
if (jsError.frames.length > 0) {
|
||||||
|
filename = jsError.frames[0].fileName;
|
||||||
|
lineno = jsError.frames[0].lineNumber;
|
||||||
|
colno = jsError.frames[0].columnNumber;
|
||||||
|
} else {
|
||||||
|
const jsError = core.destructureError(new Error());
|
||||||
|
for (const frame of jsError.frames) {
|
||||||
|
if (
|
||||||
|
typeof frame.fileName == "string" &&
|
||||||
|
!StringPrototypeStartsWith(frame.fileName, "deno:")
|
||||||
|
) {
|
||||||
|
filename = frame.fileName;
|
||||||
|
lineno = frame.lineNumber;
|
||||||
|
colno = frame.columnNumber;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const event = new ErrorEvent("error", {
|
||||||
|
cancelable: true,
|
||||||
|
message,
|
||||||
|
filename,
|
||||||
|
lineno,
|
||||||
|
colno,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
// Avoid recursing `reportException()` via error handlers more than once.
|
||||||
|
if (reportExceptionStackedCalls > 1 || window.dispatchEvent(event)) {
|
||||||
|
core.terminate(error);
|
||||||
|
}
|
||||||
|
reportExceptionStackedCalls--;
|
||||||
|
}
|
||||||
|
|
||||||
window.Event = Event;
|
window.Event = Event;
|
||||||
window.EventTarget = EventTarget;
|
window.EventTarget = EventTarget;
|
||||||
window.ErrorEvent = ErrorEvent;
|
window.ErrorEvent = ErrorEvent;
|
||||||
|
@ -1333,6 +1382,7 @@
|
||||||
listenerCount,
|
listenerCount,
|
||||||
};
|
};
|
||||||
window.__bootstrap.event = {
|
window.__bootstrap.event = {
|
||||||
|
reportException,
|
||||||
setIsTrusted,
|
setIsTrusted,
|
||||||
setTarget,
|
setTarget,
|
||||||
defineEventHandler,
|
defineEventHandler,
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
TypeError,
|
TypeError,
|
||||||
} = window.__bootstrap.primordials;
|
} = window.__bootstrap.primordials;
|
||||||
const { webidl } = window.__bootstrap;
|
const { webidl } = window.__bootstrap;
|
||||||
|
const { reportException } = window.__bootstrap.event;
|
||||||
const { assert } = window.__bootstrap.infra;
|
const { assert } = window.__bootstrap.infra;
|
||||||
|
|
||||||
function opNow() {
|
function opNow() {
|
||||||
|
@ -139,13 +140,16 @@
|
||||||
|
|
||||||
// 2.
|
// 2.
|
||||||
// 3.
|
// 3.
|
||||||
// TODO(@andreubotella): Error handling.
|
|
||||||
if (typeof callback === "function") {
|
if (typeof callback === "function") {
|
||||||
|
try {
|
||||||
FunctionPrototypeCall(
|
FunctionPrototypeCall(
|
||||||
callback,
|
callback,
|
||||||
globalThis,
|
globalThis,
|
||||||
...new SafeArrayIterator(args),
|
...new SafeArrayIterator(args),
|
||||||
);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
reportException(error);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO(@andreubotella): eval doesn't seem to have a primordial, but
|
// TODO(@andreubotella): eval doesn't seem to have a primordial, but
|
||||||
// it can be redefined in the global scope.
|
// it can be redefined in the global scope.
|
||||||
|
|
|
@ -140,14 +140,16 @@
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
let handled = false;
|
|
||||||
|
|
||||||
this.dispatchEvent(event);
|
this.dispatchEvent(event);
|
||||||
if (event.defaultPrevented) {
|
// Don't bubble error event to window for loader errors (`!e.fileName`).
|
||||||
handled = true;
|
// TODO(nayeemrmn): Currently these are never bubbled because worker
|
||||||
|
// error event fields aren't populated correctly and `e.fileName` is
|
||||||
|
// always empty.
|
||||||
|
if (e.fileName && !event.defaultPrevented) {
|
||||||
|
window.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return event.defaultPrevented;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pollControl = async () => {
|
#pollControl = async () => {
|
||||||
|
@ -165,7 +167,7 @@
|
||||||
} /* falls through */
|
} /* falls through */
|
||||||
case 2: { // Error
|
case 2: { // Error
|
||||||
if (!this.#handleError(data)) {
|
if (!this.#handleError(data)) {
|
||||||
throw new Error("Unhandled error event in child worker.");
|
throw new Error("Unhandled error in child worker.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -558,6 +558,7 @@ delete Object.prototype.__proto__;
|
||||||
|
|
||||||
eventTarget.setEventTargetData(globalThis);
|
eventTarget.setEventTargetData(globalThis);
|
||||||
|
|
||||||
|
defineEventHandler(window, "error");
|
||||||
defineEventHandler(window, "load");
|
defineEventHandler(window, "load");
|
||||||
defineEventHandler(window, "unload");
|
defineEventHandler(window, "unload");
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ pub struct WebWorkerInternalHandle {
|
||||||
has_terminated: Arc<AtomicBool>,
|
has_terminated: Arc<AtomicBool>,
|
||||||
terminate_waker: Arc<AtomicWaker>,
|
terminate_waker: Arc<AtomicWaker>,
|
||||||
isolate_handle: v8::IsolateHandle,
|
isolate_handle: v8::IsolateHandle,
|
||||||
|
pub name: String,
|
||||||
pub worker_type: WebWorkerType,
|
pub worker_type: WebWorkerType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,6 +265,7 @@ impl WebWorkerHandle {
|
||||||
|
|
||||||
fn create_handles(
|
fn create_handles(
|
||||||
isolate_handle: v8::IsolateHandle,
|
isolate_handle: v8::IsolateHandle,
|
||||||
|
name: String,
|
||||||
worker_type: WebWorkerType,
|
worker_type: WebWorkerType,
|
||||||
) -> (WebWorkerInternalHandle, SendableWebWorkerHandle) {
|
) -> (WebWorkerInternalHandle, SendableWebWorkerHandle) {
|
||||||
let (parent_port, worker_port) = create_entangled_message_port();
|
let (parent_port, worker_port) = create_entangled_message_port();
|
||||||
|
@ -272,13 +274,14 @@ fn create_handles(
|
||||||
let has_terminated = Arc::new(AtomicBool::new(false));
|
let has_terminated = Arc::new(AtomicBool::new(false));
|
||||||
let terminate_waker = Arc::new(AtomicWaker::new());
|
let terminate_waker = Arc::new(AtomicWaker::new());
|
||||||
let internal_handle = WebWorkerInternalHandle {
|
let internal_handle = WebWorkerInternalHandle {
|
||||||
sender: ctrl_tx,
|
name,
|
||||||
port: Rc::new(parent_port),
|
port: Rc::new(parent_port),
|
||||||
termination_signal: termination_signal.clone(),
|
termination_signal: termination_signal.clone(),
|
||||||
has_terminated: has_terminated.clone(),
|
has_terminated: has_terminated.clone(),
|
||||||
terminate_waker: terminate_waker.clone(),
|
terminate_waker: terminate_waker.clone(),
|
||||||
isolate_handle: isolate_handle.clone(),
|
isolate_handle: isolate_handle.clone(),
|
||||||
cancel: CancelHandle::new_rc(),
|
cancel: CancelHandle::new_rc(),
|
||||||
|
sender: ctrl_tx,
|
||||||
worker_type,
|
worker_type,
|
||||||
};
|
};
|
||||||
let external_handle = SendableWebWorkerHandle {
|
let external_handle = SendableWebWorkerHandle {
|
||||||
|
@ -452,7 +455,7 @@ impl WebWorker {
|
||||||
let (internal_handle, external_handle) = {
|
let (internal_handle, external_handle) = {
|
||||||
let handle = js_runtime.v8_isolate().thread_safe_handle();
|
let handle = js_runtime.v8_isolate().thread_safe_handle();
|
||||||
let (internal_handle, external_handle) =
|
let (internal_handle, external_handle) =
|
||||||
create_handles(handle, options.worker_type);
|
create_handles(handle, name.clone(), options.worker_type);
|
||||||
let op_state = js_runtime.op_state();
|
let op_state = js_runtime.op_state();
|
||||||
let mut op_state = op_state.borrow_mut();
|
let mut op_state = op_state.borrow_mut();
|
||||||
op_state.put(internal_handle.clone());
|
op_state.put(internal_handle.clone());
|
||||||
|
|
|
@ -217,6 +217,10 @@ impl MainWorker {
|
||||||
async fn evaluate_module(&mut self, id: ModuleId) -> Result<(), AnyError> {
|
async fn evaluate_module(&mut self, id: ModuleId) -> Result<(), AnyError> {
|
||||||
let mut receiver = self.js_runtime.mod_evaluate(id);
|
let mut receiver = self.js_runtime.mod_evaluate(id);
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
// Not using biased mode leads to non-determinism for relatively simple
|
||||||
|
// programs.
|
||||||
|
biased;
|
||||||
|
|
||||||
maybe_result = &mut receiver => {
|
maybe_result = &mut receiver => {
|
||||||
debug!("received module evaluate {:#?}", maybe_result);
|
debug!("received module evaluate {:#?}", maybe_result);
|
||||||
maybe_result.expect("Module evaluation result not provided.")
|
maybe_result.expect("Module evaluation result not provided.")
|
||||||
|
|
Loading…
Reference in a new issue