Repository: denoland/deno_core
Pull request #859 (2024-08-02 09:10:30)

perf: use Object::with_prototype_and_properties for callsite object


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index d8b42aa..db9cbd0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -555,7 +555,7 @@ dependencies = [
 
 [[package]]
 name = "deno_core"
-version = "0.301.0"
+version = "0.302.0"
 dependencies = [
  "anyhow",
  "bencher",
@@ -624,7 +624,7 @@ dependencies = [
 
 [[package]]
 name = "deno_ops"
-version = "0.177.0"
+version = "0.178.0"
 dependencies = [
  "pretty_assertions",
  "prettyplease",
@@ -1841,7 +1841,7 @@ dependencies = [
 
 [[package]]
 name = "serde_v8"
-version = "0.210.0"
+version = "0.211.0"
 dependencies = [
  "bencher",
  "num-bigint",
@@ -2728,9 +2728,9 @@ dependencies = [
 
 [[package]]
 name = "v8"
-version = "0.101.0"
+version = "0.102.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06bc034c7b5e85fac85d2c6f181878266dd344790702d03e946c25cba78646a9"
+checksum = "88a710d5b95bff79a90708203cf9f74384e080d21fc6664aa4df463f2c66ac83"
 dependencies = [
  "bindgen",
  "bitflags",
diff --git a/Cargo.toml b/Cargo.toml
index 3cc1613..ab4d5de 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,12 +19,12 @@ repository = "https://github.com/denoland/deno_core"
 
 [workspace.dependencies]
 # Local dependencies
-deno_core = { version = "0.301.0", path = "./core" }
-deno_ops = { version = "0.177.0", path = "./ops" }
-serde_v8 = { version = "0.210.0", path = "./serde_v8" }
+deno_core = { version = "0.302.0", path = "./core" }
+deno_ops = { version = "0.178.0", path = "./ops" }
+serde_v8 = { version = "0.211.0", path = "./serde_v8" }
 deno_core_testing = { path = "./testing" }
 
-v8 = { version = "0.101.0", default-features = false }
+v8 = { version = "0.102.0", default-features = false }
 deno_ast = { version = "=0.40.0", features = ["transpiling"] }
 deno_unsync = "0.4.0"
 deno_core_icudata = "0.0.73"
diff --git a/core/01_core.js b/core/01_core.js
index 9ef1464..7db81bf 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -48,6 +48,7 @@
     op_encode_binary_string,
     op_eval_context,
     op_event_loop_has_more_work,
+    op_get_extras_binding_object,
     op_get_promise_details,
     op_get_proxy_details,
     op_has_tick_scheduled,
@@ -109,6 +110,11 @@
     op_is_weak_set,
   } = ops;
 
+  const {
+    getContinuationPreservedEmbedderData,
+    setContinuationPreservedEmbedderData,
+  } = op_get_extras_binding_object();
+
   // core/infra collaborative code
   delete window.__infra;
 
@@ -608,6 +614,37 @@
     };
   }
 
+  const getAsyncContext = getContinuationPreservedEmbedderData;
+  const setAsyncContext = setContinuationPreservedEmbedderData;
+
+  let asyncVariableCounter = 0;
+  class AsyncVariable {
+    #id = asyncVariableCounter++;
+    #data = new SafeWeakMap();
+
+    enter(value) {
+      const previousContextMapping = getAsyncContext();
+      const entry = { id: this.#id };
+      const asyncContextMapping = {
+        __proto__: null,
+        ...previousContextMapping,
+        [this.#id]: entry,
+      };
+      this.#data.set(entry, value);
+      setAsyncContext(asyncContextMapping);
+      return previousContextMapping;
+    }
+
+    get() {
+      const current = getAsyncContext();
+      const entry = current?.[this.#id];
+      if (entry) {
+        return this.#data.get(entry);
+      }
+      return undefined;
+    }
+  }
+
   // Extra Deno.core.* exports
   const core = ObjectAssign(globalThis.Deno.core, {
     internalRidSymbol: Symbol("Deno.internal.rid"),
@@ -779,6 +816,9 @@
     propNonEnumerableLazyLoaded,
     createLazyLoader,
     createCancelHandle: () => op_cancel_handle(),
+    getAsyncContext,
+    setAsyncContext,
+    AsyncVariable,
   });
 
   const internals = {};
diff --git a/core/Cargo.toml b/core/Cargo.toml
index e3508f2..14ba44b 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "deno_core"
-version = "0.301.0"
+version = "0.302.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
diff --git a/core/error.rs b/core/error.rs
index 0c9a127..ba4a2d4 100644
--- a/core/error.rs
+++ b/core/error.rs
@@ -985,6 +985,7 @@ pub fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef<str>) {
 v8_static_strings::v8_static_strings! {
   ERROR = "Error",
   GET_FILE_NAME = "getFileName",
+  GET_SCRIPT_NAME_OR_SOURCE_URL = "getScriptNameOrSourceURL",
   GET_THIS = "getThis",
   GET_TYPE_NAME = "getTypeName",
   GET_FUNCTION = "getFunction",
@@ -1019,8 +1020,8 @@ fn make_patched_callsite<'s>(
   callsite: v8::Local<'s, v8::Object>,
   prototype: v8::Local<'s, v8::Object>,
 ) -> v8::Local<'s, v8::Object> {
-  let out_obj = Object::new(scope);
-  out_obj.set_prototype(scope, prototype.into());
+  let out_obj =
+    Object::with_prototype_and_properties(scope, prototype.into(), &[], &[]);
   let orig_key = original_call_site_key(scope);
   out_obj.set_private(scope, orig_key, callsite.into());
   out_obj
@@ -1099,8 +1100,10 @@ pub mod callsite_fns {
     };
     // call getFileName
     let orig_ret =
-      call_method::<v8::String>(scope, orig, super::GET_FILE_NAME, &[]);
-    if let Some(ret_val) = orig_ret {
+      call_method::<v8::Value>(scope, orig, super::GET_FILE_NAME, &[]);
+    if let Some(ret_val) =
+      orig_ret.and_then(|v| v.try_cast::<v8::String>().ok())
+    {
       // strip off `file://`
       let string = ret_val.to_rust_string_lossy(scope);
       if let Some(file_name) = maybe_to_path_str(&string) {
@@ -1122,6 +1125,10 @@ pub mod callsite_fns {
   make_callsite_fn!(is_async, IS_ASYNC);
   make_callsite_fn!(is_promise_all, IS_PROMISE_ALL);
   make_callsite_fn!(get_promise_index, GET_PROMISE_INDEX);
+  make_callsite_fn!(
+    get_script_name_or_source_url,
+    GET_SCRIPT_NAME_OR_SOURCE_URL
+  );
 
   pub fn to_string(
     scope: &mut v8::HandleScope<'_>,
@@ -1139,8 +1146,10 @@ pub mod callsite_fns {
     };
     let orig_to_string = serde_v8::to_utf8(orig_to_string_v8, scope);
     // `this[kOriginalCallsite].getFileName()`
+    let orig_ret_file_name =
+      call_method::<v8::Value>(scope, orig, GET_FILE_NAME, &[]);
     let Some(orig_file_name) =
-      call_method::<v8::String>(scope, orig, GET_FILE_NAME, &[])
+      orig_ret_file_name.and_then(|v| v.try_cast::<v8::String>().ok())
     else {
       return;
     };
@@ -1209,6 +1218,12 @@ pub(crate) fn make_callsite_prototype<'s>(
   set_attr!(scope, template, is_async, IS_ASYNC);
   set_attr!(scope, template, is_promise_all, IS_PROMISE_ALL);
   set_attr!(scope, template, get_promise_index, GET_PROMISE_INDEX);
+  set_attr!(
+    scope,
+    template,
+    get_script_name_or_source_url,
+    GET_SCRIPT_NAME_OR_SOURCE_URL
+  );
   set_attr!(scope, template, to_string, TO_STRING);
 
   template.new_instance(scope).unwrap()
diff --git a/core/modules/map.rs b/core/modules/map.rs
index 221d7fd..be2d70e 100644
--- a/core/modules/map.rs
+++ b/core/modules/map.rs
@@ -630,9 +630,12 @@ impl ModuleMap {
         })
       })
       .unwrap_or_else(|| {
-        let source =
+        let mut source =
           v8::script_compiler::Source::new(source_str, Some(&origin));
-        (v8::script_compiler::compile_module(tc_scope, source), true)
+        (
+          v8::script_compiler::compile_module(tc_scope, &mut source),
+          true,
+        )
       });
 
     if tc_scope.has_caught() {
diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs
index 32764ad..41676c0 100644
--- a/core/ops_builtin.rs
+++ b/core/ops_builtin.rs
@@ -111,6 +111,7 @@ builtin_ops! {
   ops_builtin_v8::op_get_proxy_details,
   ops_builtin_v8::op_get_non_index_property_names,
   ops_builtin_v8::op_get_constructor_name,
+  ops_builtin_v8::op_get_extras_binding_object,
   ops_builtin_v8::op_memory_usage,
   ops_builtin_v8::op_set_wasm_streaming_callback,
   ops_builtin_v8::op_abort_wasm_streaming,
diff --git a/core/ops_builtin_v8.rs b/core/ops_builtin_v8.rs
index c4143bc..54bf21d 100644
--- a/core/ops_builtin_v8.rs
+++ b/core/ops_builtin_v8.rs
@@ -1133,3 +1133,11 @@ pub fn op_set_format_exception_callback<'a>(
 pub fn op_event_loop_has_more_work(scope: &mut v8::HandleScope) -> bool {
   JsRuntime::has_more_work(scope)
 }
+
+#[op2]
+pub fn op_get_extras_binding_object<'a>(
+  scope: &mut v8::HandleScope<'a>,
+) -> v8::Local<'a, v8::Value> {
+  let context = scope.get_current_context();
+  context.get_extras_binding_object(scope).into()
+}
diff --git a/core/runtime/bindings.rs b/core/runtime/bindings.rs
index 264ab28..5a520d7 100644
--- a/core/runtime/bindings.rs
+++ b/core/runtime/bindings.rs
@@ -123,6 +123,9 @@ pub(crate) fn create_external_references(
   references.push(v8::ExternalReference {
     function: callsite_fns::get_file_name.map_fn_to(),
   });
+  references.push(v8::ExternalReference {
+    function: callsite_fns::get_script_name_or_source_url.map_fn_to(),
+  });
   references.push(v8::ExternalReference {
     function: callsite_fns::get_line_number.map_fn_to(),
   });
diff --git a/core/runtime/jsrealm.rs b/core/runtime/jsrealm.rs
index 7a0efb8..edf510b 100644
--- a/core/runtime/jsrealm.rs
+++ b/core/runtime/jsrealm.rs
@@ -211,7 +211,7 @@ impl JsRealmInner {
           std::ptr::null_mut(),
         );
       }
-      ctx.clear_all_slots(isolate);
+      ctx.clear_all_slots();
       // Expect that this context is dead (we only check this in debug mode)
       // TODO(bartlomieju): This check fails for some tests, will need to fix this
       // debug_assert_eq!(Rc::strong_count(&module_map), 1, "ModuleMap still in use.");
diff --git a/core/runtime/jsruntime.rs b/core/runtime/jsruntime.rs
index d139cb1..cf709ac 100644
--- a/core/runtime/jsruntime.rs
+++ b/core/runtime/jsruntime.rs
@@ -2033,8 +2033,9 @@ fn create_context<'a>(
 ) -> v8::Local<'a, v8::Context> {
   let context = if has_snapshot {
     // Try to load the 1st index first, embedder may have used 0th for something else (like node:vm).
-    v8::Context::from_snapshot(scope, 1)
-      .unwrap_or_else(|| v8::Context::from_snapshot(scope, 0).unwrap())
+    v8::Context::from_snapshot(scope, 1, Default::default()).unwrap_or_else(
+      || v8::Context::from_snapshot(scope, 0, Default::default()).unwrap(),
+    )
   } else {
     // Set up the global object template and create context from it.
     let mut global_object_template = v8::ObjectTemplate::new(scope);
@@ -2043,7 +2044,13 @@ fn create_context<'a>(
     }
 
     global_object_template.set_internal_field_count(2);
-    v8::Context::new_from_template(scope, global_object_template)
+    v8::Context::new(
+      scope,
+      v8::ContextOptions {
+        global_template: Some(global_object_template),
+        ..Default::default()
+      },
+    )
   };
 
   let scope = &mut v8::ContextScope::new(scope, context);
@@ -2100,7 +2107,7 @@ impl JsRuntimeForSnapshot {
     // Set the context to be snapshot's default context
     {
       let mut scope = realm.handle_scope(self.v8_isolate());
-      let default_context = v8::Context::new(&mut scope);
+      let default_context = v8::Context::new(&mut scope, Default::default());
       scope.set_default_context(default_context);
 
       let local_context = v8::Local::new(&mut scope, realm.context());
diff --git a/ops/Cargo.toml b/ops/Cargo.toml
index 7938bd6..8110193 100644
--- a/ops/Cargo.toml
+++ b/ops/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "deno_ops"
-version = "0.177.0"
+version = "0.178.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml
index 3e2798a..da232e8 100644
--- a/serde_v8/Cargo.toml
+++ b/serde_v8/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "serde_v8"
-version = "0.210.0"
+version = "0.211.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
diff --git a/serde_v8/de.rs b/serde_v8/de.rs
index 49b4407..968d0e8 100644
--- a/serde_v8/de.rs
+++ b/serde_v8/de.rs
@@ -200,6 +200,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
     V: Visitor<'de>,
   {
     if self.input.is_string() || self.input.is_string_object() {
+      // fixme: this unwrap is not safe because stringifier could have thrown
       let v8_string = self.input.to_string(self.scope).unwrap();
       let string = to_utf8(v8_string, self.scope);
       visitor.visit_string(string)
@@ -265,10 +266,10 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
   where
     V: Visitor<'de>,
   {
-    let obj = v8::Local::<v8::Object>::try_from(self.input).unwrap();
-    if obj.is_array() {
+    let obj = v8::Local::<v8::Object>::try_from(self.input)
+      .map_err(|_| Error::ExpectedObject(self.input.type_repr()))?;
+    if let Ok(array) = v8::Local::<v8::Array>::try_from(obj) {
       // If the obj is an array fail if it's length differs from the tuple length
-      let array = v8::Local::<v8::Array>::try_from(self.input).unwrap();
       let array_len = array.length() as usize;
       if array_len != len {
         return Err(Error::LengthMismatch(array_len, len));
@@ -298,10 +299,8 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
     let obj = v8::Local::<v8::Object>::try_from(self.input)
       .map_err(|_| Error::ExpectedObject(self.input.type_repr()))?;
 
-    if v8::Local::<v8::Map>::try_from(self.input).is_ok() {
-      let pairs_array = v8::Local::<v8::Map>::try_from(self.input)
-        .unwrap()
-        .as_array(self.scope);
+    if let Ok(map) = v8::Local::<v8::Map>::try_from(self.input) {
+      let pairs_array = map.as_array(self.scope);
       let map = MapPairsAccess {
         pos: 0,
         len: pairs_array.length(),
@@ -394,9 +393,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
       })
     }
     // Struct or tuple variant
-    else if self.input.is_object() {
-      // Assume object
-      let obj = v8::Local::<v8::Object>::try_from(self.input).unwrap();
+    else if let Ok(obj) = v8::Local::<v8::Object>::try_from(self.input) {
       // Unpack single-key
       let tag = {
         let prop_names =
@@ -407,9 +404,11 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
         if prop_names_len != 1 {
           return Err(Error::LengthMismatch(prop_names_len as usize, 1));
         }
+        // fixme: this unwrap  is not safe because of proxies
         prop_names.get_index(self.scope, 0).unwrap()
       };
 
+      // fixme: this unwrap  is not safe because of proxies
       let payload = obj.get(self.scope, tag).unwrap();
       visitor.visit_enum(EnumAccess {
         scope: self.scope,
@@ -629,6 +628,7 @@ impl<'de> de::SeqAccess<'de> for SeqAccess<'_, '_> {
     seed: T,
   ) -> Result<Option<T::Value>> {
     if let Some(pos) = self.range.next() {
+      // fixme: this unwrap  is not safe because of proxies
       let val = self.obj.get_index(self.scope, pos).unwrap();
       let mut deserializer = Deserializer::new(self.scope, val, None);
       seed.deserialize(&mut deserializer).map(Some)
diff --git a/serde_v8/examples/basic.rs b/serde_v8/examples/basic.rs
index be160c7..1b8c552 100644
--- a/serde_v8/examples/basic.rs
+++ b/serde_v8/examples/basic.rs
@@ -16,7 +16,7 @@ fn main() {
   {
     let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
     let handle_scope = &mut v8::HandleScope::new(isolate);
-    let context = v8::Context::new(handle_scope);
+    let context = v8::Context::new(handle_scope, Default::default());
     let scope = &mut v8::ContextScope::new(handle_scope, context);
 
     fn exec<'s>(


Test patch:
diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs
index ff0101e..20cb470 100644
--- a/serde_v8/tests/de.rs
+++ b/serde_v8/tests/de.rs
@@ -40,7 +40,7 @@ fn dedo(
   v8_do(|| {
     let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
     let handle_scope = &mut v8::HandleScope::new(isolate);
-    let context = v8::Context::new(handle_scope);
+    let context = v8::Context::new(handle_scope, Default::default());
     let scope = &mut v8::ContextScope::new(handle_scope, context);
     let v = js_exec(scope, code);
 
diff --git a/serde_v8/tests/magic.rs b/serde_v8/tests/magic.rs
index 8977860..e2ec308 100644
--- a/serde_v8/tests/magic.rs
+++ b/serde_v8/tests/magic.rs
@@ -22,7 +22,7 @@ fn magic_basic() {
   v8_do(|| {
     let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
     let handle_scope = &mut v8::HandleScope::new(isolate);
-    let context = v8::Context::new(handle_scope);
+    let context = v8::Context::new(handle_scope, Default::default());
     let scope = &mut v8::ContextScope::new(handle_scope, context);
 
     // Decode
@@ -48,7 +48,7 @@ fn magic_buffer() {
     // Init isolate
     let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
     let handle_scope = &mut v8::HandleScope::new(isolate);
-    let context = v8::Context::new(handle_scope);
+    let context = v8::Context::new(handle_scope, Default::default());
     let scope = &mut v8::ContextScope::new(handle_scope, context);
     let global = context.global(scope);
 
@@ -124,7 +124,7 @@ fn magic_byte_string() {
     // Init isolate
     let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
     let handle_scope = &mut v8::HandleScope::new(isolate);
-    let context = v8::Context::new(handle_scope);
+    let context = v8::Context::new(handle_scope, Default::default());
     let scope = &mut v8::ContextScope::new(handle_scope, context);
     let global = context.global(scope);
 
@@ -196,7 +196,7 @@ fn magic_value() {
     // Init isolate
     let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
     let handle_scope = &mut v8::HandleScope::new(isolate);
-    let context = v8::Context::new(handle_scope);
+    let context = v8::Context::new(handle_scope, Default::default());
     let scope = &mut v8::ContextScope::new(handle_scope, context);
 
     let v8_string = js_exec(scope, "'test'");
diff --git a/serde_v8/tests/ser.rs b/serde_v8/tests/ser.rs
index b68729c..09e1b55 100644
--- a/serde_v8/tests/ser.rs
+++ b/serde_v8/tests/ser.rs
@@ -46,7 +46,7 @@ fn sercheck<T: Serialize>(val: T, code: &str, pollute: bool) -> bool {
     // Setup isolate
     let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
     let handle_scope = &mut v8::HandleScope::new(isolate);
-    let context = v8::Context::new(handle_scope);
+    let context = v8::Context::new(handle_scope, Default::default());
     let scope = &mut v8::ContextScope::new(handle_scope, context);
 
     // Load util functions
diff --git a/testing/integration/error_get_file_name/error_get_file_name.out b/testing/integration/error_get_file_name/error_get_file_name.out
new file mode 100644
index 0000000..5082dbe
--- /dev/null
+++ b/testing/integration/error_get_file_name/error_get_file_name.out
@@ -0,0 +1,5 @@
+[
+  "test:///integration/error_get_file_name/error_get_file_name.ts",
+  null,
+  "test:///integration/error_get_file_name/error_get_file_name.ts"
+]
diff --git a/testing/integration/error_get_file_name/error_get_file_name.ts b/testing/integration/error_get_file_name/error_get_file_name.ts
new file mode 100644
index 0000000..8314bd2
--- /dev/null
+++ b/testing/integration/error_get_file_name/error_get_file_name.ts
@@ -0,0 +1,12 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+// deno-lint-ignore no-explicit-any
+(Error as any).prepareStackTrace = (_err: unknown, frames: any[]) => {
+  return frames.map((frame) => frame.getFileName());
+};
+
+new Promise((_, reject) => {
+  reject(new Error("fail").stack);
+}).catch((err) => {
+  console.log(err);
+});
diff --git a/testing/integration/error_get_file_name_to_string/error_get_file_name_to_string.out b/testing/integration/error_get_file_name_to_string/error_get_file_name_to_string.out
new file mode 100644
index 0000000..ba287b6
--- /dev/null
+++ b/testing/integration/error_get_file_name_to_string/error_get_file_name_to_string.out
@@ -0,0 +1,5 @@
+[
+  "test:///integration/error_get_file_name_to_string/error_get_file_name_to_string.ts:7:10",
+  null,
+  "test:///integration/error_get_file_name_to_string/error_get_file_name_to_string.ts:6:1"
+]
diff --git a/testing/integration/error_get_file_name_to_string/error_get_file_name_to_string.ts b/testing/integration/error_get_file_name_to_string/error_get_file_name_to_string.ts
new file mode 100644
index 0000000..627efbb
--- /dev/null
+++ b/testing/integration/error_get_file_name_to_string/error_get_file_name_to_string.ts
@@ -0,0 +1,12 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+// deno-lint-ignore no-explicit-any
+(Error as any).prepareStackTrace = (_err: unknown, frames: any[]) => {
+  return frames.map((frame) => frame.toString());
+};
+
+new Promise((_, reject) => {
+  reject(new Error("fail").stack);
+}).catch((err) => {
+  console.log(err);
+});
diff --git a/testing/integration/error_get_script_name_or_source_url/error_get_script_name_or_source_url.out b/testing/integration/error_get_script_name_or_source_url/error_get_script_name_or_source_url.out
new file mode 100644
index 0000000..beb9829
--- /dev/null
+++ b/testing/integration/error_get_script_name_or_source_url/error_get_script_name_or_source_url.out
@@ -0,0 +1,5 @@
+[
+  "test:///integration/error_get_script_name_or_source_url/error_get_script_name_or_source_url.ts",
+  null,
+  "test:///integration/error_get_script_name_or_source_url/error_get_script_name_or_source_url.ts"
+]
diff --git a/testing/integration/error_get_script_name_or_source_url/error_get_script_name_or_source_url.ts b/testing/integration/error_get_script_name_or_source_url/error_get_script_name_or_source_url.ts
new file mode 100644
index 0000000..45b2630
--- /dev/null
+++ b/testing/integration/error_get_script_name_or_source_url/error_get_script_name_or_source_url.ts
@@ -0,0 +1,12 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+// deno-lint-ignore no-explicit-any
+(Error as any).prepareStackTrace = (_err: unknown, frames: any[]) => {
+  return frames.map((frame) => frame.getScriptNameOrSourceURL());
+};
+
+new Promise((_, reject) => {
+  reject(new Error("fail").stack);
+}).catch((err) => {
+  console.log(err);
+});
diff --git a/testing/integration/error_prepare_stack_trace/error_prepare_stack_trace.out b/testing/integration/error_prepare_stack_trace/error_prepare_stack_trace.out
index d9eba84..2abc5c3 100644
--- a/testing/integration/error_prepare_stack_trace/error_prepare_stack_trace.out
+++ b/testing/integration/error_prepare_stack_trace/error_prepare_stack_trace.out
@@ -15,6 +15,7 @@
   "isAsync",
   "isPromiseAll",
   "getPromiseIndex",
+  "getScriptNameOrSourceURL",
   "toString"
 ]
 []
@@ -37,4 +38,5 @@ isConstructor() threw an error: The receiver is not a valid callsite object.
 isAsync() threw an error: The receiver is not a valid callsite object.
 isPromiseAll() threw an error: The receiver is not a valid callsite object.
 getPromiseIndex() threw an error: The receiver is not a valid callsite object.
+getScriptNameOrSourceURL() threw an error: The receiver is not a valid callsite object.
 toString() threw an error: The receiver is not a valid callsite object.
diff --git a/testing/lib.rs b/testing/lib.rs
index 00494ac..0a5f607 100644
--- a/testing/lib.rs
+++ b/testing/lib.rs
@@ -66,6 +66,9 @@ integration_test!(
   error_prepare_stack_trace,
   error_with_stack,
   error_without_stack,
+  error_get_file_name,
+  error_get_file_name_to_string,
+  error_get_script_name_or_source_url,
   main_module_handler,
   module_types,
   pending_unref_op_tla,