Repository: denoland/deno_core
Pull request #193 (2023-09-13 01:25:05)

refactor: remove TaskQueue
Waiting on https://github.com/denoland/deno_unsync/pull/2


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 9413123..0d7af1c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -281,7 +281,7 @@ dependencies = [
 
 [[package]]
 name = "deno_core"
-version = "0.209.0"
+version = "0.210.0"
 dependencies = [
  "anyhow",
  "bencher",
@@ -320,7 +320,7 @@ dependencies = [
 
 [[package]]
 name = "deno_ops"
-version = "0.87.0"
+version = "0.88.0"
 dependencies = [
  "deno-proc-macro-rules",
  "lazy-regex",
@@ -357,9 +357,9 @@ dependencies = [
 
 [[package]]
 name = "deno_unsync"
-version = "0.1.1"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac0984205f25e71ddd1be603d76e70255953c12ff864707359ab195d26dfc7b3"
+checksum = "0720e562455d6374a5292baec3fc895ed8bfed0937428e3245e50979924e5b15"
 dependencies = [
  "tokio",
 ]
@@ -1231,7 +1231,7 @@ dependencies = [
 
 [[package]]
 name = "serde_v8"
-version = "0.120.0"
+version = "0.121.0"
 dependencies = [
  "bencher",
  "bytes",
@@ -2024,9 +2024,9 @@ checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
 
 [[package]]
 name = "v8"
-version = "0.75.1"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0e0cb10989bf856c2fdd1b6bed1bc6f96148230aa0c954634299125c1f64230"
+checksum = "9d4e8ae7ef8b4e852e728e343cb6bb471a0424dfefa22585ea0c14a61252d73f"
 dependencies = [
  "bitflags 1.3.2",
  "fslock",
diff --git a/Cargo.toml b/Cargo.toml
index e0d54e9..d982443 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,13 +17,13 @@ repository = "https://github.com/denoland/deno_core"
 
 [workspace.dependencies]
 # Local dependencies
-deno_core = { version = "0.209.0", path = "./core" }
-deno_ops = { version = "0.87.0", path = "./ops" }
-serde_v8 = { version = "0.120.0", path = "./serde_v8" }
+deno_core = { version = "0.210.0", path = "./core" }
+deno_ops = { version = "0.88.0", path = "./ops" }
+serde_v8 = { version = "0.121.0", path = "./serde_v8" }
 
-v8 = { version = "0.75.1", default-features = false }
+v8 = { version = "0.76.0", default-features = false }
 deno_ast = { version = "0.29.1", features = ["transpiling"] }
-deno_unsync = "0.1"
+deno_unsync = "0.2.1"
 
 anyhow = "1"
 bencher = "0.1"
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 6d36fe5..d3268f8 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "deno_core"
-version = "0.209.0"
+version = "0.210.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
diff --git a/core/lib.rs b/core/lib.rs
index 39fa0ad..618d286 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -21,7 +21,6 @@ mod path;
 mod resources;
 mod runtime;
 mod source_map;
-mod task_queue;
 
 // Re-exports
 pub use anyhow;
@@ -126,8 +125,6 @@ pub use crate::runtime::Snapshot;
 pub use crate::runtime::V8_WRAPPER_OBJECT_INDEX;
 pub use crate::runtime::V8_WRAPPER_TYPE_INDEX;
 pub use crate::source_map::SourceMapGetter;
-pub use crate::task_queue::TaskQueue;
-pub use crate::task_queue::TaskQueuePermit;
 
 pub fn v8_version() -> &'static str {
   v8::V8::get_version()
diff --git a/core/task_queue.rs b/core/task_queue.rs
deleted file mode 100644
index e51aa0c..0000000
--- a/core/task_queue.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use futures::task::AtomicWaker;
-use futures::Future;
-use parking_lot::Mutex;
-use std::collections::LinkedList;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-
-#[derive(Debug, Default)]
-struct TaskQueueTaskWaker {
-  is_ready: AtomicBool,
-  waker: AtomicWaker,
-}
-
-#[derive(Debug, Default)]
-struct TaskQueueTasks {
-  is_running: bool,
-  wakers: LinkedList<Arc<TaskQueueTaskWaker>>,
-}
-
-/// A queue that executes tasks sequentially one after the other
-/// ensuring order and that no task runs at the same time as another.
-///
-/// Note that tokio's semaphore doesn't seem to maintain order
-/// and so we can't use that in the code that uses this or use
-/// that here.
-#[derive(Debug, Default)]
-pub struct TaskQueue {
-  tasks: Mutex<TaskQueueTasks>,
-}
-
-impl TaskQueue {
-  /// Acquires a permit where the tasks are executed one at a time
-  /// and in the order that they were acquired.
-  pub async fn acquire(&self) -> TaskQueuePermit {
-    let acquire = TaskQueuePermitAcquire::new(self);
-    acquire.await;
-    TaskQueuePermit(self)
-  }
-
-  /// Alternate API that acquires a permit internally
-  /// for the duration of the future.
-  pub async fn queue<R>(&self, future: impl Future<Output = R>) -> R {
-    let _permit = self.acquire().await;
-    future.await
-  }
-}
-
-/// A permit that when dropped will allow another task to proceed.
-pub struct TaskQueuePermit<'a>(&'a TaskQueue);
-
-impl<'a> Drop for TaskQueuePermit<'a> {
-  fn drop(&mut self) {
-    let next_item = {
-      let mut tasks = self.0.tasks.lock();
-      let next_item = tasks.wakers.pop_front();
-      tasks.is_running = next_item.is_some();
-      next_item
-    };
-    if let Some(next_item) = next_item {
-      next_item.is_ready.store(true, Ordering::SeqCst);
-      next_item.waker.wake();
-    }
-  }
-}
-
-struct TaskQueuePermitAcquire<'a> {
-  task_queue: &'a TaskQueue,
-  initialized: AtomicBool,
-  waker: Arc<TaskQueueTaskWaker>,
-}
-
-impl<'a> TaskQueuePermitAcquire<'a> {
-  pub fn new(task_queue: &'a TaskQueue) -> Self {
-    Self {
-      task_queue,
-      initialized: Default::default(),
-      waker: Default::default(),
-    }
-  }
-}
-
-impl<'a> Future for TaskQueuePermitAcquire<'a> {
-  type Output = ();
-
-  fn poll(
-    self: std::pin::Pin<&mut Self>,
-    cx: &mut std::task::Context<'_>,
-  ) -> std::task::Poll<Self::Output> {
-    // update with the latest waker
-    self.waker.waker.register(cx.waker());
-
-    // ensure this is initialized
-    if !self.initialized.swap(true, Ordering::SeqCst) {
-      let mut tasks = self.task_queue.tasks.lock();
-      if !tasks.is_running {
-        tasks.is_running = true;
-        return std::task::Poll::Ready(());
-      }
-      tasks.wakers.push_back(self.waker.clone());
-      return std::task::Poll::Pending;
-    }
-
-    // check if we're ready to run
-    if self.waker.is_ready.load(Ordering::SeqCst) {
-      std::task::Poll::Ready(())
-    } else {
-      std::task::Poll::Pending
-    }
-  }
-}
-
-#[cfg(test)]
-mod tests {
-  use parking_lot::Mutex;
-  use std::sync::Arc;
-
-  use super::TaskQueue;
-
-  #[tokio::test]
-  async fn task_queue_runs_one_after_other() {
-    let task_queue = TaskQueue::default();
-    let mut tasks = Vec::new();
-    let data = Arc::new(Mutex::new(0));
-    for i in 0..100 {
-      let data = data.clone();
-      tasks.push(task_queue.queue(async move {
-        crate::unsync::spawn_blocking(move || {
-          let mut data = data.lock();
-          if *data != i {
-            panic!("Value was not equal.");
-          }
-          *data = i + 1;
-        })
-        .await
-        .unwrap();
-      }));
-    }
-    futures::future::join_all(tasks).await;
-  }
-}
diff --git a/ops/Cargo.toml b/ops/Cargo.toml
index 7537774..856f06d 100644
--- a/ops/Cargo.toml
+++ b/ops/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "deno_ops"
-version = "0.87.0"
+version = "0.88.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs
index c48406b..9697bb5 100644
--- a/ops/op2/dispatch_fast.rs
+++ b/ops/op2/dispatch_fast.rs
@@ -433,6 +433,7 @@ fn map_arg_to_v8_fastcall_type(
     Arg::OptionNumeric(_)
     | Arg::Option(_)
     | Arg::OptionString(_)
+    | Arg::OptionBuffer(_)
     | Arg::SerdeV8(_)
     | Arg::Ref(..) => return Ok(None),
     // We don't support v8 global arguments
diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs
index 6b34c4b..b7662c6 100644
--- a/ops/op2/dispatch_slow.rs
+++ b/ops/op2/dispatch_slow.rs
@@ -298,7 +298,27 @@ pub fn from_arg(
       })
     }
     Arg::Buffer(buffer) => {
-      from_arg_buffer(generator_state, &arg_ident, buffer)?
+      // Explicit temporary lifetime extension so we can take a reference
+      let temp = format_ident!("{}_temp", arg_ident);
+      let buffer = from_arg_buffer(generator_state, &arg_ident, buffer, &temp)?;
+      quote! {
+        let mut #temp;
+        #buffer
+      }
+    }
+    Arg::OptionBuffer(buffer) => {
+      // Explicit temporary lifetime extension so we can take a reference
+      let temp = format_ident!("{}_temp", arg_ident);
+      let some = from_arg_buffer(generator_state, &arg_ident, buffer, &temp)?;
+      quote! {
+        let mut #temp;
+        let #arg_ident = if #arg_ident.is_null_or_undefined() {
+          None
+        } else {
+          #some
+          Some(#arg_ident)
+        };
+      }
     }
     Arg::External(External::Ptr(_)) => {
       from_arg_option(generator_state, &arg_ident, "external")?
@@ -431,6 +451,7 @@ pub fn from_arg_buffer(
   generator_state: &mut GeneratorState,
   arg_ident: &Ident,
   buffer: &Buffer,
+  temp: &Ident,
 ) -> Result<TokenStream, V8MappingError> {
   let err = format_ident!("{}_err", arg_ident);
   let throw_exception = throw_type_error_static_string(generator_state, &err)?;
@@ -449,7 +470,7 @@ pub fn from_arg_buffer(
   };
 
   let make_v8slice = gs_quote!(generator_state(deno_core, scope) => {
-    let mut #arg_ident = match unsafe { #deno_core::_ops::#to_v8_slice::<#deno_core::v8::#array>(&mut #scope, #arg_ident) } {
+    #temp = match unsafe { #deno_core::_ops::#to_v8_slice::<#deno_core::v8::#array>(&mut #scope, #arg_ident) } {
       Ok(#arg_ident) => #arg_ident,
       Err(#err) => {
         #throw_exception
@@ -458,20 +479,23 @@ pub fn from_arg_buffer(
   });
 
   let make_arg = match buffer {
-    Buffer::Slice(_, NumericArg::u8) => {
-      quote!(let #arg_ident = &mut #arg_ident;)
+    Buffer::Slice(RefType::Ref, NumericArg::u8) => {
+      quote!(let #arg_ident = #temp.as_ref();)
+    }
+    Buffer::Slice(RefType::Mut, NumericArg::u8) => {
+      quote!(let #arg_ident = #temp.as_mut();)
     }
     Buffer::Vec(NumericArg::u8) => {
-      quote!(let #arg_ident = #arg_ident.to_vec();)
+      quote!(let #arg_ident = #temp.to_vec();)
     }
     Buffer::BoxSlice(NumericArg::u8) => {
-      quote!(let #arg_ident = #arg_ident.to_boxed_slice();)
+      quote!(let #arg_ident = #temp.to_boxed_slice();)
     }
     Buffer::Bytes(BufferMode::Copy) => {
-      quote!(let #arg_ident = #arg_ident.to_vec().into();)
+      quote!(let #arg_ident = #temp.to_vec().into();)
     }
     Buffer::JsBuffer(BufferMode::Default | BufferMode::Detach) => {
-      gs_quote!(generator_state(deno_core) => (let #arg_ident = #deno_core::serde_v8::JsBuffer::from_parts(#arg_ident);))
+      gs_quote!(generator_state(deno_core) => (let #arg_ident = #deno_core::serde_v8::JsBuffer::from_parts(#temp);))
     }
     _ => {
       return Err(V8MappingError::NoMapping(
@@ -702,7 +726,7 @@ fn throw_type_error_string(
     #maybe_scope
     // TODO(mmastrac): This might be allocating too much, even if it's on the error path
     let msg = #deno_core::v8::String::new(&mut #scope, &format!("{}", #deno_core::anyhow::Error::from(#message))).unwrap();
-    let exc = #deno_core::v8::Exception::error(&mut #scope, msg);
+    let exc = #deno_core::v8::Exception::type_error(&mut #scope, msg);
     #scope.throw_exception(exc);
     return;
   }))
@@ -722,7 +746,7 @@ fn throw_type_error_static_string(
   Ok(gs_quote!(generator_state(deno_core, scope) => {
     #maybe_scope
     let msg = #deno_core::v8::String::new_from_one_byte(&mut #scope, #message.as_bytes(), #deno_core::v8::NewStringType::Normal).unwrap();
-    let exc = #deno_core::v8::Exception::error(&mut #scope, msg);
+    let exc = #deno_core::v8::Exception::type_error(&mut #scope, msg);
     #scope.throw_exception(exc);
     return;
   }))
diff --git a/ops/op2/signature.rs b/ops/op2/signature.rs
index 443c70c..dfc2458 100644
--- a/ops/op2/signature.rs
+++ b/ops/op2/signature.rs
@@ -223,6 +223,7 @@ pub enum Arg {
   Option(Special),
   OptionString(Strings),
   OptionNumeric(NumericArg),
+  OptionBuffer(Buffer),
   OptionV8Local(V8Arg),
   OptionV8Global(V8Arg),
   V8Local(V8Arg),
@@ -296,6 +297,7 @@ impl Arg {
         | Arg::OptionNumeric(..)
         | Arg::Option(..)
         | Arg::OptionString(..)
+        | Arg::OptionBuffer(..)
         | Arg::OptionState(..)
     )
   }
@@ -309,6 +311,7 @@ impl Arg {
       Arg::OptionNumeric(t) => Arg::Numeric(*t),
       Arg::Option(t) => Arg::Special(*t),
       Arg::OptionString(t) => Arg::String(*t),
+      Arg::OptionBuffer(t) => Arg::Buffer(*t),
       Arg::OptionState(r, t) => Arg::State(*r, t.clone()),
       _ => return None,
     })
@@ -346,6 +349,12 @@ impl Arg {
           | Buffer::BoxSlice(NumericArg::u8)
           | Buffer::BytesMut(BufferMode::Default),
         ) => ArgSlowRetval::V8LocalFalliable,
+        Arg::OptionBuffer(
+          Buffer::JsBuffer(BufferMode::Default)
+          | Buffer::Vec(NumericArg::u8)
+          | Buffer::BoxSlice(NumericArg::u8)
+          | Buffer::BytesMut(BufferMode::Default),
+        ) => ArgSlowRetval::V8LocalFalliable,
         _ => ArgSlowRetval::None,
       }
     }
@@ -634,6 +643,8 @@ pub enum ArgError {
   InvalidType(String, &'static str),
   #[error("Invalid numeric argument type: {0}")]
   InvalidNumericType(String),
+  #[error("Invalid numeric #[smi] argument type: {0}")]
+  InvalidSmiType(String),
   #[error(
     "Invalid argument type path (should this be #[smi] or #[serde]?): {0}"
   )]
@@ -1159,7 +1170,8 @@ pub(crate) fn parse_type(
           let token = stringify_token(of.path.clone());
           if let Ok(Some(err)) = std::panic::catch_unwind(|| {
             rules!(ty => {
-              ( $( serde_v8:: )? Value $( < $_lifetime:lifetime >)? ) => Some("use v8::Value"),
+              ( serde_v8::Value $( < $_lifetime:lifetime >)? ) => Some("use v8::Value"),
+              ( Value $( < $_lifetime:lifetime >)? ) => Some("use a fully-qualified type: v8::Value or serde_json::Value"),
               ( $_ty:ty ) => None,
             })
           }) {
@@ -1181,9 +1193,20 @@ pub(crate) fn parse_type(
       | AttributeModifier::Global => {
         // We handle this as part of the normal parsing process
       }
-      AttributeModifier::Smi => {
-        return Ok(Arg::Numeric(NumericArg::__SMI__));
-      }
+      AttributeModifier::Smi => match ty {
+        Type::Path(of) => {
+          let is_option = rules!(of.into_token_stream() => {
+            ( Option < $_ty:ty > ) => true,
+            ( $_ty:ty ) => false,
+          });
+          if is_option {
+            return Ok(Arg::OptionNumeric(NumericArg::__SMI__));
+          } else {
+            return Ok(Arg::Numeric(NumericArg::__SMI__));
+          }
+        }
+        _ => return Err(ArgError::InvalidSmiType(stringify_token(ty))),
+      },
     }
   };
   match ty {
@@ -1262,6 +1285,7 @@ pub(crate) fn parse_type(
       COption(TNumeric(special)) => Ok(Arg::OptionNumeric(special)),
       COption(TSpecial(special)) => Ok(Arg::Option(special)),
       COption(TString(string)) => Ok(Arg::OptionString(string)),
+      COption(TBuffer(buffer)) => Ok(Arg::OptionBuffer(buffer)),
       CRcRefCell(TSpecial(special)) => Ok(Arg::RcRefCell(special)),
       COptionV8Local(TV8(v8)) => Ok(Arg::OptionV8Local(v8)),
       COptionV8Global(TV8(v8)) => Ok(Arg::OptionV8Global(v8)),
@@ -1427,6 +1451,10 @@ mod tests {
     fn op_option_numeric_result(state: &mut OpState) -> Result<Option<u32>, AnyError>;
     (Ref(Mut, OpState)) -> Result(OptionNumeric(u32))
   );
+  test!(
+    #[smi] fn op_option_numeric_smi_result(#[smi] a: Option<u32>) -> Result<Option<u32>, AnyError>;
+    (OptionNumeric(__SMI__)) -> Result(OptionNumeric(__SMI__))
+  );
   test!(
     fn op_ffi_read_f64(state: &mut OpState, ptr: *mut c_void, #[bigint] offset: isize) -> Result <f64, AnyError>;
     (Ref(Mut, OpState), External(Ptr(Mut)), Numeric(isize)) -> Result(Numeric(f64))
diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml
index 2de5482..6db3bd9 100644
--- a/serde_v8/Cargo.toml
+++ b/serde_v8/Cargo.toml
@@ -2,7 +2,7 @@
 
 [package]
 name = "serde_v8"
-version = "0.120.0"
+version = "0.121.0"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true


Test patch:
diff --git a/ops/op2/test_cases/async/async_jsbuffer.out b/ops/op2/test_cases/async/async_jsbuffer.out
index c5b664b..85b5473 100644
--- a/ops/op2/test_cases/async/async_jsbuffer.out
+++ b/ops/op2/test_cases/async/async_jsbuffer.out
@@ -36,7 +36,8 @@ impl op_async_v8_buffer {
         };
         let result = {
             let arg0 = args.get(1usize as i32);
-            let mut arg0 = match unsafe {
+            let mut arg0_temp;
+            arg0_temp = match unsafe {
                 deno_core::_ops::to_v8_slice::<
                     deno_core::v8::Uint8Array,
                 >(&mut scope, arg0)
@@ -50,12 +51,12 @@ impl op_async_v8_buffer {
                             deno_core::v8::NewStringType::Normal,
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
             };
-            let arg0 = deno_core::serde_v8::JsBuffer::from_parts(arg0);
+            let arg0 = deno_core::serde_v8::JsBuffer::from_parts(arg0_temp);
             Self::call(arg0)
         };
         let promise_id = deno_core::_ops::to_i32_option(&args.get(0))
@@ -77,7 +78,7 @@ impl op_async_v8_buffer {
                             &format!("{}", deno_core::anyhow::Error::from(rv_err)),
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
diff --git a/ops/op2/test_cases/sync/buffers.out b/ops/op2/test_cases/sync/buffers.out
index 2644caa..0e5d053 100644
--- a/ops/op2/test_cases/sync/buffers.out
+++ b/ops/op2/test_cases/sync/buffers.out
@@ -60,7 +60,8 @@ impl op_buffers {
         });
         let result = {
             let arg0 = args.get(0usize as i32);
-            let mut arg0 = match unsafe {
+            let mut arg0_temp;
+            arg0_temp = match unsafe {
                 deno_core::_ops::to_v8_slice::<
                     deno_core::v8::Uint8Array,
                 >(&mut scope, arg0)
@@ -74,14 +75,15 @@ impl op_buffers {
                             deno_core::v8::NewStringType::Normal,
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
             };
-            let arg0 = &mut arg0;
+            let arg0 = arg0_temp.as_ref();
             let arg1 = args.get(1usize as i32);
-            let mut arg1 = match unsafe {
+            let mut arg1_temp;
+            arg1_temp = match unsafe {
                 deno_core::_ops::to_v8_slice::<
                     deno_core::v8::Uint8Array,
                 >(&mut scope, arg1)
@@ -94,12 +96,12 @@ impl op_buffers {
                             deno_core::v8::NewStringType::Normal,
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
             };
-            let arg1 = &mut arg1;
+            let arg1 = arg1_temp.as_mut();
             Self::call(arg0, arg1)
         };
         deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
@@ -107,3 +109,99 @@ impl op_buffers {
     #[inline(always)]
     fn call(_a: &[u8], _b: &mut [u8]) {}
 }
+
+#[allow(non_camel_case_types)]
+struct op_buffers_option {
+    _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_buffers_option {
+    const NAME: &'static str = stringify!(op_buffers_option);
+    const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl::new_internal(
+        stringify!(op_buffers_option),
+        false,
+        false,
+        false,
+        2usize as u8,
+        Self::v8_fn_ptr as _,
+        None,
+    );
+}
+impl op_buffers_option {
+    pub const fn name() -> &'static str {
+        stringify!(op_buffers_option)
+    }
+    #[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 scope = unsafe { deno_core::v8::CallbackScope::new(&*info) };
+        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 result = {
+            let arg0 = args.get(0usize as i32);
+            let mut arg0_temp;
+            let arg0 = if arg0.is_null_or_undefined() {
+                None
+            } else {
+                arg0_temp = match unsafe {
+                    deno_core::_ops::to_v8_slice::<
+                        deno_core::v8::Uint8Array,
+                    >(&mut scope, arg0)
+                } {
+                    Ok(arg0) => arg0,
+                    Err(arg0_err) => {
+                        let mut scope = unsafe {
+                            deno_core::v8::CallbackScope::new(&*info)
+                        };
+                        let msg = deno_core::v8::String::new_from_one_byte(
+                                &mut scope,
+                                arg0_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 arg0 = arg0_temp.as_ref();
+                Some(arg0)
+            };
+            let arg1 = args.get(1usize as i32);
+            let mut arg1_temp;
+            let arg1 = if arg1.is_null_or_undefined() {
+                None
+            } else {
+                arg1_temp = match unsafe {
+                    deno_core::_ops::to_v8_slice::<
+                        deno_core::v8::Uint8Array,
+                    >(&mut scope, arg1)
+                } {
+                    Ok(arg1) => arg1,
+                    Err(arg1_err) => {
+                        let msg = deno_core::v8::String::new_from_one_byte(
+                                &mut scope,
+                                arg1_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 arg1 = deno_core::serde_v8::JsBuffer::from_parts(arg1_temp);
+                Some(arg1)
+            };
+            Self::call(arg0, arg1)
+        };
+        deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
+    }
+    #[inline(always)]
+    fn call(_a: Option<&[u8]>, _b: Option<JsBuffer>) {}
+}
diff --git a/ops/op2/test_cases/sync/buffers.rs b/ops/op2/test_cases/sync/buffers.rs
index ee56204..b46cbbc 100644
--- a/ops/op2/test_cases/sync/buffers.rs
+++ b/ops/op2/test_cases/sync/buffers.rs
@@ -2,6 +2,12 @@
 #![deny(warnings)]
 deno_ops_compile_test_runner::prelude!();
 
+use deno_core::JsBuffer;
+
 #[op2(fast)]
 fn op_buffers(#[buffer] _a: &[u8], #[buffer] _b: &mut [u8]) {
 }
+
+#[op2]
+fn op_buffers_option(#[buffer] _a: Option<&[u8]>, #[buffer] _b: Option<JsBuffer>) {
+}
diff --git a/ops/op2/test_cases/sync/buffers_copy.out b/ops/op2/test_cases/sync/buffers_copy.out
index 8c4a947..e1a27fa 100644
--- a/ops/op2/test_cases/sync/buffers_copy.out
+++ b/ops/op2/test_cases/sync/buffers_copy.out
@@ -70,7 +70,8 @@ impl op_buffers {
         });
         let result = {
             let arg0 = args.get(0usize as i32);
-            let mut arg0 = match unsafe {
+            let mut arg0_temp;
+            arg0_temp = match unsafe {
                 deno_core::_ops::to_v8_slice::<
                     deno_core::v8::Uint8Array,
                 >(&mut scope, arg0)
@@ -84,14 +85,15 @@ impl op_buffers {
                             deno_core::v8::NewStringType::Normal,
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
             };
-            let arg0 = arg0.to_vec();
+            let arg0 = arg0_temp.to_vec();
             let arg1 = args.get(1usize as i32);
-            let mut arg1 = match unsafe {
+            let mut arg1_temp;
+            arg1_temp = match unsafe {
                 deno_core::_ops::to_v8_slice::<
                     deno_core::v8::Uint8Array,
                 >(&mut scope, arg1)
@@ -104,14 +106,15 @@ impl op_buffers {
                             deno_core::v8::NewStringType::Normal,
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
             };
-            let arg1 = arg1.to_boxed_slice();
+            let arg1 = arg1_temp.to_boxed_slice();
             let arg2 = args.get(2usize as i32);
-            let mut arg2 = match unsafe {
+            let mut arg2_temp;
+            arg2_temp = match unsafe {
                 deno_core::_ops::to_v8_slice::<
                     deno_core::v8::Uint8Array,
                 >(&mut scope, arg2)
@@ -124,12 +127,12 @@ impl op_buffers {
                             deno_core::v8::NewStringType::Normal,
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
             };
-            let arg2 = arg2.to_vec().into();
+            let arg2 = arg2_temp.to_vec().into();
             Self::call(arg0, arg1, arg2)
         };
         deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
diff --git a/ops/op2/test_cases/sync/serde_v8.out b/ops/op2/test_cases/sync/serde_v8.out
index 1a3adf9..b96e0e4 100644
--- a/ops/op2/test_cases/sync/serde_v8.out
+++ b/ops/op2/test_cases/sync/serde_v8.out
@@ -40,7 +40,7 @@ impl op_serde_v8 {
                             &format!("{}", deno_core::anyhow::Error::from(arg0_err)),
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
@@ -61,7 +61,7 @@ impl op_serde_v8 {
                         &format!("{}", deno_core::anyhow::Error::from(rv_err)),
                     )
                     .unwrap();
-                let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                 scope.throw_exception(exc);
                 return;
             }
diff --git a/ops/op2/test_cases/sync/smi.out b/ops/op2/test_cases/sync/smi.out
index 0c0dca1..339b773 100644
--- a/ops/op2/test_cases/sync/smi.out
+++ b/ops/op2/test_cases/sync/smi.out
@@ -253,3 +253,64 @@ impl op_smi_signed_return {
         a as Int32 + b as Int32 + c as Int32 + d as Int32
     }
 }
+
+#[allow(non_camel_case_types)]
+struct op_smi_option {
+    _unconstructable: ::std::marker::PhantomData<()>,
+}
+impl deno_core::_ops::Op for op_smi_option {
+    const NAME: &'static str = stringify!(op_smi_option);
+    const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl::new_internal(
+        stringify!(op_smi_option),
+        false,
+        false,
+        false,
+        1usize as u8,
+        Self::v8_fn_ptr as _,
+        None,
+    );
+}
+impl op_smi_option {
+    pub const fn name() -> &'static str {
+        stringify!(op_smi_option)
+    }
+    #[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 result = {
+            let arg0 = args.get(0usize as i32);
+            let arg0 = if arg0.is_null_or_undefined() {
+                None
+            } else {
+                let Some(arg0) = deno_core::_ops::to_i32_option(&arg0) else {
+                    let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*info) };
+                    let msg = deno_core::v8::String::new_from_one_byte(
+                            &mut scope,
+                            "expected i32".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 arg0 = arg0 as _;
+                Some(arg0)
+            };
+            Self::call(arg0)
+        };
+        deno_core::_ops::RustToV8RetVal::to_v8_rv(result, &mut rv)
+    }
+    #[inline(always)]
+    fn call(a: Option<Uint32>) -> Option<Uint32> {
+        a
+    }
+}
diff --git a/ops/op2/test_cases/sync/smi.rs b/ops/op2/test_cases/sync/smi.rs
index f25af80..d2c79c2 100644
--- a/ops/op2/test_cases/sync/smi.rs
+++ b/ops/op2/test_cases/sync/smi.rs
@@ -18,3 +18,9 @@ fn op_smi_unsigned_return(#[smi] a: Int16, #[smi] b: Int32, #[smi] c: Uint16, #[
 fn op_smi_signed_return(#[smi] a: Int16, #[smi] b: Int32, #[smi] c: Uint16, #[smi] d: Uint32) -> Int32 {
   a as Int32 + b as Int32 + c as Int32 + d as Int32
 }
+
+#[op2]
+#[smi]
+fn op_smi_option(#[smi] a: Option<Uint32>) -> Option<Uint32> {
+  a
+}
diff --git a/ops/op2/test_cases/sync/string_onebyte.out b/ops/op2/test_cases/sync/string_onebyte.out
index 71d04d0..7c00236 100644
--- a/ops/op2/test_cases/sync/string_onebyte.out
+++ b/ops/op2/test_cases/sync/string_onebyte.out
@@ -64,7 +64,7 @@ impl op_string_onebyte {
                             deno_core::v8::NewStringType::Normal,
                         )
                         .unwrap();
-                    let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                    let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                     scope.throw_exception(exc);
                     return;
                 }
diff --git a/ops/op2/test_cases/sync/string_option_return.out b/ops/op2/test_cases/sync/string_option_return.out
index 1dc204d..f69234a 100644
--- a/ops/op2/test_cases/sync/string_option_return.out
+++ b/ops/op2/test_cases/sync/string_option_return.out
@@ -47,7 +47,7 @@ impl op_string_return {
                         &format!("{}", deno_core::anyhow::Error::from(rv_err)),
                     )
                     .unwrap();
-                let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                 scope.throw_exception(exc);
                 return;
             }
diff --git a/ops/op2/test_cases/sync/string_return.out b/ops/op2/test_cases/sync/string_return.out
index 58995a4..40d3564 100644
--- a/ops/op2/test_cases/sync/string_return.out
+++ b/ops/op2/test_cases/sync/string_return.out
@@ -36,7 +36,7 @@ impl op_string_return {
                         &format!("{}", deno_core::anyhow::Error::from(rv_err)),
                     )
                     .unwrap();
-                let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                 scope.throw_exception(exc);
                 return;
             }
@@ -86,7 +86,7 @@ impl op_string_return_ref {
                         &format!("{}", deno_core::anyhow::Error::from(rv_err)),
                     )
                     .unwrap();
-                let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                 scope.throw_exception(exc);
                 return;
             }
@@ -136,7 +136,7 @@ impl op_string_return_cow {
                         &format!("{}", deno_core::anyhow::Error::from(rv_err)),
                     )
                     .unwrap();
-                let exc = deno_core::v8::Exception::error(&mut scope, msg);
+                let exc = deno_core::v8::Exception::type_error(&mut scope, msg);
                 scope.throw_exception(exc);
                 return;
             }