Repository: denoland/deno_core
Pull request #232 (2023-09-22 18:50:27)

Add documentation options for extension!()
Added `docs: comma separated list of toplevel #[doc=...] tags to be applied to the extension's resulting struct` to extension! to allow users to set docblocks for it, since the struct is always made public

Added comments for generated functions, since they break linting when warning about missing function docs

Added an op2 example that uses the change (also it is difficult to find samples of op2 and extension! in use with the runtime - having access to such an example would have simplified my usage of the crate significantly

CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/denoland/deno_core?pullRequest=232) <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=232) 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=232) it.</sub>

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 91edb5f..041c741 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -281,7 +281,7 @@ dependencies = [
 
 [[package]]
 name = "deno_core"
-version = "0.216.0"
+version = "0.217.0"
 dependencies = [
  "anyhow",
  "bencher",
@@ -320,7 +320,7 @@ dependencies = [
 
 [[package]]
 name = "deno_ops"
-version = "0.92.0"
+version = "0.93.0"
 dependencies = [
  "deno-proc-macro-rules",
  "lazy-regex",
@@ -1231,7 +1231,7 @@ dependencies = [
 
 [[package]]
 name = "serde_v8"
-version = "0.125.0"
+version = "0.126.0"
 dependencies = [
  "bencher",
  "bytes",
diff --git a/Cargo.toml b/Cargo.toml
index cece481..c26a04d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,9 +17,9 @@ repository = "https://github.com/denoland/deno_core"
 
 [workspace.dependencies]
 # Local dependencies
-deno_core = { version = "0.216.0", path = "./core" }
-deno_ops = { version = "0.92.0", path = "./ops" }
-serde_v8 = { version = "0.125.0", path = "./serde_v8" }
+deno_core = { version = "0.217.0", path = "./core" }
+deno_ops = { version = "0.93.0", path = "./ops" }
+serde_v8 = { version = "0.126.0", path = "./serde_v8" }
 
 v8 = { version = "0.78.0", default-features = false }
 deno_ast = { version = "0.29.1", features = ["transpiling"] }
diff --git a/core/Cargo.toml b/core/Cargo.toml
index fb4569c..77ea583 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "deno_core"
-version = "0.216.0"
+version = "0.217.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
diff --git a/core/examples/op2.js b/core/examples/op2.js
new file mode 100644
index 0000000..5ff2153
--- /dev/null
+++ b/core/examples/op2.js
@@ -0,0 +1,3 @@
+globalThis.op2_sample = {
+  "use_state": (f) => Deno.core.ops.op_use_state(f),
+};
diff --git a/core/examples/op2.rs b/core/examples/op2.rs
new file mode 100644
index 0000000..101e180
--- /dev/null
+++ b/core/examples/op2.rs
@@ -0,0 +1,68 @@
+use anyhow::Context;
+use deno_core::anyhow::Error;
+use deno_core::extension;
+use deno_core::op2;
+use deno_core::resolve_path;
+use deno_core::v8;
+use deno_core::FsModuleLoader;
+use deno_core::JsRuntime;
+use deno_core::OpState;
+use std::rc::Rc;
+
+#[op2]
+fn op_use_state(
+  state: &mut OpState,
+  #[global] callback: v8::Global<v8::Function>,
+) -> Result<(), Error> {
+  state.put(callback);
+  Ok(())
+}
+
+extension!(
+  op2_sample,
+  ops = [op_use_state],
+  esm_entry_point = "ext:op2_sample/op2.js",
+  esm = [ dir "examples", "op2.js" ],
+  docs = "A small example demonstrating op2 usage.", "Contains one op."
+);
+
+fn main() -> Result<(), Error> {
+  let module_name = "test.js";
+  let module_code = "
+      op2_sample.use_state(() => {
+          console.log('Hello World');
+      });
+  "
+  .to_string();
+
+  let mut js_runtime = JsRuntime::new(deno_core::RuntimeOptions {
+    module_loader: Some(Rc::new(FsModuleLoader)),
+    extensions: vec![op2_sample::init_ops_and_esm()],
+    ..Default::default()
+  });
+
+  let main_module = resolve_path(
+    module_name,
+    &std::env::current_dir()
+      .context("Unable to get current working directory")?,
+  )?;
+
+  let future = async move {
+    let mod_id = js_runtime
+      .load_main_module(
+        &main_module,
+        Some(deno_core::FastString::from(module_code)),
+      )
+      .await?;
+
+    let result = js_runtime.mod_evaluate(mod_id);
+    js_runtime.run_event_loop(false).await?;
+    result.await?
+  };
+
+  tokio::runtime::Builder::new_current_thread()
+    .enable_all()
+    .build()
+    .unwrap()
+    .block_on(future)
+}
diff --git a/core/extensions.rs b/core/extensions.rs
index 64f89d5..2cd0ec6 100644
--- a/core/extensions.rs
+++ b/core/extensions.rs
@@ -232,6 +232,7 @@ macro_rules! or {
 ///   my_extension,
 ///   ops = [ op_xyz ],
 ///   esm = [ "my_script.js" ],
+///   docs = "A small sample extension"
 /// );
 /// ```
 ///
@@ -249,6 +250,7 @@ macro_rules! or {
 ///  * event_loop_middleware: an event-loop middleware function (see [`ExtensionBuilder::event_loop_middleware`])
 ///  * global_template_middleware: a global template middleware function (see [`ExtensionBuilder::global_template_middleware`])
 ///  * global_object_middleware: a global object middleware function (see [`ExtensionBuilder::global_object_middleware`])
+///  * docs: comma separated list of toplevel #[doc=...] tags to be applied to the extension's resulting struct
 #[macro_export]
 macro_rules! extension {
   (
@@ -269,11 +271,24 @@ macro_rules! extension {
     $(, global_object_middleware = $global_object_middleware_fn:expr )?
     $(, external_references = [ $( $external_reference:expr ),* $(,)? ] )?
     $(, customizer = $customizer_fn:expr )?
+    $(, docs = $($docblocks:expr),+)?
     $(,)?
   ) => {
-    /// Extension struct for
-    #[doc = stringify!($name)]
-    /// .
+    $( $(#[doc = $docblocks])+ )?
+    ///
+    /// An extension for use with the Deno JS runtime.
+    /// To use it, provide it as an argument when instantiating your runtime:
+    ///
+    /// ```rust,ignore
+    /// use deno_core::{ JsRuntime, RuntimeOptions };
+    ///
+    #[doc = concat!("let mut extensions = vec![", stringify!($name), "::init_ops_and_esm()];")]
+    /// let mut js_runtime = JsRuntime::new(RuntimeOptions {
+    ///   extensions,
+    ///   ..Default::default()
+    /// });
+    /// ```
+    ///
     #[allow(non_camel_case_types)]
     pub struct $name {
     }
@@ -358,6 +373,12 @@ macro_rules! extension {
       }
 
       #[allow(dead_code)]
+      /// Legacy function for extension instantiation.
+      /// Please use `init_ops_and_esm` or `init_ops` instead
+      ///
+      /// # Returns
+      /// an Extension object that can be used during instantiation of a JsRuntime
+      #[deprecated(since="0.216.0", note="please use `init_ops_and_esm` or `init_ops` instead")]
       pub fn init_js_only $( <  $( $param : $type + 'static ),* > )? () -> $crate::Extension
       $( where $( $bound : $bound_type ),+ )?
       {
@@ -368,6 +389,13 @@ macro_rules! extension {
       }
 
       #[allow(dead_code)]
+      /// Initialize this extension for runtime or snapshot creation. Use this
+      /// function if the runtime or snapshot is not created from a (separate)
+      /// snapshot, or that snapshot does not contain this extension. Otherwise
+      /// use `init_ops()` instead.
+      ///
+      /// # Returns
+      /// an Extension object that can be used during instantiation of a JsRuntime
       pub fn init_ops_and_esm $( <  $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension
       $( where $( $bound : $bound_type ),+ )?
       {
@@ -379,6 +407,13 @@ macro_rules! extension {
       }
 
       #[allow(dead_code)]
+      /// Initialize this extension for runtime or snapshot creation, excluding
+      /// its JavaScript sources and evaluation. This is used when the runtime
+      /// or snapshot is created from a (separate) snapshot which includes this
+      /// extension in order to avoid evaluating the JavaScript twice.
+      ///
+      /// # Returns
+      /// an Extension object that can be used during instantiation of a JsRuntime
       pub fn init_ops $( <  $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension
       $( where $( $bound : $bound_type ),+ )?
       {
diff --git a/core/external.rs b/core/external.rs
new file mode 100644
index 0000000..5e0ee3e
--- /dev/null
+++ b/core/external.rs
@@ -0,0 +1,53 @@
+use std::{marker::PhantomData, rc::Rc, cell::RefCell};
+
+/// Define an external type.
+#[macro_export]
+macro_rules! external {
+  ($name:literal, $type:ident) => {
+      
+  };
+}
+pub use external;
+
+pub trait Externalizable {
+  fn marker() -> u64;
+}
+
+pub struct ExternalDefinition {
+  name: &'static str,
+}
+
+#[repr(C)]
+struct ExternalWithMarker<T> {
+  marker: u64,
+  external: RefCell<T>,
+}
+
+/// A strongly-typed external pointer.
+#[repr(transparent)]
+pub struct ExternalPointer<E: Externalizable> {
+  ptr: *mut ExternalWithMarker<E>,
+  _type: std::marker::PhantomData<E>,
+}
+
+impl <E: Externalizable> ExternalPointer<E> {
+  pub fn destroy(self) {
+
+  }
+}
+
+impl <E: Externalizable> TryFrom<*mut std::ffi::c_void> for ExternalPointer<E> {
+  type Error = &'static str;
+
+  #[inline(always)]
+  fn try_from(value: *mut std::ffi::c_void) -> Result<Self, Self::Error> {
+    let expected_marker = E::marker();
+    // SAFETY: we assume the pointer is valid. If it is not, we risk a crash but that's
+    // unfortunately not something we can easily test.
+    if value.align_offset(std::mem::align_of::<u64>()) != 0 
+    || unsafe { std::ptr::read::<u64>(value) } != expected_marker {
+      return Err("Invalid v8::External");
+    }
+    Ok(Self { ptr: value as _, _type: PhantomData })
+  }
+}
diff --git a/core/runtime/ops.rs b/core/runtime/ops.rs
index 4d66ccd..13b68dc 100644
--- a/core/runtime/ops.rs
+++ b/core/runtime/ops.rs
@@ -327,6 +327,8 @@ pub fn to_external_option(external: &v8::Value) -> Option<*mut c_void> {
     // SAFETY: We know this is an external
     let external: &v8::External = unsafe { std::mem::transmute(external) };
     Some(external.value())
+  } else if external.is_null() {
+    Some(0 as _)
   } else {
     None
   }
@@ -664,12 +666,16 @@ mod tests {
       op_state_mut_attr,
       op_state_multi_attr,
       op_buffer_slice,
+      op_buffer_ptr,
       op_buffer_slice_32,
+      op_buffer_ptr_32,
       op_buffer_slice_unsafe_callback,
       op_buffer_copy,
       op_buffer_bytesmut,
       op_external_make,
       op_external_process,
+      op_external_make_null,
+      op_external_process_null,
 
       op_async_void,
       op_async_number,
@@ -1511,6 +1517,19 @@ mod tests {
     }
   }
 
+  #[op2(core, fast)]
+  pub fn op_buffer_ptr(
+    #[buffer] input: *const u8,
+    #[number] inlen: usize,
+    #[buffer] output: *mut u8,
+    #[number] outlen: usize,
+  ) {
+    if inlen > 0 && outlen > 0 {
+      // SAFETY: for test
+      unsafe { std::ptr::write(output, std::ptr::read(input)) }
+    }
+  }
+
   #[op2(core, fast)]
   pub fn op_buffer_slice_32(
     #[buffer] input: &[u32],
@@ -1525,18 +1544,38 @@ mod tests {
     }
   }
 
+  #[op2(core, fast)]
+  pub fn op_buffer_ptr_32(
+    #[buffer] input: *const u32,
+    #[number] inlen: usize,
+    #[buffer] output: *mut u32,
+    #[number] outlen: usize,
+  ) {
+    if inlen > 0 && outlen > 0 {
+      // SAFETY: for test
+      unsafe { std::ptr::write(output, std::ptr::read(input)) }
+    }
+  }
+
   #[tokio::test]
   pub async fn test_op_buffer_slice() -> Result<(), Box<dyn std::error::Error>>
   {
-    for (op, arr, size) in [
-      ("op_buffer_slice", "Uint8Array", 1),
-      ("op_buffer_slice_32", "Uint32Array", 4),
+    for (op, op_ptr, arr, size) in [
+      ("op_buffer_slice", "op_buffer_ptr", "Uint8Array", 1),
+      ("op_buffer_slice_32", "op_buffer_ptr_32", "Uint32Array", 4),
     ] {
+      // Zero-length buffers
       run_test2(
         10000,
         op,
         &format!("{op}(new {arr}(0), 0, new {arr}(0), 0);"),
       )?;
+      // Zero-length ptrs
+      run_test2(
+        10000,
+        op_ptr,
+        &format!("{op_ptr}(new {arr}(0), 0, new {arr}(0), 0);"),
+      )?;
       // UintXArray -> UintXArray
       run_test2(
         10000,
@@ -1548,6 +1587,17 @@ mod tests {
         assert(out[0] == 1);"
         ),
       )?;
+      // UintXArray -> UintXArray
+      run_test2(
+        10000,
+        op_ptr,
+        &format!(
+          r"
+        let out = new {arr}(10);
+        {op_ptr}(new {arr}([1,2,3]), 3, out, 10);
+        assert(out[0] == 1);"
+        ),
+      )?;
       // UintXArray(ArrayBuffer) -> UintXArray(ArrayBuffer)
       run_test2(
         10000,
@@ -1702,6 +1752,29 @@ mod tests {
     Ok(())
   }
 
+  #[op2(core, fast)]
+  fn op_external_make_null() -> *const std::ffi::c_void {
+    0 as _
+  }
+
+  #[op2(core, fast)]
+  fn op_external_process_null(
+    input: *const std::ffi::c_void,
+  ) -> *const std::ffi::c_void {
+    assert_eq!(input, 0 as _);
+    input
+  }
+
+  #[tokio::test]
+  pub async fn test_external_null() -> Result<(), Box<dyn std::error::Error>> {
+    run_test2(
+      10000,
+      "op_external_make_null, op_external_process_null",
+      "assert(op_external_process_null(op_external_make_null()) === null)",
+    )?;
+    Ok(())
+  }
+
   #[op2(async, core)]
   async fn op_async_void() {}
 
diff --git a/core/runtime/ops_rust_to_v8.rs b/core/runtime/ops_rust_to_v8.rs
index 39d1edf..658f1c1 100644
--- a/core/runtime/ops_rust_to_v8.rs
+++ b/core/runtime/ops_rust_to_v8.rs
@@ -278,7 +278,13 @@ to_v8_retval!((f32, f64): |value, rv| rv.set_double(value as _));
 // Heavier primitives with no retval shortcuts
 //
 
-to_v8!((*const c_void, *mut c_void): |value, scope| v8::External::new(scope, value as _));
+to_v8!((*const c_void, *mut c_void): |value, scope| {
+  if value.is_null() {
+    v8::Local::<v8::Value>::from(v8::null(scope))
+  } else {
+    v8::Local::<v8::Value>::from(v8::External::new(scope, value as _))
+  }
+});
 to_v8!((u64, usize): |value, scope| v8::BigInt::new_from_u64(scope, value as _));
 to_v8!((i64, isize): |value, scope| v8::BigInt::new_from_i64(scope, value as _));
 
@@ -286,7 +292,7 @@ to_v8!((i64, isize): |value, scope| v8::BigInt::new_from_i64(scope, value as _))
 // Strings
 //
 
-to_v8_fallible!((String, Cow<'a, str>, &'a str): |value, scope| v8::String::new(scope, &value).ok_or_else(|| serde_v8::Error::Message("failed to allocate string".into())));
+to_v8_fallible!((String, Cow<'a, str>, &'a str): |value, scope| v8::String::new(scope, &value).ok_or_else(|| serde_v8::Error::Message("failed to allocate string; buffer exceeds maximum length".into())));
 to_v8_retval_fallible!((String, Cow<'a, str>, &'a str): |value, scope, rv| {
   if value.is_empty() {
     rv.set_empty_string();
@@ -295,7 +301,7 @@ to_v8_retval_fallible!((String, Cow<'a, str>, &'a str): |value, scope, rv| {
   }
   Ok(())
 });
-to_v8_fallible!(Cow<'a, [u8]>: |value, scope| v8::String::new_from_one_byte(scope, &value, v8::NewStringType::Normal).ok_or_else(|| serde_v8::Error::Message("failed to allocate string".into())));
+to_v8_fallible!(Cow<'a, [u8]>: |value, scope| v8::String::new_from_one_byte(scope, &value, v8::NewStringType::Normal).ok_or_else(|| serde_v8::Error::Message("failed to allocate string; buffer exceeds maximum length".into())));
 to_v8_retval_fallible!(Cow<'a, [u8]>: |value, scope, rv| {
   if value.is_empty() {
     rv.set_empty_string();
diff --git a/ops/Cargo.toml b/ops/Cargo.toml
index b123491..ed3e85b 100644
--- a/ops/Cargo.toml
+++ b/ops/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "deno_ops"
-version = "0.92.0"
+version = "0.93.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
diff --git a/ops/op2/README.md b/ops/op2/README.md
index c46cfb7..5571701 100644
--- a/ops/op2/README.md
+++ b/ops/op2/README.md
@@ -564,6 +564,34 @@ UInt8Array (resizable=true,false)
 <tr>
 <td>
 
+```text
+#[buffer] *mut u8
+```
+
+</td><td>
+✅
+</td><td>
+UInt8Array (resizable=true,false)
+</td><td>
+⚠️ JS may modify the contents of the slice if V8 is called re-entrantly. Because of how V8 treats empty arrays in fastcalls, they will always be passed as null.
+</td></tr>
+<tr>
+<td>
+
+```text
+#[buffer] *const u8
+```
+
+</td><td>
+✅
+</td><td>
+UInt8Array (resizable=true,false)
+</td><td>
+⚠️ JS may modify the contents of the slice if V8 is called re-entrantly. Because of how V8 treats empty arrays in fastcalls, they will always be passed as null.
+</td></tr>
+<tr>
+<td>
+
 ```text
 #[buffer(copy)] Vec<u8>
 ```
diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs
index cab6cb8..29748e9 100644
--- a/ops/op2/dispatch_fast.rs
+++ b/ops/op2/dispatch_fast.rs
@@ -278,7 +278,10 @@ pub fn generate_dispatch_fast(
   debug_assert!(fastcall_types.len() == input_types.len());
 
   let output_type = output.quote_rust_type(deno_core);
+  // We don't want clippy to trigger warnings on number of arguments of the fastcall
+  // function -- these will still trigger on our normal call function, however.
   let fast_fn = quote!(
+    #[allow(clippy::too_many_arguments)]
     fn #fast_function(
       _: #deno_core::v8::Local<#deno_core::v8::Object>,
       #( #fastcall_names: #fastcall_types, )*
@@ -326,6 +329,9 @@ fn map_v8_fastcall_arg_to_arg(
     Arg::Buffer(Buffer::Slice(_, NumericArg::u8 | NumericArg::u32)) => {
       quote!(let #arg_ident = #buf;)
     }
+    Arg::Buffer(Buffer::Ptr(_, NumericArg::u8 | NumericArg::u32)) => {
+      quote!(let #arg_ident = if #buf.len() == 0 { ::std::ptr::null_mut() } else { #buf.as_mut_ptr() as _ };)
+    }
     Arg::Buffer(Buffer::Vec(NumericArg::u8 | NumericArg::u32)) => {
       quote!(let #arg_ident = #buf.to_vec();)
     }
@@ -449,12 +455,14 @@ fn map_arg_to_v8_fastcall_type(
   let rv = match arg {
     Arg::Buffer(
       Buffer::Slice(_, NumericArg::u8)
+      | Buffer::Ptr(_, NumericArg::u8)
       | Buffer::Vec(NumericArg::u8)
       | Buffer::BoxSlice(NumericArg::u8)
       | Buffer::Bytes(BufferMode::Copy),
     ) => V8FastCallType::Uint8Array,
     Arg::Buffer(
       Buffer::Slice(_, NumericArg::u32)
+      | Buffer::Ptr(_, NumericArg::u32)
       | Buffer::Vec(NumericArg::u32)
       | Buffer::BoxSlice(NumericArg::u32),
     ) => V8FastCallType::Uint32Array,
diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs
index af61607..0208dbb 100644
--- a/ops/op2/dispatch_slow.rs
+++ b/ops/op2/dispatch_slow.rs
@@ -518,6 +518,12 @@ pub fn from_arg_buffer(
     Buffer::Slice(RefType::Mut, NumericArg::u8 | NumericArg::u32) => {
       quote!(let #arg_ident = #temp.as_mut();)
     }
+    Buffer::Ptr(RefType::Ref, NumericArg::u8 | NumericArg::u32) => {
+      quote!(let #arg_ident = if #temp.len() == 0 { std::ptr::null() } else { #temp.as_ref().as_ptr() };)
+    }
+    Buffer::Ptr(RefType::Mut, NumericArg::u8 | NumericArg::u32) => {
+      quote!(let #arg_ident = if #temp.len() == 0 { std::ptr::null_mut() } else { #temp.as_mut().as_mut_ptr() };)
+    }
     Buffer::Vec(NumericArg::u8 | NumericArg::u32) => {
       quote!(let #arg_ident = #temp.to_vec();)
     }
diff --git a/ops/op2/signature.rs b/ops/op2/signature.rs
index 8d53a1f..0e74b28 100644
--- a/ops/op2/signature.rs
+++ b/ops/op2/signature.rs
@@ -1526,6 +1526,10 @@ mod tests {
     fn op_slices(#[buffer] r#in: &[u8], #[buffer] out: &mut [u8]);
     (Buffer(Slice(Ref, u8)), Buffer(Slice(Mut, u8))) -> Infallible(Void)
   );
+  test!(
+    fn op_pointers(#[buffer] r#in: *const u8, #[buffer] out: *mut u8);
+    (Buffer(Ptr(Ref, u8)), Buffer(Ptr(Mut, u8))) -> Infallible(Void)
+  );
   test!(
     #[serde] fn op_serde(#[serde] input: package::SerdeInputType) -> Result<package::SerdeReturnType, Error>;
     (SerdeV8(package::SerdeInputType)) -> Result(SerdeV8(package::SerdeReturnType))
diff --git a/ops/op2/valid_args.md b/ops/op2/valid_args.md
index ae5a5c7..e5ab701 100644
--- a/ops/op2/valid_args.md
+++ b/ops/op2/valid_args.md
@@ -28,6 +28,8 @@
 | X         | #[serde] (Tuple, Tuple)          |          | any                                                 | ⚠️ May be slow.                                                                                                                                                                                                 |
 | X         | #[buffer] &mut [u8]              | X        | UInt8Array (resizable=true,false)                   | ⚠️ JS may modify the contents of the slice if V8 is called re-entrantly.                                                                                                                                        |
 | X         | #[buffer] &[u8]                  | X        | UInt8Array (resizable=true,false)                   | ⚠️ JS may modify the contents of the slice if V8 is called re-entrantly.                                                                                                                                        |
+| X         | #[buffer] *mut u8                | X        | UInt8Array (resizable=true,false)                   | ⚠️ JS may modify the contents of the slice if V8 is called re-entrantly. Because of how V8 treats empty arrays in fastcalls, they will always be passed as null.                                                |
+| X         | #[buffer] *const u8              | X        | UInt8Array (resizable=true,false)                   | ⚠️ JS may modify the contents of the slice if V8 is called re-entrantly. Because of how V8 treats empty arrays in fastcalls, they will always be passed as null.                                                |
 | X         | #[buffer(copy)] Vec<u8>          | X        | UInt8Array (resizable=true,false)                   | Safe, but forces a copy.                                                                                                                                                                                       |
 | X         | #[buffer(copy)] Box<[u8]>        | X        | UInt8Array (resizable=true,false)                   | Safe, but forces a copy.                                                                                                                                                                                       |
 | X         | #[buffer(copy)] bytes::Bytes     | X        | UInt8Array (resizable=true,false)                   | Safe, but forces a copy.                                                                                                                                                                                       |
diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml
index 3acbdf3..3b4651e 100644
--- a/serde_v8/Cargo.toml
+++ b/serde_v8/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "serde_v8"
-version = "0.125.0"
+version = "0.126.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true


Test patch:
diff --git a/ops/op2/test_cases/sync/add.out b/ops/op2/test_cases/sync/add.out
index b39cb49..0913716 100644
--- a/ops/op2/test_cases/sync/add.out
+++ b/ops/op2/test_cases/sync/add.out
@@ -30,6 +30,7 @@ impl op_add {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: u32,
diff --git a/ops/op2/test_cases/sync/bool.out b/ops/op2/test_cases/sync/bool.out
index e8a8231..fa1e1dc 100644
--- a/ops/op2/test_cases/sync/bool.out
+++ b/ops/op2/test_cases/sync/bool.out
@@ -30,6 +30,7 @@ impl op_bool {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: bool,
diff --git a/ops/op2/test_cases/sync/bool_result.out b/ops/op2/test_cases/sync/bool_result.out
index f9a977b..8ebff34 100644
--- a/ops/op2/test_cases/sync/bool_result.out
+++ b/ops/op2/test_cases/sync/bool_result.out
@@ -30,6 +30,7 @@ impl op_bool {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: bool,
diff --git a/ops/op2/test_cases/sync/buffers.out b/ops/op2/test_cases/sync/buffers.out
index a7dc06e..12eb1b6 100644
--- a/ops/op2/test_cases/sync/buffers.out
+++ b/ops/op2/test_cases/sync/buffers.out
@@ -9,7 +9,7 @@ impl deno_core::_ops::Op for op_buffers {
         false,
         false,
         false,
-        2usize as u8,
+        4usize as u8,
         Self::v8_fn_ptr as _,
         Some({
             use deno_core::v8::fast_api::Type;
@@ -19,6 +19,8 @@ impl deno_core::_ops::Op for op_buffers {
                     Type::V8Value,
                     Type::TypedArray(CType::Uint8),
                     Type::TypedArray(CType::Uint8),
+                    Type::TypedArray(CType::Uint8),
+                    Type::TypedArray(CType::Uint8),
                 ],
                 CType::Void,
                 Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
@@ -34,10 +36,13 @@ impl op_buffers {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiTypedArray<u8>,
         arg1: *mut deno_core::v8::fast_api::FastApiTypedArray<u8>,
+        arg2: *mut deno_core::v8::fast_api::FastApiTypedArray<u8>,
+        arg3: *mut deno_core::v8::fast_api::FastApiTypedArray<u8>,
     ) -> () {
         let result = {
             let arg0 = (unsafe {
@@ -52,7 +57,43 @@ impl op_buffers {
                 )
             }
                 .expect("Invalid buffer"));
-            Self::call(arg0, arg1)
+            let arg2 = if (unsafe {
+                deno_core::v8::fast_api::FastApiTypedArray::get_storage_from_pointer_if_aligned(
+                    arg2,
+                )
+            }
+                .expect("Invalid buffer"))
+                .len() == 0
+            {
+                ::std::ptr::null_mut()
+            } else {
+                (unsafe {
+                    deno_core::v8::fast_api::FastApiTypedArray::get_storage_from_pointer_if_aligned(
+                        arg2,
+                    )
+                }
+                    .expect("Invalid buffer"))
+                    .as_mut_ptr() as _
+            };
+            let arg3 = if (unsafe {
+                deno_core::v8::fast_api::FastApiTypedArray::get_storage_from_pointer_if_aligned(
+                    arg3,
+                )
+            }
+                .expect("Invalid buffer"))
+                .len() == 0
+            {
+                ::std::ptr::null_mut()
+            } else {
+                (unsafe {
+                    deno_core::v8::fast_api::FastApiTypedArray::get_storage_from_pointer_if_aligned(
+                        arg3,
+                    )
+                }
+                    .expect("Invalid buffer"))
+                    .as_mut_ptr() as _
+            };
+            Self::call(arg0, arg1, arg2, arg3)
         };
         result as _
     }
@@ -104,12 +145,58 @@ impl op_buffers {
                 }
             };
             let arg1 = arg1_temp.as_mut();
-            Self::call(arg0, arg1)
+            let arg2 = args.get(2usize as i32);
+            let mut arg2_temp;
+            arg2_temp = match unsafe {
+                deno_core::_ops::to_v8_slice::<u8>(&mut scope, arg2)
+            } {
+                Ok(arg2) => arg2,
+                Err(arg2_err) => {
+                    let msg = deno_core::v8::String::new_from_one_byte(
+                            &mut scope,
+                            arg2_err.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 arg2 = if arg2_temp.len() == 0 {
+                std::ptr::null()
+            } else {
+                arg2_temp.as_ref().as_ptr()
+            };
+            let arg3 = args.get(3usize as i32);
+            let mut arg3_temp;
+            arg3_temp = match unsafe {
+                deno_core::_ops::to_v8_slice::<u8>(&mut scope, arg3)
+            } {
+                Ok(arg3) => arg3,
+                Err(arg3_err) => {
+                    let msg = deno_core::v8::String::new_from_one_byte(
+                            &mut scope,
+                            arg3_err.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 arg3 = if arg3_temp.len() == 0 {
+                std::ptr::null_mut()
+            } else {
+                arg3_temp.as_mut().as_mut_ptr()
+            };
+            Self::call(arg0, arg1, arg2, arg3)
         };
         deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
     }
     #[inline(always)]
-    fn call(_a: &[u8], _b: &mut [u8]) {}
+    fn call(_a: &[u8], _b: &mut [u8], _c: *const u8, _d: *mut u8) {}
 }
 
 #[allow(non_camel_case_types)]
@@ -123,7 +210,7 @@ impl deno_core::_ops::Op for op_buffers_32 {
         false,
         false,
         false,
-        2usize as u8,
+        4usize as u8,
         Self::v8_fn_ptr as _,
         Some({
             use deno_core::v8::fast_api::Type;
@@ -133,6 +220,8 @@ impl deno_core::_ops::Op for op_buffers_32 {
                     Type::V8Value,
                     Type::TypedArray(CType::Uint32),
                     Type::TypedArray(CType::Uint32),
+                    Type::TypedArray(CType::Uint32),
+                    Type::TypedArray(CType::Uint32),
                 ],
                 CType::Void,
                 Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
@@ -148,10 +237,13 @@ impl op_buffers_32 {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiTypedArray<u32>,
         arg1: *mut deno_core::v8::fast_api::FastApiTypedArray<u32>,
+        arg2: *mut deno_core::v8::fast_api::FastApiTypedArray<u32>,
+        arg3: *mut deno_core::v8::fast_api::FastApiTypedArray<u32>,
     ) -> () {
         let result = {
             let arg0 = (unsafe {
@@ -166,7 +258,43 @@ impl op_buffers_32 {
                 )
             }
                 .expect("Invalid buffer"));
-            Self::call(arg0, arg1)
+            let arg2 = if (unsafe {
+                deno_core::v8::fast_api::FastApiTypedArray::get_storage_from_pointer_if_aligned(
+                    arg2,
+                )
+            }
+                .expect("Invalid buffer"))
+                .len() == 0
+            {
+                ::std::ptr::null_mut()
+            } else {
+                (unsafe {
+                    deno_core::v8::fast_api::FastApiTypedArray::get_storage_from_pointer_if_aligned(
+                        arg2,
+                    )
+                }
+                    .expect("Invalid buffer"))
+                    .as_mut_ptr() as _
+            };
+            let arg3 = if (unsafe {
+                deno_core::v8::fast_api::FastApiTypedArray::get_storage_from_pointer_if_aligned(
+                    arg3,
+                )
+            }
+                .expect("Invalid buffer"))
+                .len() == 0
+            {
+                ::std::ptr::null_mut()
+            } else {
+                (unsafe {
+                    deno_core::v8::fast_api::FastApiTypedArray::get_storage_from_pointer_if_aligned(
+                        arg3,
+                    )
+                }
+                    .expect("Invalid buffer"))
+                    .as_mut_ptr() as _
+            };
+            Self::call(arg0, arg1, arg2, arg3)
         };
         result as _
     }
@@ -218,12 +346,58 @@ impl op_buffers_32 {
                 }
             };
             let arg1 = arg1_temp.as_mut();
-            Self::call(arg0, arg1)
+            let arg2 = args.get(2usize as i32);
+            let mut arg2_temp;
+            arg2_temp = match unsafe {
+                deno_core::_ops::to_v8_slice::<u32>(&mut scope, arg2)
+            } {
+                Ok(arg2) => arg2,
+                Err(arg2_err) => {
+                    let msg = deno_core::v8::String::new_from_one_byte(
+                            &mut scope,
+                            arg2_err.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 arg2 = if arg2_temp.len() == 0 {
+                std::ptr::null()
+            } else {
+                arg2_temp.as_ref().as_ptr()
+            };
+            let arg3 = args.get(3usize as i32);
+            let mut arg3_temp;
+            arg3_temp = match unsafe {
+                deno_core::_ops::to_v8_slice::<u32>(&mut scope, arg3)
+            } {
+                Ok(arg3) => arg3,
+                Err(arg3_err) => {
+                    let msg = deno_core::v8::String::new_from_one_byte(
+                            &mut scope,
+                            arg3_err.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 arg3 = if arg3_temp.len() == 0 {
+                std::ptr::null_mut()
+            } else {
+                arg3_temp.as_mut().as_mut_ptr()
+            };
+            Self::call(arg0, arg1, arg2, arg3)
         };
         deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
     }
     #[inline(always)]
-    fn call(_a: &[u32], _b: &mut [u32]) {}
+    fn call(_a: &[u32], _b: &mut [u32], _c: *const u32, _d: *mut u32) {}
 }
 
 #[allow(non_camel_case_types)]
diff --git a/ops/op2/test_cases/sync/buffers.rs b/ops/op2/test_cases/sync/buffers.rs
index a062758..5e9305b 100644
--- a/ops/op2/test_cases/sync/buffers.rs
+++ b/ops/op2/test_cases/sync/buffers.rs
@@ -5,11 +5,11 @@ deno_ops_compile_test_runner::prelude!();
 use deno_core::JsBuffer;
 
 #[op2(fast)]
-fn op_buffers(#[buffer] _a: &[u8], #[buffer] _b: &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]) {
+fn op_buffers_32(#[buffer] _a: &[u32], #[buffer] _b: &mut [u32], #[buffer] _c: *const u32, #[buffer] _d: *mut u32) {
 }
 
 #[op2]
diff --git a/ops/op2/test_cases/sync/buffers_copy.out b/ops/op2/test_cases/sync/buffers_copy.out
index 6245a48..a68de40 100644
--- a/ops/op2/test_cases/sync/buffers_copy.out
+++ b/ops/op2/test_cases/sync/buffers_copy.out
@@ -35,6 +35,7 @@ impl op_buffers {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiTypedArray<u8>,
@@ -180,6 +181,7 @@ impl op_buffers_32 {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiTypedArray<u32>,
diff --git a/ops/op2/test_cases/sync/cfg.out b/ops/op2/test_cases/sync/cfg.out
index 3bf7aa2..0e14384 100644
--- a/ops/op2/test_cases/sync/cfg.out
+++ b/ops/op2/test_cases/sync/cfg.out
@@ -32,6 +32,7 @@ impl op_maybe_windows {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
         let result = { Self::call() };
         result as _
@@ -83,6 +84,7 @@ impl op_maybe_windows {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
         let result = { Self::call() };
         result as _
diff --git a/ops/op2/test_cases/sync/clippy_allow.out b/ops/op2/test_cases/sync/clippy_allow.out
index 4c23b35..6899ae9 100644
--- a/ops/op2/test_cases/sync/clippy_allow.out
+++ b/ops/op2/test_cases/sync/clippy_allow.out
@@ -32,6 +32,7 @@ impl op_extra_annotation {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
         let result = { Self::call() };
         result as _
@@ -81,6 +82,7 @@ impl op_clippy_internal {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
         let result = { Self::call() };
         result as _
diff --git a/ops/op2/test_cases/sync/clippy_allow.rs b/ops/op2/test_cases/sync/clippy_allow.rs
index 2b5aec7..dc91e86 100644
--- a/ops/op2/test_cases/sync/clippy_allow.rs
+++ b/ops/op2/test_cases/sync/clippy_allow.rs
@@ -12,4 +12,4 @@ pub fn op_clippy_internal() -> () {
   {
     #![allow(clippy::await_holding_refcell_ref)]
   }
-}
\ No newline at end of file
+}
diff --git a/ops/op2/test_cases/sync/doc_comment.out b/ops/op2/test_cases/sync/doc_comment.out
index 4e8023c..f326403 100644
--- a/ops/op2/test_cases/sync/doc_comment.out
+++ b/ops/op2/test_cases/sync/doc_comment.out
@@ -31,6 +31,7 @@ impl op_has_doc_comment {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
         let result = { Self::call() };
         result as _
diff --git a/ops/op2/test_cases/sync/generics.out b/ops/op2/test_cases/sync/generics.out
index f645c0b..d20be2b 100644
--- a/ops/op2/test_cases/sync/generics.out
+++ b/ops/op2/test_cases/sync/generics.out
@@ -30,6 +30,7 @@ impl<T: Trait> op_generics<T> {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
         let result = { Self::call() };
         result as _
@@ -77,6 +78,7 @@ impl<T: Trait + 'static> op_generics_static<T> {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
         let result = { Self::call() };
         result as _
@@ -124,6 +126,7 @@ impl<T: Trait + 'static> op_generics_static_where<T> {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
         let result = { Self::call() };
         result as _
diff --git a/ops/op2/test_cases/sync/op_state_attr.out b/ops/op2/test_cases/sync/op_state_attr.out
index 8f32e0c..8356fb2 100644
--- a/ops/op2/test_cases/sync/op_state_attr.out
+++ b/ops/op2/test_cases/sync/op_state_attr.out
@@ -30,6 +30,7 @@ impl op_state_rc {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
diff --git a/ops/op2/test_cases/sync/op_state_rc.out b/ops/op2/test_cases/sync/op_state_rc.out
index 62e120c..acd4bf2 100644
--- a/ops/op2/test_cases/sync/op_state_rc.out
+++ b/ops/op2/test_cases/sync/op_state_rc.out
@@ -30,6 +30,7 @@ impl op_state_rc {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
diff --git a/ops/op2/test_cases/sync/op_state_ref.out b/ops/op2/test_cases/sync/op_state_ref.out
index 077c7a9..c9c98e4 100644
--- a/ops/op2/test_cases/sync/op_state_ref.out
+++ b/ops/op2/test_cases/sync/op_state_ref.out
@@ -30,6 +30,7 @@ impl op_state_ref {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
@@ -101,6 +102,7 @@ impl op_state_mut {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
diff --git a/ops/op2/test_cases/sync/result_external.out b/ops/op2/test_cases/sync/result_external.out
index 6ccf984..c18f276 100644
--- a/ops/op2/test_cases/sync/result_external.out
+++ b/ops/op2/test_cases/sync/result_external.out
@@ -30,6 +30,7 @@ impl op_external_with_result {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
diff --git a/ops/op2/test_cases/sync/result_primitive.out b/ops/op2/test_cases/sync/result_primitive.out
index 620a8b0..e8e5270 100644
--- a/ops/op2/test_cases/sync/result_primitive.out
+++ b/ops/op2/test_cases/sync/result_primitive.out
@@ -30,6 +30,7 @@ impl op_u32_with_result {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
diff --git a/ops/op2/test_cases/sync/result_void.out b/ops/op2/test_cases/sync/result_void.out
index 1b638d4..3ff0f62 100644
--- a/ops/op2/test_cases/sync/result_void.out
+++ b/ops/op2/test_cases/sync/result_void.out
@@ -30,6 +30,7 @@ impl op_void_with_result {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
diff --git a/ops/op2/test_cases/sync/smi.out b/ops/op2/test_cases/sync/smi.out
index 339b773..9529eaa 100644
--- a/ops/op2/test_cases/sync/smi.out
+++ b/ops/op2/test_cases/sync/smi.out
@@ -30,6 +30,7 @@ impl op_smi_unsigned_return {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: i32,
@@ -158,6 +159,7 @@ impl op_smi_signed_return {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: i32,
diff --git a/ops/op2/test_cases/sync/string_cow.out b/ops/op2/test_cases/sync/string_cow.out
index 4f839d0..0e25bba 100644
--- a/ops/op2/test_cases/sync/string_cow.out
+++ b/ops/op2/test_cases/sync/string_cow.out
@@ -30,6 +30,7 @@ impl op_string_cow {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
diff --git a/ops/op2/test_cases/sync/string_onebyte.out b/ops/op2/test_cases/sync/string_onebyte.out
index 7c00236..1bc5d96 100644
--- a/ops/op2/test_cases/sync/string_onebyte.out
+++ b/ops/op2/test_cases/sync/string_onebyte.out
@@ -30,6 +30,7 @@ impl op_string_onebyte {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
diff --git a/ops/op2/test_cases/sync/string_owned.out b/ops/op2/test_cases/sync/string_owned.out
index 670840e..ea265df 100644
--- a/ops/op2/test_cases/sync/string_owned.out
+++ b/ops/op2/test_cases/sync/string_owned.out
@@ -30,6 +30,7 @@ impl op_string_owned {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
diff --git a/ops/op2/test_cases/sync/string_ref.out b/ops/op2/test_cases/sync/string_ref.out
index 5c334de..529224d 100644
--- a/ops/op2/test_cases/sync/string_ref.out
+++ b/ops/op2/test_cases/sync/string_ref.out
@@ -30,6 +30,7 @@ impl op_string_owned {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
diff --git a/ops/op2/test_cases/sync/v8_ref_option.out b/ops/op2/test_cases/sync/v8_ref_option.out
index 48d4708..12d1bd8 100644
--- a/ops/op2/test_cases/sync/v8_ref_option.out
+++ b/ops/op2/test_cases/sync/v8_ref_option.out
@@ -30,6 +30,7 @@ impl op_v8_lifetime {
     pub const fn decl() -> deno_core::_ops::OpDecl {
         <Self as deno_core::_ops::Op>::DECL
     }
+    #[allow(clippy::too_many_arguments)]
     fn v8_fn_ptr_fast(
         _: deno_core::v8::Local<deno_core::v8::Object>,
         arg0: deno_core::v8::Local<deno_core::v8::Value>,