Repository: denoland/deno_core
Pull request #226 (2023-09-21 01:30:12)

feat: add JsRuntime::op_names
This is needed in order to implement `Deno.metrics()` equivalent in Rust.

CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/denoland/deno_core?pullRequest=226) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/denoland/deno_core?pullRequest=226) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/denoland/deno_core?pullRequest=226) it.</sub>

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 4d31841..d067946 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -29,9 +29,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "aho-corasick"
-version = "1.1.0"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0"
+checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
 dependencies = [
  "memchr",
 ]
@@ -1132,9 +1132,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.13"
+version = "0.38.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662"
+checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
 dependencies = [
  "bitflags 2.4.0",
  "errno",
@@ -1282,9 +1282,9 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.11.0"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
+checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
 
 [[package]]
 name = "smartstring"
@@ -2024,9 +2024,9 @@ checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
 
 [[package]]
 name = "v8"
-version = "0.76.0"
+version = "0.77.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d4e8ae7ef8b4e852e728e343cb6bb471a0424dfefa22585ea0c14a61252d73f"
+checksum = "d2c1cc5961099892fa7a60b2486cf07065c6006118bc34ae12ef18f36d0d2489"
 dependencies = [
  "bitflags 1.3.2",
  "fslock",
@@ -2076,9 +2076,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
 dependencies = [
  "winapi",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index b50dcd8..23efb08 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,7 +21,7 @@ deno_core = { version = "0.214.0", path = "./core" }
 deno_ops = { version = "0.90.0", path = "./ops" }
 serde_v8 = { version = "0.123.0", path = "./serde_v8" }
 
-v8 = { version = "0.76.0", default-features = false }
+v8 = { version = "0.77.0", default-features = false }
 deno_ast = { version = "0.29.1", features = ["transpiling"] }
 deno_unsync = "0.3.0"
 
diff --git a/core/01_core.js b/core/01_core.js
index 5ea1179..804ad0a 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -800,6 +800,16 @@ for (let i = 0; i < 10; i++) {
     op_shutdown: shutdown,
   } = ensureFastOps();
 
+  const callSiteRetBuf = new Uint32Array(2);
+  const callSiteRetBufU8 = new Uint8Array(callSiteRetBuf.buffer);
+
+  function currentUserCallSite() {
+    const fileName = ops.op_current_user_call_site(callSiteRetBufU8);
+    const lineNumber = callSiteRetBuf[0];
+    const columnNumber = callSiteRetBuf[1];
+    return { fileName, lineNumber, columnNumber };
+  }
+
   // Extra Deno.core.* exports
   const core = ObjectAssign(globalThis.Deno.core, {
     asyncStub,
@@ -867,6 +877,7 @@ for (let i = 0; i < 10; i++) {
     byteLength: (str) => ops.op_str_byte_length(str),
     build,
     setBuildInfo,
+    currentUserCallSite,
   });
 
   const internals = {};
diff --git a/core/02_error.js b/core/02_error.js
index dcc49e3..57e0ad0 100644
--- a/core/02_error.js
+++ b/core/02_error.js
@@ -14,9 +14,9 @@
     Uint32Array,
   } = window.__bootstrap.primordials;
 
-  const DATA_URL_ABBREV_THRESHOLD = 150; // keep in sync with ops_builtin_v8.rs
+  const DATA_URL_ABBREV_THRESHOLD = 150; // keep in sync with ./error.rs
 
-  // Keep in sync with `op_format_file_name` ./ops_builtin.rs
+  // Keep in sync with `format_file_name` in ./error.rs
   function formatFileName(fileName) {
     if (
       fileName.startsWith("data:") &&
diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs
index da7d1cd..fc4286b 100644
--- a/core/ops_builtin.rs
+++ b/core/ops_builtin.rs
@@ -75,6 +75,7 @@ crate::extension!(
     ops_builtin_v8::op_op_names,
     ops_builtin_v8::op_apply_source_map,
     ops_builtin_v8::op_apply_source_map_filename,
+    ops_builtin_v8::op_current_user_call_site,
     ops_builtin_v8::op_set_format_exception_callback,
     ops_builtin_v8::op_event_loop_has_more_work,
     ops_builtin_v8::op_store_pending_promise_rejection,
diff --git a/core/ops_builtin_v8.rs b/core/ops_builtin_v8.rs
index 57bd7fc..68b7e6f 100644
--- a/core/ops_builtin_v8.rs
+++ b/core/ops_builtin_v8.rs
@@ -803,6 +803,15 @@ pub struct Location {
   column_number: u32,
 }
 
+fn write_line_and_col_to_ret_buf(
+  ret_buf: &mut [u8],
+  line_number: u32,
+  column_number: u32,
+) {
+  ret_buf[0..4].copy_from_slice(&line_number.to_le_bytes());
+  ret_buf[4..8].copy_from_slice(&column_number.to_le_bytes());
+}
+
 // Returns:
 // 0: no source mapping performed, use original location
 // 1: mapped line and column, but not file name. new line and column are in
@@ -822,8 +831,8 @@ pub fn op_apply_source_map(
   if ret_buf.len() != 8 {
     return Err(type_error("retBuf must be 8 bytes"));
   }
-  let mut cache = state.source_map_cache.borrow_mut();
   if let Some(source_map_getter) = state.source_map_getter.as_ref() {
+    let mut cache = state.source_map_cache.borrow_mut();
     let application = apply_source_map(
       file_name,
       line_number,
@@ -831,17 +840,13 @@ pub fn op_apply_source_map(
       &mut cache,
       &***source_map_getter,
     );
-    fn write_ret_buf(ret_buf: &mut [u8], line_number: u32, column_number: u32) {
-      ret_buf[0..4].copy_from_slice(&line_number.to_le_bytes());
-      ret_buf[4..8].copy_from_slice(&column_number.to_le_bytes());
-    }
     match application {
       SourceMapApplication::Unchanged => Ok(0),
       SourceMapApplication::LineAndColumn {
         line_number,
         column_number,
       } => {
-        write_ret_buf(ret_buf, line_number, column_number);
+        write_line_and_col_to_ret_buf(ret_buf, line_number, column_number);
         Ok(1)
       }
       SourceMapApplication::LineAndColumnAndFileName {
@@ -849,7 +854,7 @@ pub fn op_apply_source_map(
         column_number,
         file_name,
       } => {
-        write_ret_buf(ret_buf, line_number, column_number);
+        write_line_and_col_to_ret_buf(ret_buf, line_number, column_number);
         cache.stashed_file_name.replace(file_name);
         Ok(2)
       }
@@ -874,6 +879,73 @@ pub fn op_apply_source_map_filename(
     .ok_or_else(|| type_error("No stashed file name"))
 }
 
+#[op2(core)]
+#[string]
+pub fn op_current_user_call_site(
+  scope: &mut v8::HandleScope,
+  js_runtime_state: &mut JsRuntimeState,
+  #[buffer] ret_buf: &mut [u8],
+) -> String {
+  let stack_trace = v8::StackTrace::current_stack_trace(scope, 10).unwrap();
+  let frame_count = stack_trace.get_frame_count();
+  for i in 0..frame_count {
+    let frame = stack_trace.get_frame(scope, i).unwrap();
+    if !frame.is_user_javascript() {
+      continue;
+    }
+    let file_name = frame
+      .get_script_name(scope)
+      .unwrap()
+      .to_rust_string_lossy(scope);
+    // TODO: this condition should be configurable. It's a CLI assumption.
+    if (file_name.starts_with("ext:") || file_name.starts_with("node:"))
+      && i != frame_count - 1
+    {
+      continue;
+    }
+    let line_number = frame.get_line_number() as u32;
+    let column_number = frame.get_column() as u32;
+    let application = if let Some(source_map_getter) =
+      js_runtime_state.source_map_getter.as_ref()
+    {
+      let mut cache = js_runtime_state.source_map_cache.borrow_mut();
+      apply_source_map(
+        &file_name,
+        line_number,
+        column_number,
+        &mut cache,
+        &***source_map_getter,
+      )
+    } else {
+      SourceMapApplication::Unchanged
+    };
+
+    match application {
+      SourceMapApplication::Unchanged => {
+        write_line_and_col_to_ret_buf(ret_buf, line_number, column_number);
+        return file_name;
+      }
+      SourceMapApplication::LineAndColumn {
+        line_number,
+        column_number,
+      } => {
+        write_line_and_col_to_ret_buf(ret_buf, line_number, column_number);
+        return file_name;
+      }
+      SourceMapApplication::LineAndColumnAndFileName {
+        line_number,
+        column_number,
+        file_name,
+      } => {
+        write_line_and_col_to_ret_buf(ret_buf, line_number, column_number);
+        return file_name;
+      }
+    }
+  }
+
+  unreachable!("No stack frames found on stack at all");
+}
+
 /// Set a callback which formats exception messages as stored in
 /// `JsError::exception_message`. The callback is passed the error value and
 /// should return a string or `null`. If no callback is set or the callback
diff --git a/core/runtime/jsruntime.rs b/core/runtime/jsruntime.rs
index ed73118..bff5ef4 100644
--- a/core/runtime/jsruntime.rs
+++ b/core/runtime/jsruntime.rs
@@ -1180,6 +1180,14 @@ impl JsRuntime {
     state.op_state.clone()
   }
 
+  /// Returns the runtime's op names, ordered by OpId.
+  pub fn op_names(&self) -> Vec<&'static str> {
+    let main_realm = self.inner.main_realm.as_ref().unwrap().clone();
+    let state_rc = main_realm.0.state();
+    let state = state_rc.borrow();
+    state.op_ctxs.iter().map(|o| o.decl.name).collect()
+  }
+
   /// Executes traditional JavaScript code (traditional = not ES modules).
   ///
   /// The execution takes place on the current main realm, so it is possible
diff --git a/core/runtime/ops.rs b/core/runtime/ops.rs
index 77d8486..f059a29 100644
--- a/core/runtime/ops.rs
+++ b/core/runtime/ops.rs
@@ -270,6 +270,14 @@ macro_rules! try_bignum {
   };
 }
 
+pub fn opstate_borrow<T: 'static>(state: &OpState) -> &T {
+  state.borrow()
+}
+
+pub fn opstate_borrow_mut<T: 'static>(state: &mut OpState) -> &mut T {
+  state.borrow_mut()
+}
+
 pub fn to_u32_option(number: &v8::Value) -> Option<i32> {
   try_number_some!(number Integer is_uint32);
   try_number_some!(number Int32 is_int32);
@@ -589,6 +597,7 @@ mod tests {
   use crate::error::generic_error;
   use crate::error::AnyError;
   use crate::error::JsError;
+  use crate::runtime::JsRuntimeState;
   use crate::FastString;
   use crate::JsRuntime;
   use crate::OpState;
@@ -647,6 +656,8 @@ mod tests {
       op_test_v8_type_handle_scope_result,
       op_test_v8_global,
       op_test_serde_v8,
+      op_jsruntimestate,
+      op_jsruntimestate_mut,
       op_state_rc,
       op_state_ref,
       op_state_mut,
@@ -1416,6 +1427,19 @@ mod tests {
     Ok(())
   }
 
+  #[op2(core, fast)]
+  pub fn op_jsruntimestate(_state: &JsRuntimeState) {}
+
+  #[op2(core, fast)]
+  pub fn op_jsruntimestate_mut(_state: &mut JsRuntimeState) {}
+
+  #[tokio::test]
+  pub async fn test_jsruntimestate() -> Result<(), Box<dyn std::error::Error>> {
+    run_test2(10000, "op_jsruntimestate", "op_jsruntimestate()")?;
+    run_test2(10000, "op_jsruntimestate_mut", "op_jsruntimestate_mut()")?;
+    Ok(())
+  }
+
   #[op2(core, fast)]
   pub fn op_state_rc(state: Rc<RefCell<OpState>>, value: u32) -> u32 {
     let old_value: u32 = state.borrow_mut().take();
diff --git a/core/source_map.rs b/core/source_map.rs
index bbb733c..97a8cab 100644
--- a/core/source_map.rs
+++ b/core/source_map.rs
@@ -64,6 +64,8 @@ pub enum SourceMapApplication {
 /// Apply a source map to the passed location. If there is no source map for
 /// this location, or if the location remains unchanged after mapping, the
 /// changed values are returned.
+///
+/// Line and column numbers are 1-based.
 pub fn apply_source_map<G: SourceMapGetter + ?Sized>(
   file_name: &str,
   line_number: u32,
diff --git a/ops/lib.rs b/ops/lib.rs
index b4bddcc..c28e371 100644
--- a/ops/lib.rs
+++ b/ops/lib.rs
@@ -395,7 +395,7 @@ fn opstate_arg(arg: &FnArg) -> Option<TokenStream2> {
   match arg {
     arg if is_rc_refcell_opstate(arg) => Some(quote! { ctx.state.clone(), }),
     arg if is_mut_ref_opstate(arg) => {
-      Some(quote! { &mut std::cell::RefCell::borrow_mut(&ctx.state), })
+      Some(quote! { &mut ::std::cell::RefCell::borrow_mut(&ctx.state), })
     }
     _ => None,
   }
@@ -435,7 +435,7 @@ fn codegen_v8_sync(
   let fast_error_handler = if has_fallible_fast_call {
     quote! {
       {
-        let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
+        let op_state = &mut ::std::cell::RefCell::borrow_mut(&ctx.state);
         if let Some(err) = op_state.last_fast_op_error.take() {
           let exception = #core::error::to_v8_error(scope, ctx.get_error_class_fn, &err);
           scope.throw_exception(exception);
diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs
index efeb435..36046ce 100644
--- a/ops/op2/dispatch_fast.rs
+++ b/ops/op2/dispatch_fast.rs
@@ -332,11 +332,11 @@ fn map_v8_fastcall_arg_to_arg(
     }
     Arg::Ref(RefType::Ref, Special::OpState) => {
       *needs_opctx = true;
-      quote!(let #arg_ident = &#opctx.state.borrow();)
+      quote!(let #arg_ident = &::std::cell::RefCell::borrow(&#opctx.state);)
     }
     Arg::Ref(RefType::Mut, Special::OpState) => {
       *needs_opctx = true;
-      quote!(let #arg_ident = &mut #opctx.state.borrow_mut();)
+      quote!(let #arg_ident = &mut ::std::cell::RefCell::borrow_mut(&#opctx.state);)
     }
     Arg::RcRefCell(Special::OpState) => {
       *needs_opctx = true;
@@ -344,11 +344,11 @@ fn map_v8_fastcall_arg_to_arg(
     }
     Arg::Ref(RefType::Ref, Special::JsRuntimeState) => {
       *needs_js_runtime_state = true;
-      quote!(let #arg_ident = &#js_runtime_state.borrow();)
+      quote!(let #arg_ident = &::std::cell::RefCell::borrow(&#js_runtime_state);)
     }
     Arg::Ref(RefType::Mut, Special::JsRuntimeState) => {
       *needs_js_runtime_state = true;
-      quote!(let #arg_ident = &mut #js_runtime_state.borrow_mut();)
+      quote!(let #arg_ident = &mut ::std::cell::RefCell::borrow_mut(&#js_runtime_state);)
     }
     Arg::RcRefCell(Special::JsRuntimeState) => {
       *needs_js_runtime_state = true;
@@ -359,8 +359,8 @@ fn map_v8_fastcall_arg_to_arg(
       let state =
         syn::parse_str::<Type>(state).expect("Failed to reparse state type");
       quote! {
-        let #arg_ident = #opctx.state.borrow();
-        let #arg_ident = #arg_ident.borrow::<#state>();
+        let #arg_ident = ::std::cell::RefCell::borrow(&#opctx.state);
+        let #arg_ident = #deno_core::_ops::opstate_borrow::<#state>(&#arg_ident);
       }
     }
     Arg::State(RefType::Mut, state) => {
@@ -368,8 +368,8 @@ fn map_v8_fastcall_arg_to_arg(
       let state =
         syn::parse_str::<Type>(state).expect("Failed to reparse state type");
       quote! {
-        let mut #arg_ident = #opctx.state.borrow_mut();
-        let #arg_ident = #arg_ident.borrow_mut::<#state>();
+        let mut #arg_ident = ::std::cell::RefCell::borrow_mut(&#opctx.state);
+        let #arg_ident = #deno_core::_ops::opstate_borrow_mut::<#state>(&mut #arg_ident);
       }
     }
     Arg::OptionState(RefType::Ref, state) => {
@@ -377,7 +377,7 @@ fn map_v8_fastcall_arg_to_arg(
       let state =
         syn::parse_str::<Type>(state).expect("Failed to reparse state type");
       quote! {
-        let #arg_ident = #opctx.state.borrow();
+        let #arg_ident = &::std::cell::RefCell::borrow(&#opctx.state);
         let #arg_ident = #arg_ident.try_borrow::<#state>();
       }
     }
@@ -386,7 +386,7 @@ fn map_v8_fastcall_arg_to_arg(
       let state =
         syn::parse_str::<Type>(state).expect("Failed to reparse state type");
       quote! {
-        let mut #arg_ident = #opctx.state.borrow_mut();
+        let mut #arg_ident = &mut ::std::cell::RefCell::borrow_mut(&#opctx.state);
         let #arg_ident = #arg_ident.try_borrow_mut::<#state>();
       }
     }
diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs
index 9c4e39e..af61607 100644
--- a/ops/op2/dispatch_slow.rs
+++ b/ops/op2/dispatch_slow.rs
@@ -353,11 +353,11 @@ pub fn from_arg(
     }
     Arg::Ref(RefType::Ref, Special::OpState) => {
       *needs_opstate = true;
-      quote!(let #arg_ident = &#opstate.borrow();)
+      quote!(let #arg_ident = &::std::cell::RefCell::borrow(&#opstate);)
     }
     Arg::Ref(RefType::Mut, Special::OpState) => {
       *needs_opstate = true;
-      quote!(let #arg_ident = &mut #opstate.borrow_mut();)
+      quote!(let #arg_ident = &mut ::std::cell::RefCell::borrow_mut(&#opstate);)
     }
     Arg::RcRefCell(Special::OpState) => {
       *needs_opstate = true;
@@ -365,11 +365,11 @@ pub fn from_arg(
     }
     Arg::Ref(RefType::Ref, Special::JsRuntimeState) => {
       *needs_js_runtime_state = true;
-      quote!(let #arg_ident = &#js_runtime_state.borrow();)
+      quote!(let #arg_ident = &::std::cell::RefCell::borrow(&#js_runtime_state);)
     }
     Arg::Ref(RefType::Mut, Special::JsRuntimeState) => {
       *needs_js_runtime_state = true;
-      quote!(let #arg_ident = &mut #js_runtime_state.borrow_mut();)
+      quote!(let #arg_ident = &mut ::std::cell::RefCell::borrow_mut(&#js_runtime_state);)
     }
     Arg::RcRefCell(Special::JsRuntimeState) => {
       *needs_js_runtime_state = true;
@@ -380,8 +380,8 @@ pub fn from_arg(
       let state =
         syn::parse_str::<Type>(state).expect("Failed to reparse state type");
       quote! {
-        let #arg_ident = #opstate.borrow();
-        let #arg_ident = #arg_ident.borrow::<#state>();
+        let #arg_ident = ::std::cell::RefCell::borrow(&#opstate);
+        let #arg_ident = #deno_core::_ops::opstate_borrow::<#state>(&#arg_ident);
       }
     }
     Arg::State(RefType::Mut, state) => {
@@ -389,8 +389,8 @@ pub fn from_arg(
       let state =
         syn::parse_str::<Type>(state).expect("Failed to reparse state type");
       quote! {
-        let mut #arg_ident = #opstate.borrow_mut();
-        let #arg_ident = #arg_ident.borrow_mut::<#state>();
+        let mut #arg_ident = ::std::cell::RefCell::borrow_mut(&#opstate);
+        let #arg_ident = #deno_core::_ops::opstate_borrow_mut::<#state>(&mut #arg_ident);
       }
     }
     Arg::OptionState(RefType::Ref, state) => {
@@ -398,7 +398,7 @@ pub fn from_arg(
       let state =
         syn::parse_str::<Type>(state).expect("Failed to reparse state type");
       quote! {
-        let #arg_ident = #opstate.borrow();
+        let #arg_ident = &::std::cell::RefCell::borrow(&#opstate);
         let #arg_ident = #arg_ident.try_borrow::<#state>();
       }
     }
@@ -407,7 +407,7 @@ pub fn from_arg(
       let state =
         syn::parse_str::<Type>(state).expect("Failed to reparse state type");
       quote! {
-        let mut #arg_ident = #opstate.borrow_mut();
+        let mut #arg_ident = &mut ::std::cell::RefCell::borrow_mut(&#opstate);
         let #arg_ident = #arg_ident.try_borrow_mut::<#state>();
       }
     }


Test patch:
diff --git a/core/runtime/tests/jsrealm.rs b/core/runtime/tests/jsrealm.rs
index 5dc3b1a..f00a0f4 100644
--- a/core/runtime/tests/jsrealm.rs
+++ b/core/runtime/tests/jsrealm.rs
@@ -176,6 +176,9 @@ fn js_realm_init() {
     .execute_script_static(runtime.v8_isolate(), "", "Deno.core.ops.op_test()")
     .unwrap();
 
+  let op_names = runtime.op_names();
+  assert_eq!(op_names[op_names.len() - 1], "op_test");
+
   let scope = &mut realm.handle_scope(runtime.v8_isolate());
   assert_eq!(ret, serde_v8::to_v8(scope, "Test").unwrap());
 }
diff --git a/core/runtime/tests/ops.rs b/core/runtime/tests/ops.rs
index e361925..2c1e526 100644
--- a/core/runtime/tests/ops.rs
+++ b/core/runtime/tests/ops.rs
@@ -501,6 +501,22 @@ fn test_dispatch_stack_zero_copy_bufs() {
   assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
 }
 
+#[test]
+fn test_call_site() {
+  let (mut runtime, _) = setup(Mode::Async);
+  runtime
+    .execute_script_static(
+      "file:///filename.js",
+      r#"
+      const cs = Deno.core.currentUserCallSite();
+      assert(cs.fileName === "file:///filename.js");
+      assert(cs.lineNumber === 2);
+      assert(cs.columnNumber === 28);
+    "#,
+    )
+    .unwrap();
+}
+
 /// Test that long-running ops do not block dynamic imports from loading.
 // https://github.com/denoland/deno/issues/19903
 // https://github.com/denoland/deno/issues/19455
diff --git a/ops/op2/test_cases/sync/op_state_attr.out b/ops/op2/test_cases/sync/op_state_attr.out
index 1e73a1c..8f32e0c 100644
--- a/ops/op2/test_cases/sync/op_state_attr.out
+++ b/ops/op2/test_cases/sync/op_state_attr.out
@@ -42,9 +42,9 @@ impl op_state_rc {
                 .value() as *const deno_core::_ops::OpCtx)
         };
         let result = {
-            let arg0 = opctx.state.borrow();
-            let arg0 = arg0.borrow::<Something>();
-            let arg1 = opctx.state.borrow();
+            let arg0 = ::std::cell::RefCell::borrow(&opctx.state);
+            let arg0 = deno_core::_ops::opstate_borrow::<Something>(&arg0);
+            let arg1 = &::std::cell::RefCell::borrow(&opctx.state);
             let arg1 = arg1.try_borrow::<Something>();
             Self::call(arg0, arg1)
         };
@@ -63,9 +63,9 @@ impl op_state_rc {
         };
         let opstate = &opctx.state;
         let result = {
-            let arg0 = opstate.borrow();
-            let arg0 = arg0.borrow::<Something>();
-            let arg1 = opstate.borrow();
+            let arg0 = ::std::cell::RefCell::borrow(&opstate);
+            let arg0 = deno_core::_ops::opstate_borrow::<Something>(&arg0);
+            let arg1 = &::std::cell::RefCell::borrow(&opstate);
             let arg1 = arg1.try_borrow::<Something>();
             Self::call(arg0, arg1)
         };
diff --git a/ops/op2/test_cases/sync/op_state_attr.rs b/ops/op2/test_cases/sync/op_state_attr.rs
index 8fdde64..40efaad 100644
--- a/ops/op2/test_cases/sync/op_state_attr.rs
+++ b/ops/op2/test_cases/sync/op_state_attr.rs
@@ -2,6 +2,12 @@
 #![deny(warnings)]
 deno_ops_compile_test_runner::prelude!();
 
+// Test w/ import pollution
+#[allow(unused)]
+use std::borrow::Borrow;
+#[allow(unused)]
+use std::borrow::BorrowMut;
+
 struct Something {}
 
 #[op2(fast)]
diff --git a/ops/op2/test_cases/sync/op_state_ref.out b/ops/op2/test_cases/sync/op_state_ref.out
index da3326b..077c7a9 100644
--- a/ops/op2/test_cases/sync/op_state_ref.out
+++ b/ops/op2/test_cases/sync/op_state_ref.out
@@ -42,7 +42,7 @@ impl op_state_ref {
                 .value() as *const deno_core::_ops::OpCtx)
         };
         let result = {
-            let arg0 = &opctx.state.borrow();
+            let arg0 = &::std::cell::RefCell::borrow(&opctx.state);
             Self::call(arg0)
         };
         result as _
@@ -60,7 +60,7 @@ impl op_state_ref {
         };
         let opstate = &opctx.state;
         let result = {
-            let arg0 = &opstate.borrow();
+            let arg0 = &::std::cell::RefCell::borrow(&opstate);
             Self::call(arg0)
         };
         deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
@@ -68,3 +68,137 @@ impl op_state_ref {
     #[inline(always)]
     fn call(_state: &OpState) {}
 }
+
+#[allow(non_camel_case_types)]
+struct op_state_mut {
+    _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_state_mut {
+    const NAME: &'static str = stringify!(op_state_mut);
+    const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl::new_internal(
+        stringify!(op_state_mut),
+        false,
+        false,
+        false,
+        1usize as u8,
+        Self::v8_fn_ptr as _,
+        Some({
+            use deno_core::v8::fast_api::Type;
+            use deno_core::v8::fast_api::CType;
+            deno_core::v8::fast_api::FastFunction::new_with_bigint(
+                &[Type::V8Value, Type::CallbackOptions],
+                CType::Void,
+                Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
+            )
+        }),
+    );
+}
+impl op_state_mut {
+    pub const fn name() -> &'static str {
+        stringify!(op_state_mut)
+    }
+    #[deprecated(note = "Use the const op::DECL instead")]
+    pub const fn decl() -> deno_core::_ops::OpDecl {
+        <Self as deno_core::_ops::Op>::DECL
+    }
+    fn v8_fn_ptr_fast(
+        _: deno_core::v8::Local<deno_core::v8::Object>,
+        fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
+    ) -> () {
+        let fast_api_callback_options = unsafe { &mut *fast_api_callback_options };
+        let opctx = unsafe {
+            &*(deno_core::v8::Local::<
+                deno_core::v8::External,
+            >::cast(unsafe { fast_api_callback_options.data.data })
+                .value() as *const deno_core::_ops::OpCtx)
+        };
+        let result = {
+            let arg0 = &mut ::std::cell::RefCell::borrow_mut(&opctx.state);
+            Self::call(arg0)
+        };
+        result as _
+    }
+    extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
+        let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
+            &*info
+        });
+        let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
+            &*info
+        });
+        let opctx = unsafe {
+            &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
+                as *const deno_core::_ops::OpCtx)
+        };
+        let opstate = &opctx.state;
+        let result = {
+            let arg0 = &mut ::std::cell::RefCell::borrow_mut(&opstate);
+            Self::call(arg0)
+        };
+        deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
+    }
+    #[inline(always)]
+    fn call(_state: &mut OpState) {}
+}
+
+#[allow(non_camel_case_types)]
+struct op_state_and_v8 {
+    _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_state_and_v8 {
+    const NAME: &'static str = stringify!(op_state_and_v8);
+    const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl::new_internal(
+        stringify!(op_state_and_v8),
+        false,
+        false,
+        false,
+        2usize as u8,
+        Self::v8_fn_ptr as _,
+        None,
+    );
+}
+impl op_state_and_v8 {
+    pub const fn name() -> &'static str {
+        stringify!(op_state_and_v8)
+    }
+    #[deprecated(note = "Use the const op::DECL instead")]
+    pub const fn decl() -> deno_core::_ops::OpDecl {
+        <Self as deno_core::_ops::Op>::DECL
+    }
+    extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
+        let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
+            &*info
+        });
+        let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
+            &*info
+        });
+        let opctx = unsafe {
+            &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
+                as *const deno_core::_ops::OpCtx)
+        };
+        let mut scope = unsafe { &mut *opctx.isolate };
+        let opstate = &opctx.state;
+        let result = {
+            let arg1 = args.get(0usize as i32);
+            let Ok(mut arg1) = deno_core::_ops::v8_try_convert::<
+                deno_core::v8::Function,
+            >(arg1) else {
+                let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*info) };
+                let msg = deno_core::v8::String::new_from_one_byte(
+                        &mut scope,
+                        "expected Function".as_bytes(),
+                        deno_core::v8::NewStringType::Normal,
+                    )
+                    .unwrap();
+                let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
+                scope.throw_exception(exc);
+                return;
+            };
+            let arg1 = deno_core::v8::Global::new(&mut scope, arg1);
+            let arg0 = &mut ::std::cell::RefCell::borrow_mut(&opstate);
+            Self::call(arg0, arg1)
+        };
+        deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
+    }
+    #[inline(always)]
+    fn call(_state: &mut OpState, _callback: v8::Global<v8::Function>) {}
+}
diff --git a/ops/op2/test_cases/sync/op_state_ref.rs b/ops/op2/test_cases/sync/op_state_ref.rs
index f765f5f..83d2632 100644
--- a/ops/op2/test_cases/sync/op_state_ref.rs
+++ b/ops/op2/test_cases/sync/op_state_ref.rs
@@ -3,6 +3,19 @@
 deno_ops_compile_test_runner::prelude!();
 
 use deno_core::OpState;
+use deno_core::v8;
+
+// Test w/ import pollution
+#[allow(unused)]
+use std::borrow::Borrow;
+#[allow(unused)]
+use std::borrow::BorrowMut;
 
 #[op2(fast)]
 fn op_state_ref(_state: &OpState) {}
+
+#[op2(fast)]
+fn op_state_mut(_state: &mut OpState) {}
+
+#[op2]
+fn op_state_and_v8(_state: &mut OpState, #[global] _callback: v8::Global<v8::Function>) {}
diff --git a/ops/optimizer_tests/op_blob_revoke_object_url.out b/ops/optimizer_tests/op_blob_revoke_object_url.out
index 75c0c80..c88e88c 100644
--- a/ops/optimizer_tests/op_blob_revoke_object_url.out
+++ b/ops/optimizer_tests/op_blob_revoke_object_url.out
@@ -66,7 +66,10 @@ impl op_blob_revoke_object_url {
                 );
             }
         };
-        let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state), arg_0);
+        let result = Self::call(
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
+            arg_0,
+        );
         let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
         op_state.tracker.track_sync(ctx.id);
         match result {
diff --git a/ops/optimizer_tests/op_print.out b/ops/optimizer_tests/op_print.out
index f7108d5..9a4540e 100644
--- a/ops/optimizer_tests/op_print.out
+++ b/ops/optimizer_tests/op_print.out
@@ -78,7 +78,7 @@ impl op_print {
             }
         };
         let result = Self::call(
-            &mut std::cell::RefCell::borrow_mut(&ctx.state),
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
             arg_0,
             arg_1,
         );
diff --git a/ops/optimizer_tests/op_state.out b/ops/optimizer_tests/op_state.out
index 9cce4e4..0e0b633 100644
--- a/ops/optimizer_tests/op_state.out
+++ b/ops/optimizer_tests/op_state.out
@@ -73,7 +73,10 @@ impl op_set_exit_code {
                 return deno_core::_ops::throw_type_error(scope, msg);
             }
         };
-        let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state), arg_0);
+        let result = Self::call(
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
+            arg_0,
+        );
         let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
         op_state.tracker.track_sync(ctx.id);
     }
diff --git a/ops/optimizer_tests/op_state_basic1.out b/ops/optimizer_tests/op_state_basic1.out
index 14df2fa..a7eccde 100644
--- a/ops/optimizer_tests/op_state_basic1.out
+++ b/ops/optimizer_tests/op_state_basic1.out
@@ -85,7 +85,7 @@ impl foo {
             }
         };
         let result = Self::call(
-            &mut std::cell::RefCell::borrow_mut(&ctx.state),
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
             arg_0,
             arg_1,
         );
diff --git a/ops/optimizer_tests/op_state_generics.out b/ops/optimizer_tests/op_state_generics.out
index 72a302d..b62a352 100644
--- a/ops/optimizer_tests/op_state_generics.out
+++ b/ops/optimizer_tests/op_state_generics.out
@@ -66,7 +66,7 @@ where
             &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
                 as *const deno_core::_ops::OpCtx)
         };
-        let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state));
+        let result = Self::call(&mut ::std::cell::RefCell::borrow_mut(&ctx.state));
         let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
         op_state.tracker.track_sync(ctx.id);
     }
diff --git a/ops/optimizer_tests/op_state_result.out b/ops/optimizer_tests/op_state_result.out
index b0ca7de..d66d041 100644
--- a/ops/optimizer_tests/op_state_result.out
+++ b/ops/optimizer_tests/op_state_result.out
@@ -63,7 +63,7 @@ impl foo {
                 as *const deno_core::_ops::OpCtx)
         };
         {
-            let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
+            let op_state = &mut ::std::cell::RefCell::borrow_mut(&ctx.state);
             if let Some(err) = op_state.last_fast_op_error.take() {
                 let exception = deno_core::error::to_v8_error(
                     scope,
@@ -97,7 +97,7 @@ impl foo {
             }
         };
         let result = Self::call(
-            &mut std::cell::RefCell::borrow_mut(&ctx.state),
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
             arg_0,
             arg_1,
         );
diff --git a/ops/optimizer_tests/op_state_warning.out b/ops/optimizer_tests/op_state_warning.out
index 615048d..5d74e08 100644
--- a/ops/optimizer_tests/op_state_warning.out
+++ b/ops/optimizer_tests/op_state_warning.out
@@ -69,7 +69,7 @@ impl op_listen {
                 as *const deno_core::_ops::OpCtx)
         };
         {
-            let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
+            let op_state = &mut ::std::cell::RefCell::borrow_mut(&ctx.state);
             if let Some(err) = op_state.last_fast_op_error.take() {
                 let exception = deno_core::error::to_v8_error(
                     scope,
@@ -80,7 +80,7 @@ impl op_listen {
                 return;
             }
         }
-        let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state));
+        let result = Self::call(&mut ::std::cell::RefCell::borrow_mut(&ctx.state));
         let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
         op_state.tracker.track_sync(ctx.id);
         match result {
diff --git a/ops/optimizer_tests/op_state_with_transforms.out b/ops/optimizer_tests/op_state_with_transforms.out
index efccd5e..b17ab75 100644
--- a/ops/optimizer_tests/op_state_with_transforms.out
+++ b/ops/optimizer_tests/op_state_with_transforms.out
@@ -110,7 +110,10 @@ where
                 }
             }
         };
-        let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state), arg_0);
+        let result = Self::call(
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
+            arg_0,
+        );
         let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
         op_state.tracker.track_sync(ctx.id);
     }
diff --git a/ops/optimizer_tests/opstate_with_arity.out b/ops/optimizer_tests/opstate_with_arity.out
index 3e052b8..6a8c92c 100644
--- a/ops/optimizer_tests/opstate_with_arity.out
+++ b/ops/optimizer_tests/opstate_with_arity.out
@@ -63,7 +63,7 @@ impl op_add_4 {
                 as *const deno_core::_ops::OpCtx)
         };
         {
-            let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
+            let op_state = &mut ::std::cell::RefCell::borrow_mut(&ctx.state);
             if let Some(err) = op_state.last_fast_op_error.take() {
                 let exception = deno_core::error::to_v8_error(
                     scope,
diff --git a/ops/optimizer_tests/option_arg.out b/ops/optimizer_tests/option_arg.out
index 94ae14c..17fd0c2 100644
--- a/ops/optimizer_tests/option_arg.out
+++ b/ops/optimizer_tests/option_arg.out
@@ -64,7 +64,10 @@ impl op_try_close {
                 return deno_core::_ops::throw_type_error(scope, msg);
             }
         };
-        let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state), arg_0);
+        let result = Self::call(
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
+            arg_0,
+        );
         let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
         op_state.tracker.track_sync(ctx.id);
         match result {
diff --git a/ops/optimizer_tests/param_mut_binding_warning.out b/ops/optimizer_tests/param_mut_binding_warning.out
index 2357426..af5225c 100644
--- a/ops/optimizer_tests/param_mut_binding_warning.out
+++ b/ops/optimizer_tests/param_mut_binding_warning.out
@@ -79,7 +79,7 @@ impl op_read_sync {
             }
         };
         let result = Self::call(
-            &mut std::cell::RefCell::borrow_mut(&ctx.state),
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
             arg_0,
             arg_1,
         );
diff --git a/ops/optimizer_tests/raw_ptr.out b/ops/optimizer_tests/raw_ptr.out
index aa011b8..a7bc5ab 100644
--- a/ops/optimizer_tests/raw_ptr.out
+++ b/ops/optimizer_tests/raw_ptr.out
@@ -141,7 +141,7 @@ where
             );
         };
         let result = Self::call(
-            &mut std::cell::RefCell::borrow_mut(&ctx.state),
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
             arg_0,
             arg_1,
         );
diff --git a/ops/optimizer_tests/u64_result.out b/ops/optimizer_tests/u64_result.out
index 93a6a81..d638966 100644
--- a/ops/optimizer_tests/u64_result.out
+++ b/ops/optimizer_tests/u64_result.out
@@ -54,7 +54,7 @@ impl op_bench_now {
             &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
                 as *const deno_core::_ops::OpCtx)
         };
-        let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state));
+        let result = Self::call(&mut ::std::cell::RefCell::borrow_mut(&ctx.state));
         let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
         op_state.tracker.track_sync(ctx.id);
         match result {
diff --git a/ops/optimizer_tests/unit_result.out b/ops/optimizer_tests/unit_result.out
index ce1f007..df44dab 100644
--- a/ops/optimizer_tests/unit_result.out
+++ b/ops/optimizer_tests/unit_result.out
@@ -63,7 +63,7 @@ impl op_unit_result {
                 as *const deno_core::_ops::OpCtx)
         };
         {
-            let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
+            let op_state = &mut ::std::cell::RefCell::borrow_mut(&ctx.state);
             if let Some(err) = op_state.last_fast_op_error.take() {
                 let exception = deno_core::error::to_v8_error(
                     scope,
diff --git a/ops/optimizer_tests/unit_result2.out b/ops/optimizer_tests/unit_result2.out
index f4e185c..fa990c6 100644
--- a/ops/optimizer_tests/unit_result2.out
+++ b/ops/optimizer_tests/unit_result2.out
@@ -70,7 +70,7 @@ impl op_set_nodelay {
                 as *const deno_core::_ops::OpCtx)
         };
         {
-            let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
+            let op_state = &mut ::std::cell::RefCell::borrow_mut(&ctx.state);
             if let Some(err) = op_state.last_fast_op_error.take() {
                 let exception = deno_core::error::to_v8_error(
                     scope,
@@ -104,7 +104,7 @@ impl op_set_nodelay {
             }
         };
         let result = Self::call(
-            &mut std::cell::RefCell::borrow_mut(&ctx.state),
+            &mut ::std::cell::RefCell::borrow_mut(&ctx.state),
             arg_0,
             arg_1,
         );