summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2023-12-06 17:02:52 -0700
committerGitHub <noreply@github.com>2023-12-06 17:02:52 -0700
commit9314928990a6cbd0bc0abe3100872ba2682eda9a (patch)
tree462d19eeaac0974a752128ad5d8b64e1066be8af /runtime
parent68d356eed91731cd0c13eb946f296aa90ef4d5ac (diff)
chore: bump deno_core and update tests (#21467)
Landing changes required for https://github.com/denoland/deno_core/pull/359 We needed to update 99_main.js and a whole load of tests. API changes: - setPromiseRejectCallback becomes setUnhandledPromiseRejectionHandler. The function is now called from eventLoopTick. - The promiseRejectMacrotaskCallback no longer exists, as this is automatically handled in eventLoopTick. - ops.op_dispatch_exception now takes a second parameter: in_promise. The preferred way to call this op is now reportUnhandledException or reportUnhandledPromiseRejection.
Diffstat (limited to 'runtime')
-rw-r--r--runtime/fmt_errors.rs30
-rw-r--r--runtime/js/99_main.js120
-rw-r--r--runtime/web_worker.rs1
-rw-r--r--runtime/worker.rs1
4 files changed, 31 insertions, 121 deletions
diff --git a/runtime/fmt_errors.rs b/runtime/fmt_errors.rs
index 5dcb96ec7..7945842bd 100644
--- a/runtime/fmt_errors.rs
+++ b/runtime/fmt_errors.rs
@@ -9,25 +9,6 @@ use deno_core::error::JsError;
use deno_core::error::JsStackFrame;
use std::fmt::Write as _;
-/// Compares all properties of JsError, except for JsError::cause.
-/// This function is used to detect that 2 JsError objects in a JsError::cause
-/// chain are identical, ie. there is a recursive cause.
-/// 01_console.js, which also detects recursive causes, can use JS object
-/// comparisons to compare errors. We don't have access to JS object identity in
-/// format_js_error().
-fn errors_are_equal_without_cause(a: &JsError, b: &JsError) -> bool {
- a.name == b.name
- && a.message == b.message
- && a.stack == b.stack
- // `a.cause == b.cause` omitted, because it is absent in recursive errors,
- // despite the error being identical to a previously seen one.
- && a.exception_message == b.exception_message
- && a.frames == b.frames
- && a.source_line == b.source_line
- && a.source_line_frame_index == b.source_line_frame_index
- && a.aggregated == b.aggregated
-}
-
#[derive(Debug, Clone)]
struct ErrorReference<'a> {
from: &'a JsError,
@@ -191,10 +172,7 @@ fn find_recursive_cause(js_error: &JsError) -> Option<ErrorReference> {
while let Some(cause) = &current_error.cause {
history.push(current_error);
- if let Some(seen) = history
- .iter()
- .find(|&el| errors_are_equal_without_cause(el, cause.as_ref()))
- {
+ if let Some(seen) = history.iter().find(|&el| cause.is_same_error(el)) {
return Some(ErrorReference {
from: current_error,
to: seen,
@@ -246,7 +224,7 @@ fn format_js_error_inner(
s.push_str(&js_error.exception_message);
if let Some(circular) = &circular {
- if errors_are_equal_without_cause(js_error, circular.reference.to) {
+ if js_error.is_same_error(circular.reference.to) {
write!(s, " {}", cyan(format!("<ref *{}>", circular.index))).unwrap();
}
}
@@ -281,9 +259,7 @@ fn format_js_error_inner(
if let Some(cause) = &js_error.cause {
let is_caused_by_circular = circular
.as_ref()
- .map(|circular| {
- errors_are_equal_without_cause(circular.reference.from, js_error)
- })
+ .map(|circular| js_error.is_same_error(circular.reference.from))
.unwrap_or(false);
let error_string = if is_caused_by_circular {
diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js
index 6e43da085..050cd3bf8 100644
--- a/runtime/js/99_main.js
+++ b/runtime/js/99_main.js
@@ -9,12 +9,8 @@ const internals = globalThis.__bootstrap.internals;
const primordials = globalThis.__bootstrap.primordials;
const {
ArrayPrototypeFilter,
- ArrayPrototypeIndexOf,
ArrayPrototypeIncludes,
ArrayPrototypeMap,
- ArrayPrototypePush,
- ArrayPrototypeShift,
- ArrayPrototypeSplice,
DateNow,
Error,
ErrorPrototype,
@@ -27,13 +23,9 @@ const {
ObjectSetPrototypeOf,
PromisePrototypeThen,
PromiseResolve,
- SafeWeakMap,
Symbol,
SymbolIterator,
TypeError,
- WeakMapPrototypeDelete,
- WeakMapPrototypeGet,
- WeakMapPrototypeSet,
} = primordials;
import * as util from "ext:runtime/06_util.js";
import * as event from "ext:deno_web/02_event.js";
@@ -328,7 +320,6 @@ function runtimeStart(
target,
) {
core.setMacrotaskCallback(timers.handleTimerMacrotask);
- core.setMacrotaskCallback(promiseRejectMacrotaskCallback);
core.setWasmStreamingCallback(fetch.handleWasmStreaming);
core.setReportExceptionCallback(event.reportException);
ops.op_set_format_exception_callback(formatException);
@@ -340,91 +331,38 @@ function runtimeStart(
core.setBuildInfo(target);
}
-const pendingRejections = [];
-const pendingRejectionsReasons = new SafeWeakMap();
-
-function promiseRejectCallback(type, promise, reason) {
- switch (type) {
- case 0: {
- ops.op_store_pending_promise_rejection(promise, reason);
- ArrayPrototypePush(pendingRejections, promise);
- WeakMapPrototypeSet(pendingRejectionsReasons, promise, reason);
- break;
- }
- case 1: {
- ops.op_remove_pending_promise_rejection(promise);
- const index = ArrayPrototypeIndexOf(pendingRejections, promise);
- if (index > -1) {
- ArrayPrototypeSplice(pendingRejections, index, 1);
- WeakMapPrototypeDelete(pendingRejectionsReasons, promise);
- }
- break;
- }
- default:
- return false;
- }
-
- return !!globalThis_.onunhandledrejection ||
- event.listenerCount(globalThis_, "unhandledrejection") > 0 ||
- typeof internals.nodeProcessUnhandledRejectionCallback !== "undefined";
-}
-
-function promiseRejectMacrotaskCallback() {
- // We have no work to do, tell the runtime that we don't
- // need to perform microtask checkpoint.
- if (pendingRejections.length === 0) {
- return undefined;
- }
-
- while (pendingRejections.length > 0) {
- const promise = ArrayPrototypeShift(pendingRejections);
- const hasPendingException = ops.op_has_pending_promise_rejection(
+core.setUnhandledPromiseRejectionHandler(processUnhandledPromiseRejection);
+// Notification that the core received an unhandled promise rejection that is about to
+// terminate the runtime. If we can handle it, attempt to do so.
+function processUnhandledPromiseRejection(promise, reason) {
+ const rejectionEvent = new event.PromiseRejectionEvent(
+ "unhandledrejection",
+ {
+ cancelable: true,
promise,
- );
- const reason = WeakMapPrototypeGet(pendingRejectionsReasons, promise);
- WeakMapPrototypeDelete(pendingRejectionsReasons, promise);
+ reason,
+ },
+ );
- if (!hasPendingException) {
- continue;
- }
+ // Note that the handler may throw, causing a recursive "error" event
+ globalThis_.dispatchEvent(rejectionEvent);
- const rejectionEvent = new event.PromiseRejectionEvent(
- "unhandledrejection",
- {
- cancelable: true,
- promise,
- reason,
- },
- );
-
- const errorEventCb = (event) => {
- if (event.error === reason) {
- ops.op_remove_pending_promise_rejection(promise);
- }
- };
- // Add a callback for "error" event - it will be dispatched
- // if error is thrown during dispatch of "unhandledrejection"
- // event.
- globalThis_.addEventListener("error", errorEventCb);
- globalThis_.dispatchEvent(rejectionEvent);
- globalThis_.removeEventListener("error", errorEventCb);
-
- // If event was not yet prevented, try handing it off to Node compat layer
- // (if it was initialized)
- if (
- !rejectionEvent.defaultPrevented &&
- typeof internals.nodeProcessUnhandledRejectionCallback !== "undefined"
- ) {
- internals.nodeProcessUnhandledRejectionCallback(rejectionEvent);
- }
+ // If event was not yet prevented, try handing it off to Node compat layer
+ // (if it was initialized)
+ if (
+ !rejectionEvent.defaultPrevented &&
+ typeof internals.nodeProcessUnhandledRejectionCallback !== "undefined"
+ ) {
+ internals.nodeProcessUnhandledRejectionCallback(rejectionEvent);
+ }
- // If event was not prevented (or "unhandledrejection" listeners didn't
- // throw) we will let Rust side handle it.
- if (rejectionEvent.defaultPrevented) {
- ops.op_remove_pending_promise_rejection(promise);
- }
+ // If event was not prevented (or "unhandledrejection" listeners didn't
+ // throw) we will let Rust side handle it.
+ if (rejectionEvent.defaultPrevented) {
+ return true;
}
- return true;
+
+ return false;
}
let hasBootstrapped = false;
@@ -523,8 +461,6 @@ function bootstrapMainRuntime(runtimeOptions) {
event.defineEventHandler(globalThis, "unload");
event.defineEventHandler(globalThis, "unhandledrejection");
- core.setPromiseRejectCallback(promiseRejectCallback);
-
runtimeStart(
denoVersion,
v8Version,
@@ -642,8 +578,6 @@ function bootstrapWorkerRuntime(
event.defineEventHandler(self, "error", undefined, true);
event.defineEventHandler(self, "unhandledrejection");
- core.setPromiseRejectCallback(promiseRejectCallback);
-
// `Deno.exit()` is an alias to `self.close()`. Setting and exit
// code using an op in worker context is a no-op.
os.setExitHandler((_exitCode) => {
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index e5adf4cc6..5b8c1944a 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -182,6 +182,7 @@ impl WebWorkerInternalHandle {
/// This function will set terminated to true, terminate the isolate and close the message channel
pub fn terminate(&mut self) {
self.cancel.cancel();
+ self.terminate_waker.wake();
// This function can be called multiple times by whomever holds
// the handle. However only a single "termination" should occur so
diff --git a/runtime/worker.rs b/runtime/worker.rs
index e3e97de7e..3267bd78d 100644
--- a/runtime/worker.rs
+++ b/runtime/worker.rs
@@ -1,5 +1,4 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
use std::rc::Rc;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering::Relaxed;