diff options
| author | Matt Mastracci <matthew@mastracci.com> | 2023-12-06 17:02:52 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-12-06 17:02:52 -0700 |
| commit | 9314928990a6cbd0bc0abe3100872ba2682eda9a (patch) | |
| tree | 462d19eeaac0974a752128ad5d8b64e1066be8af /runtime | |
| parent | 68d356eed91731cd0c13eb946f296aa90ef4d5ac (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.rs | 30 | ||||
| -rw-r--r-- | runtime/js/99_main.js | 120 | ||||
| -rw-r--r-- | runtime/web_worker.rs | 1 | ||||
| -rw-r--r-- | runtime/worker.rs | 1 |
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) = ¤t_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; |
