Skip to content

Commit

Permalink
feat(ops): allow JsBuffer arguments to be fast (denoland#254)
Browse files Browse the repository at this point in the history
  • Loading branch information
mmastrac authored Oct 17, 2023
1 parent 08ed2d0 commit 134ebaa
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 95 deletions.
19 changes: 5 additions & 14 deletions core/runtime/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,6 @@ pub fn serde_v8_to_rust<'a, T: Deserialize<'a>>(

/// Retrieve a [`serde_v8::V8Slice`] from a typed array in an [`v8::ArrayBufferView`].
pub fn to_v8_slice<'a, T>(
scope: &mut v8::HandleScope,
input: v8::Local<'a, v8::Value>,
) -> Result<serde_v8::V8Slice<T>, &'static str>
where
Expand All @@ -580,14 +579,10 @@ where
let (store, offset, length) =
if let Ok(buf) = v8::Local::<T::V8>::try_from(input) {
let buf: v8::Local<v8::ArrayBufferView> = buf.into();
let Some(buffer) = buf.buffer(scope) else {
let Some(buffer) = buf.get_backing_store() else {
return Err("buffer missing");
};
(
buffer.get_backing_store(),
buf.byte_offset(),
buf.byte_length(),
)
(buffer, buf.byte_offset(), buf.byte_length())
} else {
return Err("expected typed ArrayBufferView");
};
Expand Down Expand Up @@ -719,20 +714,16 @@ pub fn to_v8_slice_buffer_detachable(

/// Retrieve a [`serde_v8::V8Slice`] from a [`v8::ArrayBuffer`].
pub fn to_v8_slice_any(
scope: &mut v8::HandleScope,
input: v8::Local<v8::Value>,
) -> Result<serde_v8::V8Slice<u8>, &'static str> {
if let Ok(buf) = v8::Local::<v8::ArrayBufferView>::try_from(input) {
let offset = buf.byte_offset();
let len = buf.byte_length();
let Some(buf) = buf.buffer(scope) else {
let Some(buf) = buf.get_backing_store() else {
return Err("buffer missing");
};
return Ok(unsafe {
serde_v8::V8Slice::<u8>::from_parts(
buf.get_backing_store(),
offset..offset + len,
)
serde_v8::V8Slice::<u8>::from_parts(buf, offset..offset + len)
});
}
if let Ok(buf) = to_v8_slice_buffer(input) {
Expand Down Expand Up @@ -1795,7 +1786,7 @@ mod tests {
Ok(())
}

#[op2(core)]
#[op2(core, fast)]
pub fn op_buffer_jsbuffer(
#[buffer] input: JsBuffer,
#[number] inlen: usize,
Expand Down
6 changes: 3 additions & 3 deletions ops/op2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -849,9 +849,9 @@ Safe, but forces a copy.
```

</td><td>

</td><td>
ArrayBuffer, ArrayBufferView (resizable=false)
ArrayBufferView (resizable=false)
</td><td>
⚠️ JS may modify the contents of slices obtained from buffer.
</td></tr>
Expand All @@ -865,7 +865,7 @@ ArrayBuffer, ArrayBufferView (resizable=false)
</td><td>

</td><td>
ArrayBuffer, ArrayBufferView (resizable=true,false)
ArrayBufferView (resizable=true,false)
</td><td>
Safe.
</td></tr>
Expand Down
18 changes: 17 additions & 1 deletion ops/op2/dispatch_fast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,22 @@ fn map_v8_fastcall_arg_to_arg(
#buf
)
}
Arg::Buffer(
buffer @ (BufferType::V8Slice(..) | BufferType::JsBuffer),
_,
BufferSource::TypedArray,
) => {
*needs_fast_api_callback_options = true;
let buf = v8slice_to_buffer(deno_core, arg_ident, &arg_temp, *buffer)?;
quote!(
let Ok(mut #arg_temp) = #deno_core::_ops::to_v8_slice(#arg_ident.into()) else {
#fast_api_callback_options.fallback = true;
// SAFETY: All fast return types have zero as a valid value
return unsafe { std::mem::zeroed() };
};
#buf
)
}
Arg::Buffer(buffer, _, BufferSource::ArrayBuffer) => {
*needs_fast_api_callback_options = true;
let buf = byte_slice_to_buffer(arg_ident, &arg_temp, *buffer)?;
Expand Down Expand Up @@ -549,7 +565,7 @@ fn map_arg_to_v8_fastcall_type(
BufferType::JsBuffer | BufferType::V8Slice(..),
_,
BufferSource::TypedArray,
) => return Ok(None),
) => V8FastCallType::V8Value,
Arg::Buffer(
BufferType::Slice(.., NumericArg::u8)
| BufferType::Ptr(.., NumericArg::u8),
Expand Down
19 changes: 8 additions & 11 deletions ops/op2/dispatch_slow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,22 +561,22 @@ pub fn from_arg_buffer(
let throw_exception = throw_type_error_static_string(generator_state, &err)?;

let array = buffer_type.element();
generator_state.needs_scope = true;

let to_v8_slice = if matches!(buffer_mode, BufferMode::Detach) {
quote!(to_v8_slice_detachable)
generator_state.needs_scope = true;
gs_quote!(generator_state(deno_core, scope) => { #deno_core::_ops::to_v8_slice_detachable::<#array>(&mut #scope, #arg_ident) })
} else {
quote!(to_v8_slice)
gs_quote!(generator_state(deno_core) => { #deno_core::_ops::to_v8_slice::<#array>(#arg_ident) })
};

let make_v8slice = gs_quote!(generator_state(deno_core, scope) => {
#temp = match unsafe { #deno_core::_ops::#to_v8_slice::<#array>(&mut #scope, #arg_ident) } {
let make_v8slice = quote!(
#temp = match unsafe { #to_v8_slice } {
Ok(#arg_ident) => #arg_ident,
Err(#err) => {
#throw_exception
}
};
});
);

let make_arg = v8slice_to_buffer(
&generator_state.deno_core,
Expand Down Expand Up @@ -645,11 +645,8 @@ pub fn from_arg_any_buffer(
quote!(to_v8_slice_any)
};

// TODO(mmastrac): upstream change required to avoid scope
generator_state.needs_scope = true;

let make_v8slice = gs_quote!(generator_state(deno_core, scope) => {
#temp = match unsafe { #deno_core::_ops::#to_v8_slice(&mut #scope, #arg_ident) } {
let make_v8slice = gs_quote!(generator_state(deno_core) => {
#temp = match unsafe { #deno_core::_ops::#to_v8_slice(#arg_ident) } {
Ok(#arg_ident) => #arg_ident,
Err(#err) => {
#throw_exception
Expand Down
4 changes: 1 addition & 3 deletions ops/op2/test_cases/async/async_jsbuffer.out

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 19 additions & 33 deletions ops/op2/test_cases/sync/buffers.out

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 134ebaa

Please sign in to comment.