mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 00:29:09 -05:00
perf(ops): inline &[u8] arguments and enable fast API (#15731)
This commit is contained in:
parent
d57f9d560d
commit
027d4d433d
8 changed files with 128 additions and 60 deletions
|
@ -134,12 +134,12 @@ impl Resource for WasmStreamingResource {
|
||||||
pub fn op_wasm_streaming_feed(
|
pub fn op_wasm_streaming_feed(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
rid: ResourceId,
|
rid: ResourceId,
|
||||||
bytes: ZeroCopyBuf,
|
bytes: &[u8],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let wasm_streaming =
|
let wasm_streaming =
|
||||||
state.resource_table.get::<WasmStreamingResource>(rid)?;
|
state.resource_table.get::<WasmStreamingResource>(rid)?;
|
||||||
|
|
||||||
wasm_streaming.0.borrow_mut().on_bytes_received(&bytes);
|
wasm_streaming.0.borrow_mut().on_bytes_received(bytes);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ fn op_encode<'a>(
|
||||||
#[op(v8)]
|
#[op(v8)]
|
||||||
fn op_decode<'a>(
|
fn op_decode<'a>(
|
||||||
scope: &mut v8::HandleScope<'a>,
|
scope: &mut v8::HandleScope<'a>,
|
||||||
zero_copy: ZeroCopyBuf,
|
zero_copy: &[u8],
|
||||||
) -> Result<serde_v8::Value<'a>, Error> {
|
) -> Result<serde_v8::Value<'a>, Error> {
|
||||||
let buf = &zero_copy;
|
let buf = &zero_copy;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ use deno_core::Extension;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
use deno_core::ResourceId;
|
use deno_core::ResourceId;
|
||||||
use deno_core::ZeroCopyBuf;
|
|
||||||
use dlopen::raw::Library;
|
use dlopen::raw::Library;
|
||||||
use libffi::middle::Arg;
|
use libffi::middle::Arg;
|
||||||
use libffi::middle::Cif;
|
use libffi::middle::Cif;
|
||||||
|
@ -2154,7 +2153,7 @@ where
|
||||||
fn op_ffi_buf_copy_into<FP>(
|
fn op_ffi_buf_copy_into<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
src: usize,
|
src: usize,
|
||||||
mut dst: ZeroCopyBuf,
|
dst: &mut [u8],
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<(), AnyError>
|
) -> Result<(), AnyError>
|
||||||
where
|
where
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
MapPrototypeGet,
|
MapPrototypeGet,
|
||||||
MapPrototypeHas,
|
MapPrototypeHas,
|
||||||
MapPrototypeSet,
|
MapPrototypeSet,
|
||||||
|
Uint8Array,
|
||||||
Uint32Array,
|
Uint32Array,
|
||||||
// deno-lint-ignore camelcase
|
// deno-lint-ignore camelcase
|
||||||
NumberPOSITIVE_INFINITY,
|
NumberPOSITIVE_INFINITY,
|
||||||
|
@ -27,13 +28,10 @@
|
||||||
const { reportException } = window.__bootstrap.event;
|
const { reportException } = window.__bootstrap.event;
|
||||||
const { assert } = window.__bootstrap.infra;
|
const { assert } = window.__bootstrap.infra;
|
||||||
|
|
||||||
let hr;
|
const hrU8 = new Uint8Array(8);
|
||||||
|
const hr = new Uint32Array(hrU8.buffer);
|
||||||
function opNow() {
|
function opNow() {
|
||||||
if (!hr) {
|
ops.op_now.fast(hrU8);
|
||||||
hr = new Uint32Array(2);
|
|
||||||
ops.op_now_set_buf(hr);
|
|
||||||
}
|
|
||||||
ops.op_now.fast();
|
|
||||||
return (hr[0] * 1000 + hr[1] / 1e6);
|
return (hr[0] * 1000 + hr[1] / 1e6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,38 +68,38 @@ pub fn op_compression_new(
|
||||||
pub fn op_compression_write(
|
pub fn op_compression_write(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
rid: ResourceId,
|
rid: ResourceId,
|
||||||
input: ZeroCopyBuf,
|
input: &[u8],
|
||||||
) -> Result<ZeroCopyBuf, AnyError> {
|
) -> Result<ZeroCopyBuf, AnyError> {
|
||||||
let resource = state.resource_table.get::<CompressionResource>(rid)?;
|
let resource = state.resource_table.get::<CompressionResource>(rid)?;
|
||||||
let mut inner = resource.0.borrow_mut();
|
let mut inner = resource.0.borrow_mut();
|
||||||
let out: Vec<u8> = match &mut *inner {
|
let out: Vec<u8> = match &mut *inner {
|
||||||
Inner::DeflateDecoder(d) => {
|
Inner::DeflateDecoder(d) => {
|
||||||
d.write_all(&input)?;
|
d.write_all(input)?;
|
||||||
d.flush()?;
|
d.flush()?;
|
||||||
d.get_mut().drain(..)
|
d.get_mut().drain(..)
|
||||||
}
|
}
|
||||||
Inner::DeflateEncoder(d) => {
|
Inner::DeflateEncoder(d) => {
|
||||||
d.write_all(&input)?;
|
d.write_all(input)?;
|
||||||
d.flush()?;
|
d.flush()?;
|
||||||
d.get_mut().drain(..)
|
d.get_mut().drain(..)
|
||||||
}
|
}
|
||||||
Inner::DeflateRawDecoder(d) => {
|
Inner::DeflateRawDecoder(d) => {
|
||||||
d.write_all(&input)?;
|
d.write_all(input)?;
|
||||||
d.flush()?;
|
d.flush()?;
|
||||||
d.get_mut().drain(..)
|
d.get_mut().drain(..)
|
||||||
}
|
}
|
||||||
Inner::DeflateRawEncoder(d) => {
|
Inner::DeflateRawEncoder(d) => {
|
||||||
d.write_all(&input)?;
|
d.write_all(input)?;
|
||||||
d.flush()?;
|
d.flush()?;
|
||||||
d.get_mut().drain(..)
|
d.get_mut().drain(..)
|
||||||
}
|
}
|
||||||
Inner::GzDecoder(d) => {
|
Inner::GzDecoder(d) => {
|
||||||
d.write_all(&input)?;
|
d.write_all(input)?;
|
||||||
d.flush()?;
|
d.flush()?;
|
||||||
d.get_mut().drain(..)
|
d.get_mut().drain(..)
|
||||||
}
|
}
|
||||||
Inner::GzEncoder(d) => {
|
Inner::GzEncoder(d) => {
|
||||||
d.write_all(&input)?;
|
d.write_all(input)?;
|
||||||
d.flush()?;
|
d.flush()?;
|
||||||
d.get_mut().drain(..)
|
d.get_mut().drain(..)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@ pub use crate::message_port::JsMessageData;
|
||||||
pub use crate::message_port::MessagePort;
|
pub use crate::message_port::MessagePort;
|
||||||
|
|
||||||
use crate::timers::op_now;
|
use crate::timers::op_now;
|
||||||
use crate::timers::op_now_set_buf;
|
|
||||||
use crate::timers::op_sleep;
|
use crate::timers::op_sleep;
|
||||||
use crate::timers::op_timer_handle;
|
use crate::timers::op_timer_handle;
|
||||||
use crate::timers::StartTime;
|
use crate::timers::StartTime;
|
||||||
|
@ -106,7 +105,6 @@ pub fn init<P: TimersPermission + 'static>(
|
||||||
compression::op_compression_new::decl(),
|
compression::op_compression_new::decl(),
|
||||||
compression::op_compression_write::decl(),
|
compression::op_compression_write::decl(),
|
||||||
compression::op_compression_finish::decl(),
|
compression::op_compression_finish::decl(),
|
||||||
op_now_set_buf::decl(),
|
|
||||||
op_now::decl::<P>(),
|
op_now::decl::<P>(),
|
||||||
op_timer_handle::decl(),
|
op_timer_handle::decl(),
|
||||||
op_cancel_handle::decl(),
|
op_cancel_handle::decl(),
|
||||||
|
@ -149,8 +147,8 @@ fn forgiving_base64_decode(input: &mut [u8]) -> Result<usize, AnyError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_base64_encode(s: ZeroCopyBuf) -> String {
|
fn op_base64_encode(s: &[u8]) -> String {
|
||||||
forgiving_base64_encode(s.as_ref())
|
forgiving_base64_encode(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
|
@ -179,7 +177,7 @@ fn op_encoding_normalize_label(label: String) -> Result<String, AnyError> {
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
fn op_encoding_decode_single(
|
fn op_encoding_decode_single(
|
||||||
data: ZeroCopyBuf,
|
data: &[u8],
|
||||||
label: String,
|
label: String,
|
||||||
fatal: bool,
|
fatal: bool,
|
||||||
ignore_bom: bool,
|
ignore_bom: bool,
|
||||||
|
@ -205,7 +203,7 @@ fn op_encoding_decode_single(
|
||||||
|
|
||||||
if fatal {
|
if fatal {
|
||||||
let (result, _, written) =
|
let (result, _, written) =
|
||||||
decoder.decode_to_utf16_without_replacement(&data, &mut output, true);
|
decoder.decode_to_utf16_without_replacement(data, &mut output, true);
|
||||||
match result {
|
match result {
|
||||||
DecoderResult::InputEmpty => {
|
DecoderResult::InputEmpty => {
|
||||||
output.truncate(written);
|
output.truncate(written);
|
||||||
|
@ -220,7 +218,7 @@ fn op_encoding_decode_single(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (result, _, written, _) =
|
let (result, _, written, _) =
|
||||||
decoder.decode_to_utf16(&data, &mut output, true);
|
decoder.decode_to_utf16(data, &mut output, true);
|
||||||
match result {
|
match result {
|
||||||
CoderResult::InputEmpty => {
|
CoderResult::InputEmpty => {
|
||||||
output.truncate(written);
|
output.truncate(written);
|
||||||
|
@ -262,7 +260,7 @@ fn op_encoding_new_decoder(
|
||||||
#[op]
|
#[op]
|
||||||
fn op_encoding_decode(
|
fn op_encoding_decode(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
data: ZeroCopyBuf,
|
data: &[u8],
|
||||||
rid: ResourceId,
|
rid: ResourceId,
|
||||||
stream: bool,
|
stream: bool,
|
||||||
) -> Result<U16String, AnyError> {
|
) -> Result<U16String, AnyError> {
|
||||||
|
@ -279,7 +277,7 @@ fn op_encoding_decode(
|
||||||
|
|
||||||
if fatal {
|
if fatal {
|
||||||
let (result, _, written) =
|
let (result, _, written) =
|
||||||
decoder.decode_to_utf16_without_replacement(&data, &mut output, !stream);
|
decoder.decode_to_utf16_without_replacement(data, &mut output, !stream);
|
||||||
match result {
|
match result {
|
||||||
DecoderResult::InputEmpty => {
|
DecoderResult::InputEmpty => {
|
||||||
output.truncate(written);
|
output.truncate(written);
|
||||||
|
@ -294,7 +292,7 @@ fn op_encoding_decode(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (result, _, written, _) =
|
let (result, _, written, _) =
|
||||||
decoder.decode_to_utf16(&data, &mut output, !stream);
|
decoder.decode_to_utf16(data, &mut output, !stream);
|
||||||
match result {
|
match result {
|
||||||
CoderResult::InputEmpty => {
|
CoderResult::InputEmpty => {
|
||||||
output.truncate(written);
|
output.truncate(written);
|
||||||
|
@ -326,7 +324,7 @@ struct EncodeIntoResult {
|
||||||
#[op]
|
#[op]
|
||||||
fn op_encoding_encode_into(
|
fn op_encoding_encode_into(
|
||||||
input: String,
|
input: String,
|
||||||
mut buffer: ZeroCopyBuf,
|
buffer: &mut [u8],
|
||||||
) -> EncodeIntoResult {
|
) -> EncodeIntoResult {
|
||||||
// Since `input` is already UTF-8, we can simply find the last UTF-8 code
|
// Since `input` is already UTF-8, we can simply find the last UTF-8 code
|
||||||
// point boundary from input that fits in `buffer`, and copy the bytes up to
|
// point boundary from input that fits in `buffer`, and copy the bytes up to
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::op;
|
use deno_core::op;
|
||||||
use deno_core::ZeroCopyBuf;
|
|
||||||
|
|
||||||
use deno_core::CancelFuture;
|
use deno_core::CancelFuture;
|
||||||
use deno_core::CancelHandle;
|
use deno_core::CancelHandle;
|
||||||
|
@ -24,24 +23,12 @@ pub trait TimersPermission {
|
||||||
|
|
||||||
pub type StartTime = Instant;
|
pub type StartTime = Instant;
|
||||||
|
|
||||||
static mut NOW_BUF: *mut u32 = std::ptr::null_mut();
|
|
||||||
|
|
||||||
#[op]
|
|
||||||
pub fn op_now_set_buf(buf: ZeroCopyBuf) {
|
|
||||||
assert_eq!(buf.len(), 8);
|
|
||||||
// SAFETY: This is safe because this is the only place where we initialize
|
|
||||||
// NOW_BUF.
|
|
||||||
unsafe {
|
|
||||||
NOW_BUF = buf.as_ptr() as *mut u32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a milliseconds and nanoseconds subsec
|
// Returns a milliseconds and nanoseconds subsec
|
||||||
// since the start time of the deno runtime.
|
// since the start time of the deno runtime.
|
||||||
// If the High precision flag is not set, the
|
// If the High precision flag is not set, the
|
||||||
// nanoseconds are rounded on 2ms.
|
// nanoseconds are rounded on 2ms.
|
||||||
#[op(fast)]
|
#[op(fast)]
|
||||||
pub fn op_now<TP>(state: &mut OpState)
|
pub fn op_now<TP>(state: &mut OpState, buf: &mut [u8])
|
||||||
where
|
where
|
||||||
TP: TimersPermission + 'static,
|
TP: TimersPermission + 'static,
|
||||||
{
|
{
|
||||||
|
@ -57,18 +44,15 @@ where
|
||||||
let reduced_time_precision = 2_000_000; // 2ms in nanoseconds
|
let reduced_time_precision = 2_000_000; // 2ms in nanoseconds
|
||||||
subsec_nanos -= subsec_nanos % reduced_time_precision;
|
subsec_nanos -= subsec_nanos % reduced_time_precision;
|
||||||
}
|
}
|
||||||
|
if buf.len() < 8 {
|
||||||
// SAFETY: This is safe because we initialize NOW_BUF in op_now_set_buf, its a null pointer
|
return;
|
||||||
// otherwise.
|
}
|
||||||
// op_now_set_buf guarantees that the buffer is 8 bytes long.
|
let buf: &mut [u32] =
|
||||||
unsafe {
|
// SAFETY: buffer is at least 8 bytes long.
|
||||||
if !NOW_BUF.is_null() {
|
unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as _, 2) };
|
||||||
let buf = std::slice::from_raw_parts_mut(NOW_BUF, 2);
|
|
||||||
buf[0] = seconds as u32;
|
buf[0] = seconds as u32;
|
||||||
buf[1] = subsec_nanos as u32;
|
buf[1] = subsec_nanos as u32;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TimerHandle(Rc<CancelHandle>);
|
pub struct TimerHandle(Rc<CancelHandle>);
|
||||||
|
|
||||||
|
|
99
ops/lib.rs
99
ops/lib.rs
|
@ -11,6 +11,7 @@ use quote::format_ident;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::collections::HashMap;
|
||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
use syn::token::Comma;
|
use syn::token::Comma;
|
||||||
use syn::FnArg;
|
use syn::FnArg;
|
||||||
|
@ -310,10 +311,11 @@ fn codegen_fast_impl(
|
||||||
use_recv,
|
use_recv,
|
||||||
use_fast_cb_opts,
|
use_fast_cb_opts,
|
||||||
v8_values,
|
v8_values,
|
||||||
|
slices,
|
||||||
}) = fast_info
|
}) = fast_info
|
||||||
{
|
{
|
||||||
let offset = if use_recv { 1 } else { 0 };
|
let offset = if use_recv { 1 } else { 0 };
|
||||||
let inputs = &f
|
let mut inputs = f
|
||||||
.sig
|
.sig
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -327,8 +329,11 @@ fn codegen_fast_impl(
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if use_fast_cb_opts && idx == f.sig.inputs.len() - 1 {
|
if let Some(ty) = slices.get(&(idx + offset)) {
|
||||||
return quote! { #ident: *mut #core::v8::fast_api::FastApiCallbackOptions };
|
return quote! { #ident: *const #core::v8::fast_api::FastApiTypedArray< #ty > };
|
||||||
|
}
|
||||||
|
if use_fast_cb_opts && idx + offset == f.sig.inputs.len() - 1 {
|
||||||
|
return quote! { fast_api_callback_options: *mut #core::v8::fast_api::FastApiCallbackOptions };
|
||||||
}
|
}
|
||||||
if v8_values.contains(&idx) {
|
if v8_values.contains(&idx) {
|
||||||
return quote! { #ident: #core::v8::Local < #core::v8::Value > };
|
return quote! { #ident: #core::v8::Local < #core::v8::Value > };
|
||||||
|
@ -336,6 +341,9 @@ fn codegen_fast_impl(
|
||||||
quote!(#arg)
|
quote!(#arg)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
if !slices.is_empty() && !use_fast_cb_opts {
|
||||||
|
inputs.push(quote! { fast_api_callback_options: *mut #core::v8::fast_api::FastApiCallbackOptions });
|
||||||
|
}
|
||||||
let input_idents = f
|
let input_idents = f
|
||||||
.sig
|
.sig
|
||||||
.inputs
|
.inputs
|
||||||
|
@ -349,8 +357,19 @@ fn codegen_fast_impl(
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
if slices.get(&idx).is_some() {
|
||||||
|
return quote! {
|
||||||
|
match unsafe { &* #ident }.get_storage_if_aligned() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => {
|
||||||
|
unsafe { &mut * fast_api_callback_options }.fallback = true;
|
||||||
|
return Default::default();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
if use_fast_cb_opts && idx == f.sig.inputs.len() - 1 {
|
if use_fast_cb_opts && idx == f.sig.inputs.len() - 1 {
|
||||||
return quote! { Some(unsafe { &mut * #ident }) };
|
return quote! { Some(unsafe { &mut * fast_api_callback_options }) };
|
||||||
}
|
}
|
||||||
if v8_values.contains(&idx) {
|
if v8_values.contains(&idx) {
|
||||||
return quote! {
|
return quote! {
|
||||||
|
@ -494,6 +513,7 @@ struct FastApiSyn {
|
||||||
use_recv: bool,
|
use_recv: bool,
|
||||||
use_fast_cb_opts: bool,
|
use_fast_cb_opts: bool,
|
||||||
v8_values: Vec<usize>,
|
v8_values: Vec<usize>,
|
||||||
|
slices: HashMap<usize, TokenStream2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_be_fast_api(core: &TokenStream2, f: &syn::ItemFn) -> Option<FastApiSyn> {
|
fn can_be_fast_api(core: &TokenStream2, f: &syn::ItemFn) -> Option<FastApiSyn> {
|
||||||
|
@ -509,11 +529,12 @@ fn can_be_fast_api(core: &TokenStream2, f: &syn::ItemFn) -> Option<FastApiSyn> {
|
||||||
let mut use_recv = false;
|
let mut use_recv = false;
|
||||||
let mut use_fast_cb_opts = false;
|
let mut use_fast_cb_opts = false;
|
||||||
let mut v8_values = Vec::new();
|
let mut v8_values = Vec::new();
|
||||||
|
let mut slices = HashMap::new();
|
||||||
let mut args = vec![quote! { #core::v8::fast_api::Type::V8Value }];
|
let mut args = vec![quote! { #core::v8::fast_api::Type::V8Value }];
|
||||||
for (pos, input) in inputs.iter().enumerate() {
|
for (pos, input) in inputs.iter().enumerate() {
|
||||||
if pos == inputs.len() - 1 && is_optional_fast_callback_option(input) {
|
if pos == inputs.len() - 1 && is_optional_fast_callback_option(input) {
|
||||||
args.push(quote! { #core::v8::fast_api::Type::CallbackOptions });
|
|
||||||
use_fast_cb_opts = true;
|
use_fast_cb_opts = true;
|
||||||
|
args.push(quote! { #core::v8::fast_api::Type::CallbackOptions });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,9 +557,15 @@ fn can_be_fast_api(core: &TokenStream2, f: &syn::ItemFn) -> Option<FastApiSyn> {
|
||||||
Some(arg) => {
|
Some(arg) => {
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
}
|
}
|
||||||
|
None => match is_ref_slice(&ty) {
|
||||||
|
Some(_) => {
|
||||||
|
args.push(quote! { #core::v8::fast_api::Type::TypedArray(#core::v8::fast_api::CType::Uint8) });
|
||||||
|
slices.insert(pos, quote!(u8));
|
||||||
|
}
|
||||||
// early return, this function cannot be a fast call.
|
// early return, this function cannot be a fast call.
|
||||||
None => return None,
|
None => return None,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
Some(arg) => {
|
Some(arg) => {
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
}
|
}
|
||||||
|
@ -555,6 +582,7 @@ fn can_be_fast_api(core: &TokenStream2, f: &syn::ItemFn) -> Option<FastApiSyn> {
|
||||||
args: args.parse().unwrap(),
|
args: args.parse().unwrap(),
|
||||||
ret,
|
ret,
|
||||||
use_recv,
|
use_recv,
|
||||||
|
slices,
|
||||||
v8_values,
|
v8_values,
|
||||||
use_fast_cb_opts,
|
use_fast_cb_opts,
|
||||||
})
|
})
|
||||||
|
@ -692,6 +720,44 @@ fn codegen_arg(
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Fast path for &/&mut [u8] and &/&mut [u32]
|
||||||
|
if let Some(ty) = is_ref_slice(&**ty) {
|
||||||
|
let (ptr_ty, mutability) = match ty {
|
||||||
|
SliceType::U8 => (quote!([u8]), quote!(&)),
|
||||||
|
SliceType::U8Mut => (quote!([u8]), quote!(&mut)),
|
||||||
|
};
|
||||||
|
return quote! {
|
||||||
|
let #ident = {
|
||||||
|
let value = args.get(#idx as i32);
|
||||||
|
if let Ok(view) = #core::v8::Local::<#core::v8::ArrayBufferView>::try_from(value) {
|
||||||
|
let (offset, len) = (view.byte_offset(), view.byte_length());
|
||||||
|
let buffer = match view.buffer(scope) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
return #core::_ops::throw_type_error(scope, format!("Expected ArrayBufferView at position {}", #idx));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let store = buffer.get_backing_store();
|
||||||
|
if store.is_shared() {
|
||||||
|
return #core::_ops::throw_type_error(scope, format!("Expected non-shared ArrayBufferView at position {}", #idx));
|
||||||
|
}
|
||||||
|
unsafe { #mutability *(&store[offset..offset + len] as *const _ as *mut #ptr_ty) }
|
||||||
|
} else {
|
||||||
|
let b: #core::v8::Local<#core::v8::ArrayBuffer> = match value.try_into() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => {
|
||||||
|
return #core::_ops::throw_type_error(scope, format!("Expected ArrayBuffer at position {}", #idx));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let store = b.get_backing_store();
|
||||||
|
if store.is_shared() {
|
||||||
|
return #core::_ops::throw_type_error(scope, format!("Expected non-shared ArrayBufferView at position {}", #idx));
|
||||||
|
}
|
||||||
|
unsafe { #mutability *(&store[0..b.byte_length()] as *const _ as *mut #ptr_ty) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
// Otherwise deserialize it via serde_v8
|
// Otherwise deserialize it via serde_v8
|
||||||
quote! {
|
quote! {
|
||||||
let #ident = args.get(#idx as i32);
|
let #ident = args.get(#idx as i32);
|
||||||
|
@ -780,6 +846,29 @@ fn is_option_string(ty: impl ToTokens) -> bool {
|
||||||
tokens(ty) == "Option < String >"
|
tokens(ty) == "Option < String >"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SliceType {
|
||||||
|
U8,
|
||||||
|
U8Mut,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ref_slice(ty: impl ToTokens) -> Option<SliceType> {
|
||||||
|
if is_u8_slice(&ty) {
|
||||||
|
return Some(SliceType::U8);
|
||||||
|
}
|
||||||
|
if is_u8_slice_mut(&ty) {
|
||||||
|
return Some(SliceType::U8Mut);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_u8_slice(ty: impl ToTokens) -> bool {
|
||||||
|
tokens(ty) == "& [u8]"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_u8_slice_mut(ty: impl ToTokens) -> bool {
|
||||||
|
tokens(ty) == "& mut [u8]"
|
||||||
|
}
|
||||||
|
|
||||||
fn is_optional_fast_callback_option(ty: impl ToTokens) -> bool {
|
fn is_optional_fast_callback_option(ty: impl ToTokens) -> bool {
|
||||||
tokens(&ty).contains("Option < & mut FastApiCallbackOptions")
|
tokens(&ty).contains("Option < & mut FastApiCallbackOptions")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue