Repository: denoland/deno_core
Pull request #602 (2024-02-24 01:46:44)

refactor: Remove deno_core::Snapshot
This commit removes `deno_core::Snapshot`.

Embedders need to pass a `&'static [u8]` for the startup
snapshot now.

It was an unnecessary abstraction that complicated things.

To satisfy test requirements, all snapshots are leaked. It's not
a big deal, because they are really small and this setup better
corresponds with the real world usage (and doesn't require
expensive integration tests that would need to compile a full
fledged binary).


Patch:
diff --git a/.github/workflows/ci-job.yml b/.github/workflows/ci-job.yml
index 111b016..4753ec1 100644
--- a/.github/workflows/ci-job.yml
+++ b/.github/workflows/ci-job.yml
@@ -41,7 +41,8 @@ jobs:
 
       - name: Install ARM runner tools
         if: ${{ inputs.os == 'ubuntu-22.04-arm64' }}
-        run: sudo apt update && sudo apt-get install -y unzip clang
+        run: |
+          sudo apt update && sudo apt-get install -y unzip clang
 
       - name: Install Rust
         uses: dsherret/rust-toolchain-file@v1
diff --git a/.github/workflows/ci-lint/action.yml b/.github/workflows/ci-lint/action.yml
index f0b5d67..d3787e3 100644
--- a/.github/workflows/ci-lint/action.yml
+++ b/.github/workflows/ci-lint/action.yml
@@ -7,6 +7,10 @@ runs:
       run: |
         cargo fmt -- --check
         deno fmt --check ./core/ ./ops/ ./serde_v8/
+    - name: tsc
+      shell: bash
+      run: |
+        deno run --allow-read --allow-env npm:typescript@5.3.3/tsc --noEmit -p testing/tsconfig.json
     - name: Lint
       shell: bash
       run: |
diff --git a/core/01_core.js b/core/01_core.js
index 18980ec..6a1b8dd 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -378,7 +378,7 @@
     );
   }
 
-  function ensureFastOps(keep) {
+  function ensureFastOps(keep = false) {
     return new Proxy({}, {
       get(_target, opName) {
         const op = ops[opName];
diff --git a/core/benches/snapshot/snapshot.rs b/core/benches/snapshot/snapshot.rs
index e2b01cc..316276f 100644
--- a/core/benches/snapshot/snapshot.rs
+++ b/core/benches/snapshot/snapshot.rs
@@ -6,7 +6,6 @@ use deno_core::ExtensionFileSourceCode;
 use deno_core::JsRuntime;
 use deno_core::JsRuntimeForSnapshot;
 use deno_core::RuntimeOptions;
-use deno_core::Snapshot;
 use std::time::Duration;
 use std::time::Instant;
 
@@ -137,7 +136,7 @@ fn bench_load_snapshot(c: &mut Criterion) {
         let now = Instant::now();
         let runtime = JsRuntime::new(RuntimeOptions {
           extensions: make_extensions_ops(),
-          startup_snapshot: Some(Snapshot::Static(snapshot)),
+          startup_snapshot: Some(snapshot),
           ..Default::default()
         });
         total += now.elapsed().as_nanos();
diff --git a/core/internal.d.ts b/core/internal.d.ts
index b09d188..9986c63 100644
--- a/core/internal.d.ts
+++ b/core/internal.d.ts
@@ -46,7 +46,7 @@ declare namespace __bootstrap {
    * primordials.StringPrototypeStartsWith('thing', 'hello')
    * ```
    */
-  declare namespace primordials {
+  namespace primordials {
     type UncurryThis<T extends (this: unknown, ...args: unknown[]) => unknown> =
       (self: ThisParameterType<T>, ...args: Parameters<T>) => ReturnType<T>;
     type UncurryThisStaticApply<
diff --git a/core/lib.deno_core.d.ts b/core/lib.deno_core.d.ts
index 173e055..7252002 100644
--- a/core/lib.deno_core.d.ts
+++ b/core/lib.deno_core.d.ts
@@ -8,7 +8,7 @@
 declare namespace Deno {
   namespace core {
     /** Returns a proxy that generates the fast versions of sync and async ops. */
-    function ensureFastOps(): any;
+    function ensureFastOps(keep?: boolean): any;
 
     /** Mark following promise as "ref", ie. event loop won't exit
      * until all "ref" promises are resolved. All async ops are "ref" by default. */
diff --git a/core/lib.rs b/core/lib.rs
index e19e55d..aa51077 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -140,7 +140,6 @@ pub use crate::runtime::JsRuntimeForSnapshot;
 pub use crate::runtime::PollEventLoopOptions;
 pub use crate::runtime::RuntimeOptions;
 pub use crate::runtime::SharedArrayBufferStore;
-pub use crate::runtime::Snapshot;
 pub use crate::runtime::V8_WRAPPER_OBJECT_INDEX;
 pub use crate::runtime::V8_WRAPPER_TYPE_INDEX;
 pub use crate::source_map::SourceMapGetter;
@@ -180,7 +179,6 @@ pub mod snapshot {
   pub use crate::runtime::CreateSnapshotOptions;
   pub use crate::runtime::CreateSnapshotOutput;
   pub use crate::runtime::FilterFn;
-  pub use crate::runtime::Snapshot;
 }
 
 /// A helper macro that will return a call site in Rust code. Should be
diff --git a/core/runtime/jsruntime.rs b/core/runtime/jsruntime.rs
index 0001436..4e1617e 100644
--- a/core/runtime/jsruntime.rs
+++ b/core/runtime/jsruntime.rs
@@ -46,7 +46,6 @@ use crate::FeatureChecker;
 use crate::NoopModuleLoader;
 use crate::OpMetricsEvent;
 use crate::OpState;
-use crate::Snapshot;
 use anyhow::anyhow;
 use anyhow::bail;
 use anyhow::Context as _;
@@ -434,7 +433,10 @@ pub struct RuntimeOptions {
   pub extensions: Vec<Extension>,
 
   /// V8 snapshot that should be loaded on startup.
-  pub startup_snapshot: Option<Snapshot>,
+  ///
+  /// For testing, use `runtime.snapshot()` and then [`Box::leak`] to acquire
+  // a static slice.
+  pub startup_snapshot: Option<&'static [u8]>,
 
   /// Should op registration be skipped?
   pub skip_op_registration: bool,
@@ -692,7 +694,7 @@ impl JsRuntime {
     let (maybe_startup_snapshot, sidecar_data) = options
       .startup_snapshot
       .take()
-      .map(Snapshot::deconstruct)
+      .map(snapshot::deconstruct)
       .unzip();
     let mut isolate = setup::create_isolate(
       will_snapshot,
diff --git a/core/runtime/mod.rs b/core/runtime/mod.rs
index a4deb01..436318a 100644
--- a/core/runtime/mod.rs
+++ b/core/runtime/mod.rs
@@ -37,7 +37,6 @@ pub use snapshot::get_js_files;
 pub use snapshot::CreateSnapshotOptions;
 pub use snapshot::CreateSnapshotOutput;
 pub use snapshot::FilterFn;
-pub use snapshot::Snapshot;
 pub(crate) use snapshot::SnapshotDataId;
 pub(crate) use snapshot::SnapshotLoadDataStore;
 pub(crate) use snapshot::SnapshotStoreDataStore;
diff --git a/core/runtime/setup.rs b/core/runtime/setup.rs
index 76076bc..2b741b0 100644
--- a/core/runtime/setup.rs
+++ b/core/runtime/setup.rs
@@ -5,7 +5,7 @@ use crate::V8_WRAPPER_TYPE_INDEX;
 
 use super::bindings;
 use super::snapshot;
-use super::snapshot::V8StartupData;
+use super::snapshot::V8Snapshot;
 use std::sync::atomic::AtomicBool;
 use std::sync::atomic::Ordering;
 use std::sync::Mutex;
@@ -110,7 +110,7 @@ pub fn create_isolate_ptr() -> *mut v8::OwnedIsolate {
 pub fn create_isolate(
   will_snapshot: bool,
   maybe_create_params: Option<v8::CreateParams>,
-  maybe_startup_snapshot: Option<V8StartupData>,
+  maybe_startup_snapshot: Option<V8Snapshot>,
   external_refs: &'static v8::ExternalReferences,
 ) -> v8::OwnedIsolate {
   let mut isolate = if will_snapshot {
@@ -125,10 +125,7 @@ pub fn create_isolate(
       .external_references(&**external_refs);
     let has_snapshot = maybe_startup_snapshot.is_some();
     if let Some(snapshot) = maybe_startup_snapshot {
-      params = match snapshot {
-        V8StartupData::Static(data) => params.snapshot_blob(data),
-        V8StartupData::Boxed(data) => params.snapshot_blob(data),
-      };
+      params = params.snapshot_blob(snapshot.0);
     }
     static FIRST_SNAPSHOT_INIT: AtomicBool = AtomicBool::new(false);
     static SNAPSHOW_INIT_MUT: Mutex<()> = Mutex::new(());
diff --git a/core/runtime/snapshot.rs b/core/runtime/snapshot.rs
index 3343b34..dca6215 100644
--- a/core/runtime/snapshot.rs
+++ b/core/runtime/snapshot.rs
@@ -20,49 +20,19 @@ pub type SnapshotDataId = u32;
 /// We use this constant a few times
 const ULEN: usize = std::mem::size_of::<usize>();
 
-/// The input snapshot source for a runtime.
-pub enum Snapshot {
-  /// Embedded in static data.
-  Static(&'static [u8]),
-  /// Freshly created, serialized as a boxed slice.
-  Boxed(Box<[u8]>),
-}
-
 /// The v8 lifetime is different than the sidecar data, so we
 /// allow for it to be split out.
-pub(crate) enum V8StartupData {
-  /// Embedded in static data.
-  Static(&'static [u8]),
-  /// Freshly created, serialized as a boxed slice.
-  Boxed(Box<[u8]>),
-}
-
-impl Snapshot {
-  pub(crate) fn deconstruct(
-    self,
-  ) -> (V8StartupData, SerializableSnapshotSidecarData) {
-    match self {
-      Snapshot::Static(slice) => {
-        let len =
-          usize::from_le_bytes(slice[slice.len() - ULEN..].try_into().unwrap());
-        let data = SerializableSnapshotSidecarData::from_slice(
-          &slice[len..slice.len() - ULEN],
-        );
-        (V8StartupData::Static(&slice[0..len]), data)
-      }
-      Snapshot::Boxed(slice) => {
-        let len =
-          usize::from_le_bytes(slice[slice.len() - ULEN..].try_into().unwrap());
-        let data = SerializableSnapshotSidecarData::from_slice(
-          &slice[len..slice.len() - ULEN],
-        );
-        let mut v8 = Vec::from(slice);
-        v8.truncate(len);
-        let v8 = v8.into_boxed_slice();
-        (V8StartupData::Boxed(v8), data)
-      }
-    }
-  }
+pub(crate) struct V8Snapshot(pub(crate) &'static [u8]);
+
+pub(crate) fn deconstruct(
+  slice: &'static [u8],
+) -> (V8Snapshot, SerializableSnapshotSidecarData) {
+  let len =
+    usize::from_le_bytes(slice[slice.len() - ULEN..].try_into().unwrap());
+  let data = SerializableSnapshotSidecarData::from_slice(
+    &slice[len..slice.len() - ULEN],
+  );
+  (V8Snapshot(&slice[0..len]), data)
 }
 
 pub(crate) fn serialize(
@@ -137,7 +107,7 @@ impl SnapshotStoreDataStore {
 
 pub struct CreateSnapshotOptions {
   pub cargo_manifest_dir: &'static str,
-  pub startup_snapshot: Option<Snapshot>,
+  pub startup_snapshot: Option<&'static [u8]>,
   pub skip_op_registration: bool,
   pub extensions: Vec<Extension>,
   pub with_runtime_cb: Option<Box<WithRuntimeCb>>,
@@ -189,6 +159,7 @@ pub fn create_snapshot(
 
   let mut snapshot = js_runtime.snapshot();
   if let Some(warmup_script) = warmup_script {
+    let leaked_snapshot = Box::leak(snapshot);
     let warmup_exts = warmup_exts.unwrap();
 
     // Warm up the snapshot bootstrap.
@@ -197,7 +168,7 @@ pub fn create_snapshot(
     // - Run warmup script in new context.
     // - Serialize the new context into a new snapshot blob.
     let mut js_runtime = JsRuntimeForSnapshot::new(RuntimeOptions {
-      startup_snapshot: Some(Snapshot::Boxed(snapshot)),
+      startup_snapshot: Some(leaked_snapshot),
       extensions: warmup_exts,
       skip_op_registration: true,
       ..Default::default()
@@ -357,23 +328,13 @@ pub(crate) fn store_snapshotted_data_for_snapshot(
 /// Returns an isolate set up for snapshotting.
 pub(crate) fn create_snapshot_creator(
   external_refs: &'static v8::ExternalReferences,
-  maybe_startup_snapshot: Option<V8StartupData>,
+  maybe_startup_snapshot: Option<V8Snapshot>,
 ) -> v8::OwnedIsolate {
   if let Some(snapshot) = maybe_startup_snapshot {
-    match snapshot {
-      V8StartupData::Boxed(snapshot) => {
-        v8::Isolate::snapshot_creator_from_existing_snapshot(
-          snapshot,
-          Some(external_refs),
-        )
-      }
-      V8StartupData::Static(snapshot) => {
-        v8::Isolate::snapshot_creator_from_existing_snapshot(
-          snapshot,
-          Some(external_refs),
-        )
-      }
-    }
+    v8::Isolate::snapshot_creator_from_existing_snapshot(
+      snapshot.0,
+      Some(external_refs),
+    )
   } else {
     v8::Isolate::snapshot_creator(Some(external_refs))
   }


Test patch:
diff --git a/core/modules/tests.rs b/core/modules/tests.rs
index 8a38491..81eb2ab 100644
--- a/core/modules/tests.rs
+++ b/core/modules/tests.rs
@@ -23,7 +23,6 @@ use crate::ModuleSpecifier;
 use crate::ModuleType;
 use crate::ResolutionKind;
 use crate::RuntimeOptions;
-use crate::Snapshot;
 use anyhow::bail;
 use anyhow::Error;
 use deno_ops::op2;
@@ -1428,7 +1427,7 @@ fn dynamic_imports_snapshot() {
     runtime.snapshot()
   };
 
-  let snapshot = Snapshot::Boxed(snapshot);
+  let snapshot = Box::leak(snapshot);
   let mut runtime2 = JsRuntime::new(RuntimeOptions {
     startup_snapshot: Some(snapshot),
     ..Default::default()
@@ -1471,7 +1470,7 @@ fn import_meta_snapshot() {
     runtime.snapshot()
   };
 
-  let snapshot = Snapshot::Boxed(snapshot);
+  let snapshot = Box::leak(snapshot);
   let mut runtime2 = JsRuntime::new(RuntimeOptions {
     startup_snapshot: Some(snapshot),
     ..Default::default()
diff --git a/core/runtime/tests/jsrealm.rs b/core/runtime/tests/jsrealm.rs
index 37b094f..c53429b 100644
--- a/core/runtime/tests/jsrealm.rs
+++ b/core/runtime/tests/jsrealm.rs
@@ -2,7 +2,6 @@
 use crate::error;
 use crate::modules::StaticModuleLoader;
 use crate::op2;
-use crate::snapshot::Snapshot;
 use crate::JsRuntime;
 use crate::JsRuntimeForSnapshot;
 use crate::RuntimeOptions;
@@ -142,9 +141,10 @@ fn es_snapshot() {
     });
     runtime.snapshot()
   };
+  let snapshot = Box::leak(startup_data);
   let mut runtime = JsRuntime::new(RuntimeOptions {
     module_loader: None,
-    startup_snapshot: Some(Snapshot::Boxed(startup_data)),
+    startup_snapshot: Some(snapshot),
     ..Default::default()
   });
 
diff --git a/core/runtime/tests/snapshot.rs b/core/runtime/tests/snapshot.rs
index 033d64d..e4d70ba 100644
--- a/core/runtime/tests/snapshot.rs
+++ b/core/runtime/tests/snapshot.rs
@@ -20,7 +20,7 @@ fn will_snapshot() {
     runtime.snapshot()
   };
 
-  let snapshot = Snapshot::Boxed(snapshot);
+  let snapshot = Box::leak(snapshot);
   let mut runtime2 = JsRuntime::new(RuntimeOptions {
     startup_snapshot: Some(snapshot),
     ..Default::default()
@@ -40,7 +40,7 @@ fn will_snapshot2() {
     runtime.snapshot()
   };
 
-  let snapshot = Snapshot::Boxed(startup_data);
+  let snapshot = Box::leak(startup_data);
   let mut runtime = JsRuntimeForSnapshot::new(RuntimeOptions {
     startup_snapshot: Some(snapshot),
     ..Default::default()
@@ -54,7 +54,7 @@ fn will_snapshot2() {
     runtime.snapshot()
   };
 
-  let snapshot = Snapshot::Boxed(startup_data);
+  let snapshot = Box::leak(startup_data);
   {
     let mut runtime = JsRuntime::new(RuntimeOptions {
       startup_snapshot: Some(snapshot),
@@ -93,7 +93,7 @@ fn test_snapshot_callbacks() {
     runtime.snapshot()
   };
 
-  let snapshot = Snapshot::Boxed(snapshot);
+  let snapshot = Box::leak(snapshot);
   let mut runtime2 = JsRuntime::new(RuntimeOptions {
     startup_snapshot: Some(snapshot),
     ..Default::default()
@@ -104,33 +104,14 @@ fn test_snapshot_callbacks() {
 }
 
 #[test]
-fn test_from_snapshot_boxed() {
+fn test_from_snapshot() {
   let snapshot = {
     let mut runtime = JsRuntimeForSnapshot::new(Default::default());
     runtime.execute_script_static("a.js", "a = 1 + 2").unwrap();
     runtime.snapshot()
   };
 
-  let snapshot = Snapshot::Boxed(snapshot);
-  let mut runtime2 = JsRuntime::new(RuntimeOptions {
-    startup_snapshot: Some(snapshot),
-    ..Default::default()
-  });
-  runtime2
-    .execute_script_static("check.js", "if (a != 3) throw Error('x')")
-    .unwrap();
-}
-
-#[test]
-fn test_from_snapshot_static() {
-  let snapshot = {
-    let mut runtime = JsRuntimeForSnapshot::new(Default::default());
-    runtime.execute_script_static("a.js", "a = 1 + 2").unwrap();
-    let data = runtime.snapshot();
-    Box::leak(data)
-  };
-
-  let snapshot = Snapshot::Static(snapshot);
+  let snapshot = Box::leak(snapshot);
   let mut runtime2 = JsRuntime::new(RuntimeOptions {
     startup_snapshot: Some(snapshot),
     ..Default::default()
@@ -157,7 +138,7 @@ fn test_snapshot_creator() {
   )
   .unwrap();
 
-  let snapshot = Snapshot::Boxed(output.output);
+  let snapshot = Box::leak(output.output);
 
   let mut runtime2 = JsRuntime::new(RuntimeOptions {
     startup_snapshot: Some(snapshot),
@@ -193,7 +174,7 @@ fn test_snapshot_creator_warmup() {
   // and one for the warmup.
   assert_eq!(*counter.borrow(), 2);
 
-  let snapshot = Snapshot::Boxed(output.output);
+  let snapshot = Box::leak(output.output);
 
   let mut runtime2 = JsRuntime::new(RuntimeOptions {
     startup_snapshot: Some(snapshot),
@@ -293,9 +274,10 @@ fn es_snapshot() {
   runtime.module_map().assert_module_map(&modules);
 
   let snapshot = runtime.snapshot();
+  let snapshot = Box::leak(snapshot);
 
   let mut runtime2 = JsRuntimeForSnapshot::new(RuntimeOptions {
-    startup_snapshot: Some(Snapshot::Boxed(snapshot)),
+    startup_snapshot: Some(snapshot),
     extensions: vec![Extension {
       name: "test_ext",
       ops: Cow::Borrowed(&[op_test::DECL]),
@@ -312,9 +294,10 @@ fn es_snapshot() {
   runtime2.module_map().assert_module_map(&modules);
 
   let snapshot2 = runtime2.snapshot();
+  let snapshot2 = Box::leak(snapshot2);
 
   let mut runtime3 = JsRuntime::new(RuntimeOptions {
-    startup_snapshot: Some(Snapshot::Boxed(snapshot2)),
+    startup_snapshot: Some(snapshot2),
     extensions: vec![Extension {
       name: "test_ext",
       ops: Cow::Borrowed(&[op_test::DECL]),
@@ -358,9 +341,11 @@ pub(crate) fn es_snapshot_without_runtime_module_loader() {
     runtime.snapshot()
   };
 
+  let snapshot = Box::leak(startup_data);
+
   let mut runtime = JsRuntime::new(RuntimeOptions {
     module_loader: None,
-    startup_snapshot: Some(Snapshot::Boxed(startup_data)),
+    startup_snapshot: Some(snapshot),
     ..Default::default()
   });
   let realm = runtime.main_realm();
diff --git a/testing/checkin.d.ts b/testing/checkin.d.ts
index 56f3e21..ae215c2 100644
--- a/testing/checkin.d.ts
+++ b/testing/checkin.d.ts
@@ -1,13 +1,16 @@
 // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
 /// <reference path="../core/lib.deno_core.d.ts" />
+// TODO(mmastrac): make this typecheck
+// <reference path="../core/internal.d.ts" />
 /// <reference lib="dom" />
 
+// deno-lint-ignore-file no-explicit-any
+
 // Types and method unavailable in TypeScript by default.
 interface PromiseConstructor {
   withResolvers<T>(): {
     promise: Promise<T>;
     resolve: (value: T | PromiseLike<T>) => void;
-    // deno-lint-ignore no-explicit-any
     reject: (reason?: any) => void;
   };
 }
@@ -24,3 +27,28 @@ declare namespace Deno {
   export function refTimer(id);
   export function unrefTimer(id);
 }
+
+declare module 'ext:core/mod.js' {
+  const core: any;
+}
+
+declare module 'ext:core/ops' {
+  function op_log_debug(...any): any;
+  function op_log_info(...any): any;
+
+  function op_test_register(...any): any;
+
+  function op_async_throw_error_deferred(...any): any;
+  function op_async_throw_error_eager(...any): any;
+  function op_async_throw_error_lazy(...any): any;
+  function op_error_context_async(...any): any;
+  function op_error_context_sync(...any): any;
+  function op_error_custom_sync(...any): any;
+
+  function op_worker_await_close(...any): any;
+  function op_worker_parent(...any): any;
+  function op_worker_recv(...any): any;
+  function op_worker_send(...any): any;
+  function op_worker_spawn(...any): any;
+  function op_worker_terminate(...any): any;
+}
diff --git a/testing/checkin/runner/mod.rs b/testing/checkin/runner/mod.rs
index e2da2bc..9927629 100644
--- a/testing/checkin/runner/mod.rs
+++ b/testing/checkin/runner/mod.rs
@@ -7,7 +7,6 @@ use deno_core::JsRuntime;
 use deno_core::JsRuntimeForSnapshot;
 use deno_core::PollEventLoopOptions;
 use deno_core::RuntimeOptions;
-use deno_core::Snapshot;
 use futures::Future;
 use pretty_assertions::assert_eq;
 use std::path::Path;
@@ -108,11 +107,11 @@ fn create_runtime(
   });
 
   let snapshot = runtime_for_snapshot.snapshot();
-
+  let snapshot = Box::leak(snapshot);
   let extensions = vec![checkin_runtime::init_ops()];
   let mut runtime = JsRuntime::new(RuntimeOptions {
     extensions,
-    startup_snapshot: Some(Snapshot::Boxed(snapshot)),
+    startup_snapshot: Some(snapshot),
     module_loader: Some(Rc::new(
       ts_module_loader::TypescriptModuleLoader::default(),
     )),
diff --git a/testing/checkin/runtime/__init.js b/testing/checkin/runtime/__init.js
index 98504bc..ec0888c 100644
--- a/testing/checkin/runtime/__init.js
+++ b/testing/checkin/runtime/__init.js
@@ -10,6 +10,7 @@ import * as throw_ from "checkin:throw";
 testing;
 async;
 error;
+throw_;
 
 globalThis.console = console.console;
 globalThis.setTimeout = timers.setTimeout;
@@ -17,7 +18,6 @@ globalThis.setInterval = timers.setInterval;
 globalThis.clearTimeout = timers.clearTimeout;
 globalThis.clearInterval = timers.clearInterval;
 globalThis.Worker = worker.Worker;
-globalThis.throwInExt = throw_.throwInExt;
 Reflect.defineProperty(globalThis, "onerror", {
   set: (cb) => {
     if (cb) {
diff --git a/testing/checkin/runtime/throw.ts b/testing/checkin/runtime/throw.ts
index 5e25594..2f44427 100644
--- a/testing/checkin/runtime/throw.ts
+++ b/testing/checkin/runtime/throw.ts
@@ -3,7 +3,7 @@
 /**
  * This is needed to test that stack traces in extensions are correct.
  */
-export function throwInExt() {
+export function throwExceptionFromExtension() {
   innerThrowInExt();
 }
 
diff --git a/testing/integration/error_ext_stack/error_ext_stack.out b/testing/integration/error_ext_stack/error_ext_stack.out
index 2c32eb3..b585138 100644
--- a/testing/integration/error_ext_stack/error_ext_stack.out
+++ b/testing/integration/error_ext_stack/error_ext_stack.out
@@ -1,4 +1,4 @@
 [ERR] Error: Failed
 [ERR]     at innerThrowInExt (checkin:throw:11:9)
-[ERR]     at throwInExt (checkin:throw:7:3)
-[ERR]     at test:///integration/error_ext_stack/error_ext_stack.ts:3:1
+[ERR]     at throwExceptionFromExtension (checkin:throw:7:3)
+[ERR]     at test:///integration/error_ext_stack/error_ext_stack.ts:4:1
diff --git a/testing/integration/error_ext_stack/error_ext_stack.ts b/testing/integration/error_ext_stack/error_ext_stack.ts
index cade9a2..1be2be5 100644
--- a/testing/integration/error_ext_stack/error_ext_stack.ts
+++ b/testing/integration/error_ext_stack/error_ext_stack.ts
@@ -1,4 +1,5 @@
 // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
 // FAIL
+import { throwExceptionFromExtension } from "checkin:throw";
 
-throwInExt();
+throwExceptionFromExtension();
diff --git a/testing/tsconfig.json b/testing/tsconfig.json
index b997ba5..3dbf5ff 100644
--- a/testing/tsconfig.json
+++ b/testing/tsconfig.json
@@ -7,6 +7,7 @@
       "checkin:console": ["checkin/runtime/console.ts"],
       "checkin:error": ["checkin/runtime/error.ts"],
       "checkin:testing": ["checkin/runtime/testing.ts"],
+      "checkin:throw": ["checkin/runtime/throw.ts"],
       "checkin:timers": ["checkin/runtime/timers.ts"],
       "checkin:worker": ["checkin/runtime/worker.ts"]
     },