Repository: denoland/deno_core
Pull request #598 (2024-02-23 20:57:19)

fix(core): ensure `this` receiver in setTimeout and handle errors


Patch:
diff --git a/dprint.json b/.dprint.json
similarity index 100%
rename from dprint.json
rename to .dprint.json
diff --git a/.rustfmt.toml b/.rustfmt.toml
index 8e60d0c..9bb8d9d 100644
--- a/.rustfmt.toml
+++ b/.rustfmt.toml
@@ -1,3 +1,3 @@
 max_width = 80
 tab_spaces = 2
-edition = "2021"
\ No newline at end of file
+edition = "2021"
diff --git a/core/01_core.js b/core/01_core.js
index 0ca898d..18980ec 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -178,7 +178,12 @@
     if (timers) {
       for (let i = 0; i < timers.length; i += 2) {
         timerDepth = timers[i];
-        timers[i + 1]();
+        try {
+          const f = timers[i + 1];
+          f.call(window);
+        } catch (e) {
+          reportExceptionCallback(e);
+        }
         op_run_microtasks();
       }
       timerDepth = 0;
@@ -244,7 +249,9 @@
     };
   }
 
-  let reportExceptionCallback = undefined;
+  let reportExceptionCallback = (error) => {
+    op_dispatch_exception(error, false);
+  };
 
   // Used to report errors thrown from functions passed to `queueMicrotask()`.
   // The callback will be passed the thrown error. For example, you can use this
@@ -252,10 +259,16 @@
   // In other words, set the implementation for
   // https://html.spec.whatwg.org/multipage/webappapis.html#report-the-exception
   function setReportExceptionCallback(cb) {
-    if (typeof cb != "function") {
-      throw new TypeError("expected a function");
+    if (cb === null || cb === undefined) {
+      reportExceptionCallback = (error) => {
+        op_dispatch_exception(error, false);
+      };
+    } else {
+      if (typeof cb != "function") {
+        throw new TypeError("expected a function");
+      }
+      reportExceptionCallback = cb;
     }
-    reportExceptionCallback = cb;
   }
 
   function queueMicrotask(cb) {
@@ -266,11 +279,7 @@
       try {
         cb();
       } catch (error) {
-        if (reportExceptionCallback) {
-          reportExceptionCallback(error);
-        } else {
-          throw error;
-        }
+        reportExceptionCallback(error);
       }
     });
   }
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 9a856df..caff0c0 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -29,9 +29,9 @@ unsafe_use_unprotected_platform = []
 
 [dependencies]
 anyhow.workspace = true
+bincode = { workspace = true, optional = true }
 bit-set.workspace = true
 bit-vec.workspace = true
-bincode = { workspace = true, optional = true }
 bytes.workspace = true
 cooked-waker.workspace = true
 deno_core_icudata = { workspace = true, optional = true }
diff --git a/core/arena/mod.rs b/core/arena/mod.rs
index 6a370d4..4fef787 100644
--- a/core/arena/mod.rs
+++ b/core/arena/mod.rs
@@ -4,10 +4,9 @@ mod shared_arena;
 mod shared_atomic_arena;
 mod unique_arena;
 
-use std::{
-  alloc::{handle_alloc_error, Layout},
-  ptr::NonNull,
-};
+use std::alloc::handle_alloc_error;
+use std::alloc::Layout;
+use std::ptr::NonNull;
 
 pub use raw_arena::*;
 pub use shared_arena::*;
diff --git a/ops/op2/README.md b/ops/op2/README.md
index 2d0bf8e..a1e9573 100644
--- a/ops/op2/README.md
+++ b/ops/op2/README.md
@@ -42,7 +42,7 @@ the function will return `None` and the future will be handled by Deno's pending
 op system.
 
 ```rust,ignore
-fn op_xyz(promise_id: i32, /* ... */) -> Option<X> {}
+fn op_xyz(promise_id: i32 /* ... */) -> Option<X> {}
 ```
 
 ### Eager `async` calls: `async`
diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml
index fba57c9..491502a 100644
--- a/serde_v8/Cargo.toml
+++ b/serde_v8/Cargo.toml
@@ -23,10 +23,10 @@ thiserror.workspace = true
 v8.workspace = true
 
 [dev-dependencies]
-serde_v8_utilities = { path = "./utilities" }
 bencher.workspace = true
-serde_json.workspace = true
 serde_bytes.workspace = true
+serde_json.workspace = true
+serde_v8_utilities = { path = "./utilities" }
 
 [[example]]
 name = "basic"
diff --git a/serde_v8/magic/rawbytes.rs b/serde_v8/magic/rawbytes.rs
index 3a02c69..27d349e 100644
--- a/serde_v8/magic/rawbytes.rs
+++ b/serde_v8/magic/rawbytes.rs
@@ -129,7 +129,8 @@ mod tests {
   use bytes::Bytes;
 
   use super::*;
-  use std::{mem, sync::Arc};
+  use std::mem;
+  use std::sync::Arc;
 
   const HELLO: &str = "hello";
 


Test patch:
diff --git a/ops/compile_test_runner/Cargo.toml b/ops/compile_test_runner/Cargo.toml
index 37a47f8..c7d7f74 100644
--- a/ops/compile_test_runner/Cargo.toml
+++ b/ops/compile_test_runner/Cargo.toml
@@ -5,21 +5,21 @@ version = "0.2.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
+publish = false
 readme = "README.md"
 repository.workspace = true
 description = "Compile-test runner for deno_ops"
-publish = false
 
 [lib]
 
 [dev-dependencies]
-trybuild = "1.0"
+bytes.workspace = true
+deno_core.workspace = true
+deno_ops.workspace = true
 pretty_assertions.workspace = true
 prettyplease = "0.2.9"
-testing_macros = "0.2.11"
-deno_ops.workspace = true
-deno_core.workspace = true
-syn.workspace = true
-bytes.workspace = true
-serde.workspace = true
 rustversion = "1.0"
+serde.workspace = true
+syn.workspace = true
+testing_macros = "0.2.11"
+trybuild = "1.0"
diff --git a/ops/op2/test_cases/async/async_arg_return.rs b/ops/op2/test_cases/async/async_arg_return.rs
index b7e7883..a66ca93 100644
--- a/ops/op2/test_cases/async/async_arg_return.rs
+++ b/ops/op2/test_cases/async/async_arg_return.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(async)]
 pub async fn op_async(x: i32) -> i32 {
-    x
+  x
 }
diff --git a/ops/op2/test_cases/async/async_arg_return_result.rs b/ops/op2/test_cases/async/async_arg_return_result.rs
index c3c6b00..198370a 100644
--- a/ops/op2/test_cases/async/async_arg_return_result.rs
+++ b/ops/op2/test_cases/async/async_arg_return_result.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(async)]
 pub async fn op_async(x: i32) -> std::io::Result<i32> {
-    Ok(x)
+  Ok(x)
 }
diff --git a/ops/op2/test_cases/async/async_deferred.rs b/ops/op2/test_cases/async/async_deferred.rs
index 95665b7..7703fdb 100644
--- a/ops/op2/test_cases/async/async_deferred.rs
+++ b/ops/op2/test_cases/async/async_deferred.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(async(deferred), fast)]
 pub async fn op_async_deferred() -> std::io::Result<i32> {
-    Ok(0)
+  Ok(0)
 }
diff --git a/ops/op2/test_cases/async/async_jsbuffer.rs b/ops/op2/test_cases/async/async_jsbuffer.rs
index 2be678d..c3f33c7 100644
--- a/ops/op2/test_cases/async/async_jsbuffer.rs
+++ b/ops/op2/test_cases/async/async_jsbuffer.rs
@@ -7,5 +7,5 @@ use deno_core::JsBuffer;
 #[op2(async)]
 #[buffer]
 pub async fn op_async_v8_buffer(#[buffer] buf: JsBuffer) -> JsBuffer {
-    buf
+  buf
 }
diff --git a/ops/op2/test_cases/async/async_lazy.rs b/ops/op2/test_cases/async/async_lazy.rs
index 2a4cde7..9e282da 100644
--- a/ops/op2/test_cases/async/async_lazy.rs
+++ b/ops/op2/test_cases/async/async_lazy.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(async(lazy), fast)]
 pub async fn op_async_lazy() -> std::io::Result<i32> {
-    Ok(0)
+  Ok(0)
 }
diff --git a/ops/op2/test_cases/async/async_opstate.rs b/ops/op2/test_cases/async/async_opstate.rs
index 000b2d1..706cf3b 100644
--- a/ops/op2/test_cases/async/async_opstate.rs
+++ b/ops/op2/test_cases/async/async_opstate.rs
@@ -2,11 +2,13 @@
 #![deny(warnings)]
 deno_ops_compile_test_runner::prelude!();
 
-use std::rc::Rc;
-use std::cell::RefCell;
 use deno_core::OpState;
+use std::cell::RefCell;
+use std::rc::Rc;
 
 #[op2(async)]
-pub async fn op_async_opstate(state: Rc<RefCell<OpState>>) -> std::io::Result<i32> {
-    Ok(*state.borrow().borrow::<i32>())
+pub async fn op_async_opstate(
+  state: Rc<RefCell<OpState>>,
+) -> std::io::Result<i32> {
+  Ok(*state.borrow().borrow::<i32>())
 }
diff --git a/ops/op2/test_cases/async/async_result.rs b/ops/op2/test_cases/async/async_result.rs
index 7fb1a32..9771a2a 100644
--- a/ops/op2/test_cases/async/async_result.rs
+++ b/ops/op2/test_cases/async/async_result.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(async)]
 pub async fn op_async() -> std::io::Result<i32> {
-    Ok(0)
+  Ok(0)
 }
diff --git a/ops/op2/test_cases/async/async_result_impl.rs b/ops/op2/test_cases/async/async_result_impl.rs
index 71588ba..f2d996a 100644
--- a/ops/op2/test_cases/async/async_result_impl.rs
+++ b/ops/op2/test_cases/async/async_result_impl.rs
@@ -2,12 +2,12 @@
 #![deny(warnings)]
 deno_ops_compile_test_runner::prelude!();
 
-use std::future::Future;
 use deno_core::error::AnyError;
+use std::future::Future;
 
 #[op2(async)]
-pub fn op_async_result_impl(x: i32) -> Result<impl Future<Output = std::io::Result<i32>>, AnyError> {
-    Ok(async move {
-        Ok(x)
-    })
+pub fn op_async_result_impl(
+  x: i32,
+) -> Result<impl Future<Output = std::io::Result<i32>>, AnyError> {
+  Ok(async move { Ok(x) })
 }
diff --git a/ops/op2/test_cases/async/async_result_smi.rs b/ops/op2/test_cases/async/async_result_smi.rs
index f620845..40311ed 100644
--- a/ops/op2/test_cases/async/async_result_smi.rs
+++ b/ops/op2/test_cases/async/async_result_smi.rs
@@ -7,5 +7,5 @@ pub type ResourceId = i16;
 #[op2(async)]
 #[smi]
 pub async fn op_async(#[smi] rid: ResourceId) -> std::io::Result<ResourceId> {
-    Ok(rid as _)
+  Ok(rid as _)
 }
diff --git a/ops/op2/test_cases/compiler_pass/async.rs b/ops/op2/test_cases/compiler_pass/async.rs
index b3db841..f4a7dee 100644
--- a/ops/op2/test_cases/compiler_pass/async.rs
+++ b/ops/op2/test_cases/compiler_pass/async.rs
@@ -2,12 +2,12 @@
 #![deny(warnings)]
 deno_ops_compile_test_runner::prelude!();
 
-use std::rc::Rc;
-use std::cell::RefCell;
-use std::future::Future;
 use deno_core::error::AnyError;
-use deno_core::OpState;
 use deno_core::JsBuffer;
+use deno_core::OpState;
+use std::cell::RefCell;
+use std::future::Future;
+use std::rc::Rc;
 
 // Collect a few examples that we'll smoke test when not running on the CI.
 
@@ -26,16 +26,14 @@ pub async fn op_async3(x: i32) -> std::io::Result<i32> {
 
 #[op2(async)]
 pub fn op_async4(x: i32) -> Result<impl Future<Output = i32>, AnyError> {
-  Ok(async move {
-    x
-  })
+  Ok(async move { x })
 }
 
 #[op2(async)]
-pub fn op_async5(x: i32) -> Result<impl Future<Output = std::io::Result<i32>>, AnyError> {
-  Ok(async move {
-    Ok(x)
-  })
+pub fn op_async5(
+  x: i32,
+) -> Result<impl Future<Output = std::io::Result<i32>>, AnyError> {
+  Ok(async move { Ok(x) })
 }
 
 #[op2(async)]
@@ -44,7 +42,9 @@ pub async fn op_async6(x: f32) -> f32 {
 }
 
 #[op2(async)]
-pub async fn op_async_opstate(state: Rc<RefCell<OpState>>) -> std::io::Result<i32> {
+pub async fn op_async_opstate(
+  state: Rc<RefCell<OpState>>,
+) -> std::io::Result<i32> {
   Ok(*state.borrow().borrow::<i32>())
 }
 
diff --git a/ops/op2/test_cases/compiler_pass/sync.rs b/ops/op2/test_cases/compiler_pass/sync.rs
index 7c82c8a..ae07f98 100644
--- a/ops/op2/test_cases/compiler_pass/sync.rs
+++ b/ops/op2/test_cases/compiler_pass/sync.rs
@@ -8,17 +8,20 @@ use deno_core::v8;
 
 #[op2(fast)]
 pub fn op_fast(x: u32) -> u32 {
-    x
+  x
 }
 
 #[op2(fast)]
-fn op_buffers(#[buffer] _a: &[u8], #[buffer(copy)] _b: Vec<u8>) {
-}
+fn op_buffers(#[buffer] _a: &[u8], #[buffer(copy)] _b: Vec<u8>) {}
 
 struct Something {}
 
 #[op2(fast)]
-fn op_state_rc(#[state] _arg: &Something, #[state] _arg_opt: Option<&Something>) {}
+fn op_state_rc(
+  #[state] _arg: &Something,
+  #[state] _arg_opt: Option<&Something>,
+) {
+}
 
 #[op2(fast)]
 fn op_v8_1(_s: v8::Local<v8::String>) {}
@@ -36,12 +39,22 @@ pub type Uint32 = u32;
 
 #[op2(fast)]
 #[smi]
-fn op_smi_unsigned_return(#[smi] a: Int16, #[smi] b: Int32, #[smi] c: Uint16, #[smi] d: Uint32) -> Uint32 {
+fn op_smi_unsigned_return(
+  #[smi] a: Int16,
+  #[smi] b: Int32,
+  #[smi] c: Uint16,
+  #[smi] d: Uint32,
+) -> Uint32 {
   a as Uint32 + b as Uint32 + c as Uint32 + d as Uint32
 }
 
 #[op2(fast)]
 #[smi]
-fn op_smi_signed_return(#[smi] a: Int16, #[smi] b: Int32, #[smi] c: Uint16, #[smi] d: Uint32) -> Int32 {
+fn op_smi_signed_return(
+  #[smi] a: Int16,
+  #[smi] b: Int32,
+  #[smi] c: Uint16,
+  #[smi] d: Uint32,
+) -> Int32 {
   a as Int32 + b as Int32 + c as Int32 + d as Int32
 }
diff --git a/ops/op2/test_cases/sync/bool.rs b/ops/op2/test_cases/sync/bool.rs
index c5ced32..04c9043 100644
--- a/ops/op2/test_cases/sync/bool.rs
+++ b/ops/op2/test_cases/sync/bool.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(fast)]
 pub fn op_bool(arg: bool) -> bool {
-    arg
+  arg
 }
diff --git a/ops/op2/test_cases/sync/bool_result.rs b/ops/op2/test_cases/sync/bool_result.rs
index 2cb422f..a4bedf8 100644
--- a/ops/op2/test_cases/sync/bool_result.rs
+++ b/ops/op2/test_cases/sync/bool_result.rs
@@ -6,5 +6,5 @@ use deno_core::error::AnyError;
 
 #[op2(fast)]
 pub fn op_bool(arg: bool) -> Result<bool, AnyError> {
-    Ok(arg)
+  Ok(arg)
 }
diff --git a/ops/op2/test_cases/sync/buffers.rs b/ops/op2/test_cases/sync/buffers.rs
index 5e9305b..70cb764 100644
--- a/ops/op2/test_cases/sync/buffers.rs
+++ b/ops/op2/test_cases/sync/buffers.rs
@@ -5,13 +5,26 @@ deno_ops_compile_test_runner::prelude!();
 use deno_core::JsBuffer;
 
 #[op2(fast)]
-fn op_buffers(#[buffer] _a: &[u8], #[buffer] _b: &mut [u8], #[buffer] _c: *const u8, #[buffer] _d: *mut u8) {
+fn op_buffers(
+  #[buffer] _a: &[u8],
+  #[buffer] _b: &mut [u8],
+  #[buffer] _c: *const u8,
+  #[buffer] _d: *mut u8,
+) {
 }
 
 #[op2(fast)]
-fn op_buffers_32(#[buffer] _a: &[u32], #[buffer] _b: &mut [u32], #[buffer] _c: *const u32, #[buffer] _d: *mut u32) {
+fn op_buffers_32(
+  #[buffer] _a: &[u32],
+  #[buffer] _b: &mut [u32],
+  #[buffer] _c: *const u32,
+  #[buffer] _d: *mut u32,
+) {
 }
 
 #[op2]
-fn op_buffers_option(#[buffer] _a: Option<&[u8]>, #[buffer] _b: Option<JsBuffer>) {
+fn op_buffers_option(
+  #[buffer] _a: Option<&[u8]>,
+  #[buffer] _b: Option<JsBuffer>,
+) {
 }
diff --git a/ops/op2/test_cases/sync/buffers_copy.rs b/ops/op2/test_cases/sync/buffers_copy.rs
index b0bf7fe..671954d 100644
--- a/ops/op2/test_cases/sync/buffers_copy.rs
+++ b/ops/op2/test_cases/sync/buffers_copy.rs
@@ -3,7 +3,11 @@
 deno_ops_compile_test_runner::prelude!();
 
 #[op2(fast)]
-fn op_buffers(#[buffer(copy)] _a: Vec<u8>, #[buffer(copy)] _b: Box<[u8]>, #[buffer(copy)] _c: bytes::Bytes) {
+fn op_buffers(
+  #[buffer(copy)] _a: Vec<u8>,
+  #[buffer(copy)] _b: Box<[u8]>,
+  #[buffer(copy)] _c: bytes::Bytes,
+) {
 }
 
 #[op2(fast)]
diff --git a/ops/op2/test_cases/sync/generics.rs b/ops/op2/test_cases/sync/generics.rs
index e6ada46..61d0ed6 100644
--- a/ops/op2/test_cases/sync/generics.rs
+++ b/ops/op2/test_cases/sync/generics.rs
@@ -11,4 +11,8 @@ pub fn op_generics<T: Trait>() {}
 pub fn op_generics_static<T: Trait + 'static>() {}
 
 #[op2(fast)]
-pub fn op_generics_static_where<T>() where T: Trait + 'static {}
+pub fn op_generics_static_where<T>()
+where
+  T: Trait + 'static,
+{
+}
diff --git a/ops/op2/test_cases/sync/op_state_attr.rs b/ops/op2/test_cases/sync/op_state_attr.rs
index 40efaad..867e88c 100644
--- a/ops/op2/test_cases/sync/op_state_attr.rs
+++ b/ops/op2/test_cases/sync/op_state_attr.rs
@@ -11,4 +11,8 @@ use std::borrow::BorrowMut;
 struct Something {}
 
 #[op2(fast)]
-fn op_state_rc(#[state] _arg: &Something, #[state] _arg_opt: Option<&Something>) {}
+fn op_state_rc(
+  #[state] _arg: &Something,
+  #[state] _arg_opt: Option<&Something>,
+) {
+}
diff --git a/ops/op2/test_cases/sync/op_state_rc.rs b/ops/op2/test_cases/sync/op_state_rc.rs
index 862158d..b5a3c25 100644
--- a/ops/op2/test_cases/sync/op_state_rc.rs
+++ b/ops/op2/test_cases/sync/op_state_rc.rs
@@ -2,9 +2,9 @@
 #![deny(warnings)]
 deno_ops_compile_test_runner::prelude!();
 
-use std::rc::Rc;
-use std::cell::RefCell;
 use deno_core::OpState;
+use std::cell::RefCell;
+use std::rc::Rc;
 
 #[op2(fast)]
 fn op_state_rc(_state: Rc<RefCell<OpState>>) {}
diff --git a/ops/op2/test_cases/sync/op_state_ref.rs b/ops/op2/test_cases/sync/op_state_ref.rs
index 08e4738..25b5b64 100644
--- a/ops/op2/test_cases/sync/op_state_ref.rs
+++ b/ops/op2/test_cases/sync/op_state_ref.rs
@@ -2,8 +2,8 @@
 #![deny(warnings)]
 deno_ops_compile_test_runner::prelude!();
 
-use deno_core::OpState;
 use deno_core::v8;
+use deno_core::OpState;
 
 // Test w/ import pollution
 #[allow(unused)]
@@ -18,7 +18,15 @@ fn op_state_ref(_state: &OpState) {}
 fn op_state_mut(_state: &mut OpState) {}
 
 #[op2]
-fn op_state_and_v8(_state: &mut OpState, #[global] _callback: v8::Global<v8::Function>) {}
+fn op_state_and_v8(
+  _state: &mut OpState,
+  #[global] _callback: v8::Global<v8::Function>,
+) {
+}
 
 #[op2(fast)]
-fn op_state_and_v8_local(_state: &mut OpState, _callback: v8::Local<v8::Function>) {}
+fn op_state_and_v8_local(
+  _state: &mut OpState,
+  _callback: v8::Local<v8::Function>,
+) {
+}
diff --git a/ops/op2/test_cases/sync/result_external.rs b/ops/op2/test_cases/sync/result_external.rs
index 742b5cc..c8aa346 100644
--- a/ops/op2/test_cases/sync/result_external.rs
+++ b/ops/op2/test_cases/sync/result_external.rs
@@ -6,5 +6,5 @@ use deno_core::error::AnyError;
 
 #[op2(fast)]
 pub fn op_external_with_result() -> Result<*mut std::ffi::c_void, AnyError> {
-    Ok(0 as _)
+  Ok(0 as _)
 }
diff --git a/ops/op2/test_cases/sync/result_primitive.rs b/ops/op2/test_cases/sync/result_primitive.rs
index e750169..417bbe8 100644
--- a/ops/op2/test_cases/sync/result_primitive.rs
+++ b/ops/op2/test_cases/sync/result_primitive.rs
@@ -6,5 +6,5 @@ use deno_core::error::AnyError;
 
 #[op2(fast)]
 pub fn op_u32_with_result() -> Result<u32, AnyError> {
-    Ok(0)
+  Ok(0)
 }
diff --git a/ops/op2/test_cases/sync/result_scope.rs b/ops/op2/test_cases/sync/result_scope.rs
index eab1e14..113f3fa 100644
--- a/ops/op2/test_cases/sync/result_scope.rs
+++ b/ops/op2/test_cases/sync/result_scope.rs
@@ -6,6 +6,8 @@ use deno_core::error::AnyError;
 use deno_core::v8;
 
 #[op2]
-pub fn op_void_with_result(_scope: &mut v8::HandleScope) -> Result<(), AnyError> {
-    Ok(())
+pub fn op_void_with_result(
+  _scope: &mut v8::HandleScope,
+) -> Result<(), AnyError> {
+  Ok(())
 }
diff --git a/ops/op2/test_cases/sync/result_void.rs b/ops/op2/test_cases/sync/result_void.rs
index 6e51c91..697a107 100644
--- a/ops/op2/test_cases/sync/result_void.rs
+++ b/ops/op2/test_cases/sync/result_void.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(fast)]
 pub fn op_void_with_result() -> std::io::Result<()> {
-    Ok(())
+  Ok(())
 }
diff --git a/ops/op2/test_cases/sync/serde_v8.rs b/ops/op2/test_cases/sync/serde_v8.rs
index c746360..b1aa7b7 100644
--- a/ops/op2/test_cases/sync/serde_v8.rs
+++ b/ops/op2/test_cases/sync/serde_v8.rs
@@ -2,8 +2,8 @@
 #![deny(warnings)]
 deno_ops_compile_test_runner::prelude!();
 
-use serde::Serialize;
 use serde::Deserialize;
+use serde::Serialize;
 
 #[derive(Serialize, Deserialize)]
 pub struct Input {}
@@ -13,5 +13,5 @@ pub struct Output {}
 #[op2]
 #[serde]
 pub fn op_serde_v8(#[serde] _input: Input) -> Output {
-    Output {}
+  Output {}
 }
diff --git a/ops/op2/test_cases/sync/smi.rs b/ops/op2/test_cases/sync/smi.rs
index d2c79c2..a84a4f0 100644
--- a/ops/op2/test_cases/sync/smi.rs
+++ b/ops/op2/test_cases/sync/smi.rs
@@ -9,13 +9,23 @@ pub type Uint32 = u32;
 
 #[op2(fast)]
 #[smi]
-fn op_smi_unsigned_return(#[smi] a: Int16, #[smi] b: Int32, #[smi] c: Uint16, #[smi] d: Uint32) -> Uint32 {
+fn op_smi_unsigned_return(
+  #[smi] a: Int16,
+  #[smi] b: Int32,
+  #[smi] c: Uint16,
+  #[smi] d: Uint32,
+) -> Uint32 {
   a as Uint32 + b as Uint32 + c as Uint32 + d as Uint32
 }
 
 #[op2(fast)]
 #[smi]
-fn op_smi_signed_return(#[smi] a: Int16, #[smi] b: Int32, #[smi] c: Uint16, #[smi] d: Uint32) -> Int32 {
+fn op_smi_signed_return(
+  #[smi] a: Int16,
+  #[smi] b: Int32,
+  #[smi] c: Uint16,
+  #[smi] d: Uint32,
+) -> Int32 {
   a as Int32 + b as Int32 + c as Int32 + d as Int32
 }
 
diff --git a/ops/op2/test_cases/sync/string_cow.rs b/ops/op2/test_cases/sync/string_cow.rs
index 59f3772..57b8526 100644
--- a/ops/op2/test_cases/sync/string_cow.rs
+++ b/ops/op2/test_cases/sync/string_cow.rs
@@ -6,5 +6,5 @@ use std::borrow::Cow;
 
 #[op2(fast)]
 fn op_string_cow(#[string] s: Cow<str>) -> u32 {
-    s.len() as _
+  s.len() as _
 }
diff --git a/ops/op2/test_cases/sync/string_onebyte.rs b/ops/op2/test_cases/sync/string_onebyte.rs
index b0f9559..2fa1fb2 100644
--- a/ops/op2/test_cases/sync/string_onebyte.rs
+++ b/ops/op2/test_cases/sync/string_onebyte.rs
@@ -6,5 +6,5 @@ use std::borrow::Cow;
 
 #[op2(fast)]
 fn op_string_onebyte(#[string(onebyte)] s: Cow<[u8]>) -> u32 {
-    s.len() as _
+  s.len() as _
 }
diff --git a/ops/op2/test_cases/sync/string_option_return.rs b/ops/op2/test_cases/sync/string_option_return.rs
index 76d63d5..fc69dfa 100644
--- a/ops/op2/test_cases/sync/string_option_return.rs
+++ b/ops/op2/test_cases/sync/string_option_return.rs
@@ -5,5 +5,5 @@ deno_ops_compile_test_runner::prelude!();
 #[op2]
 #[string]
 pub fn op_string_return(#[string] s: Option<String>) -> Option<String> {
-    s
+  s
 }
diff --git a/ops/op2/test_cases/sync/string_owned.rs b/ops/op2/test_cases/sync/string_owned.rs
index e2d623a..34273b4 100644
--- a/ops/op2/test_cases/sync/string_owned.rs
+++ b/ops/op2/test_cases/sync/string_owned.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(fast)]
 fn op_string_owned(#[string] s: String) -> u32 {
-    s.len() as _
+  s.len() as _
 }
diff --git a/ops/op2/test_cases/sync/string_ref.rs b/ops/op2/test_cases/sync/string_ref.rs
index 5f0f084..82fc3d0 100644
--- a/ops/op2/test_cases/sync/string_ref.rs
+++ b/ops/op2/test_cases/sync/string_ref.rs
@@ -4,5 +4,5 @@ deno_ops_compile_test_runner::prelude!();
 
 #[op2(fast)]
 fn op_string_owned(#[string] s: &str) -> u32 {
-    s.len() as _
+  s.len() as _
 }
diff --git a/ops/op2/test_cases/sync/string_return.rs b/ops/op2/test_cases/sync/string_return.rs
index 26e379a..7e0da29 100644
--- a/ops/op2/test_cases/sync/string_return.rs
+++ b/ops/op2/test_cases/sync/string_return.rs
@@ -6,17 +6,17 @@ use std::borrow::Cow;
 #[op2]
 #[string]
 pub fn op_string_return() -> String {
-    "".into()
+  "".into()
 }
 
 #[op2]
 #[string]
 pub fn op_string_return_ref() -> &'static str {
-    ""
+  ""
 }
 
 #[op2]
 #[string]
 pub fn op_string_return_cow<'a>() -> Cow<'a, str> {
-    "".into()
+  "".into()
 }
diff --git a/ops/op2/test_cases/sync/v8_global.rs b/ops/op2/test_cases/sync/v8_global.rs
index 5af404e..a98c1e6 100644
--- a/ops/op2/test_cases/sync/v8_global.rs
+++ b/ops/op2/test_cases/sync/v8_global.rs
@@ -6,6 +6,8 @@ use deno_core::v8;
 
 #[op2]
 #[global]
-pub fn op_global(#[global] g: v8::Global<v8::String>) -> v8::Global<v8::String> {
-    g
+pub fn op_global(
+  #[global] g: v8::Global<v8::String>,
+) -> v8::Global<v8::String> {
+  g
 }
diff --git a/ops/op2/test_cases/sync/v8_handlescope.rs b/ops/op2/test_cases/sync/v8_handlescope.rs
index 30fa245..596c67c 100644
--- a/ops/op2/test_cases/sync/v8_handlescope.rs
+++ b/ops/op2/test_cases/sync/v8_handlescope.rs
@@ -5,6 +5,9 @@ deno_ops_compile_test_runner::prelude!();
 use deno_core::v8;
 
 #[op2]
-fn op_handlescope<'a>(_scope: &v8::HandleScope<'a>, _str2: v8::Local<v8::String>) -> v8::Local<'a, v8::String> {
-    unimplemented!()
+fn op_handlescope<'a>(
+  _scope: &v8::HandleScope<'a>,
+  _str2: v8::Local<v8::String>,
+) -> v8::Local<'a, v8::String> {
+  unimplemented!()
 }
diff --git a/ops/op2/test_cases/sync/v8_lifetime.rs b/ops/op2/test_cases/sync/v8_lifetime.rs
index e1ca23d..d16fcf6 100644
--- a/ops/op2/test_cases/sync/v8_lifetime.rs
+++ b/ops/op2/test_cases/sync/v8_lifetime.rs
@@ -5,6 +5,8 @@ deno_ops_compile_test_runner::prelude!();
 use deno_core::v8;
 
 #[op2]
-pub fn op_v8_lifetime<'s>(_s: v8::Local<'s, v8::String>) -> v8::Local<'s, v8::String> {
-    unimplemented!()
+pub fn op_v8_lifetime<'s>(
+  _s: v8::Local<'s, v8::String>,
+) -> v8::Local<'s, v8::String> {
+  unimplemented!()
 }
diff --git a/ops/op2/test_cases/sync/v8_ref_option.rs b/ops/op2/test_cases/sync/v8_ref_option.rs
index 7dcfc10..e4dbc06 100644
--- a/ops/op2/test_cases/sync/v8_ref_option.rs
+++ b/ops/op2/test_cases/sync/v8_ref_option.rs
@@ -6,4 +6,3 @@ use deno_core::v8;
 
 #[op2(fast)]
 pub fn op_v8_lifetime<'s>(_s: Option<&v8::String>, _s2: Option<&v8::String>) {}
-
diff --git a/ops/op2/test_cases/sync/v8_string.rs b/ops/op2/test_cases/sync/v8_string.rs
index 5f6f52a..b2dd918 100644
--- a/ops/op2/test_cases/sync/v8_string.rs
+++ b/ops/op2/test_cases/sync/v8_string.rs
@@ -5,6 +5,9 @@ deno_ops_compile_test_runner::prelude!();
 use deno_core::v8;
 
 #[op2]
-fn op_v8_string<'a>(_str1: &v8::String, _str2: v8::Local<v8::String>) -> v8::Local<'a, v8::String> {
-    unimplemented!()
+fn op_v8_string<'a>(
+  _str1: &v8::String,
+  _str2: v8::Local<v8::String>,
+) -> v8::Local<'a, v8::String> {
+  unimplemented!()
 }
diff --git a/testing/Cargo.toml b/testing/Cargo.toml
index 62b5a99..a94e0d6 100644
--- a/testing/Cargo.toml
+++ b/testing/Cargo.toml
@@ -3,10 +3,10 @@
 [package]
 name = "deno_core_testing"
 version = "0.0.0"
-publish = false
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
+publish = false
 readme = "README.md"
 repository.workspace = true
 
@@ -14,12 +14,12 @@ repository.workspace = true
 path = "./lib.rs"
 
 [dev-dependencies]
+anyhow.workspace = true
+deno_ast.workspace = true
 deno_core.workspace = true
 deno_core.features = ["unsafe_use_unprotected_platform"]
+futures.workspace = true
 pretty_assertions.workspace = true
 prettyplease.workspace = true
 testing_macros.workspace = true
-anyhow.workspace = true
-deno_ast.workspace = true
-futures.workspace = true
 tokio.workspace = true
diff --git a/testing/checkin/runtime/__init.js b/testing/checkin/runtime/__init.js
index bbebf73..98504bc 100644
--- a/testing/checkin/runtime/__init.js
+++ b/testing/checkin/runtime/__init.js
@@ -18,6 +18,24 @@ globalThis.clearTimeout = timers.clearTimeout;
 globalThis.clearInterval = timers.clearInterval;
 globalThis.Worker = worker.Worker;
 globalThis.throwInExt = throw_.throwInExt;
+Reflect.defineProperty(globalThis, "onerror", {
+  set: (cb) => {
+    if (cb) {
+      Deno.core.setReportExceptionCallback((error) => {
+        let defaultPrevented = false;
+        cb({
+          error,
+          preventDefault: () => defaultPrevented = true,
+        });
+        if (!defaultPrevented) {
+          Deno.core.reportUnhandledException(error);
+        }
+      });
+    } else {
+      Deno.core.setReportExceptionCallback(null);
+    }
+  },
+});
 Reflect.defineProperty(globalThis, "onunhandledrejection", {
   set: (cb) => {
     if (cb) {
diff --git a/testing/unit/timer_test.ts b/testing/unit/timer_test.ts
index ddcfd68..e124227 100644
--- a/testing/unit/timer_test.ts
+++ b/testing/unit/timer_test.ts
@@ -86,3 +86,32 @@ test(async function testMicrotaskOrdering() {
   await promise;
   assertEquals(s, "promise\nno promise\n");
 });
+
+test(async function testTimerException() {
+  const { promise, resolve } = Promise.withResolvers<Error>();
+  globalThis.onerror = (e: ErrorEvent) => {
+    resolve(e.error);
+    e.preventDefault();
+  };
+  try {
+    setTimeout(() => {
+      throw new Error("timeout error");
+    });
+    assertEquals("timeout error", (await promise).message);
+  } finally {
+    globalThis.onerror = null;
+  }
+});
+
+test(async function testTimerThis() {
+  const { promise, resolve, reject } = Promise.withResolvers();
+  setTimeout(function () {
+    try {
+      assertEquals(this, globalThis);
+      resolve(0);
+    } catch (e) {
+      reject(e);
+    }
+  }, 1);
+  await promise;
+});