diff options
author | Aapo Alasuutari <aapo.alasuutari@gmail.com> | 2022-10-20 07:05:56 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-20 09:35:56 +0530 |
commit | 722ea20e860df0a568b5d97734ad8d89aa7382a9 (patch) | |
tree | 7b5dea0f32318dcc8d7d98b0cc6d4a3384a5805c /ext/ffi/lib.rs | |
parent | 973069b341de65e8e32b91072ff5a745fe7e704a (diff) |
perf(ext/ffi): Fast UnsafePointerView read functions (#16351)
This PR makes pointer read methods of `Deno.UnsafePointerView` Fast API
compliant, with the exception of `getCString` which cannot be made fast
with current V8 Fast API.
Diffstat (limited to 'ext/ffi/lib.rs')
-rw-r--r-- | ext/ffi/lib.rs | 242 |
1 files changed, 172 insertions, 70 deletions
diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index 183fd9214..ae51db34c 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -2117,7 +2117,8 @@ unsafe extern "C" fn noop_deleter_callback( fn op_ffi_get_buf<FP, 'scope>( scope: &mut v8::HandleScope<'scope>, state: &mut deno_core::OpState, - src: serde_v8::Value<'scope>, + ptr: usize, + offset: usize, len: usize, ) -> Result<serde_v8::Value<'scope>, AnyError> where @@ -2128,18 +2129,15 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - let ptr = if let Ok(value) = v8::Local::<v8::Number>::try_from(src.v8_value) { - value.value() as usize as *mut c_void - } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(src.v8_value) { - value.u64_value().0 as usize as *mut c_void - } else { - return Err(type_error("Invalid FFI pointer value, expected BigInt")); - }; + let ptr = ptr as *mut c_void; - if std::ptr::eq(ptr, std::ptr::null()) { + if ptr.is_null() { return Err(type_error("Invalid FFI pointer value, got nullptr")); } + // SAFETY: Offset is user defined. + let ptr = unsafe { ptr.add(offset) }; + // SAFETY: Trust the user to have provided a real pointer, and a valid matching size to it. Since this is a foreign pointer, we should not do any deletion. let backing_store = unsafe { v8::ArrayBuffer::new_backing_store_from_ptr( @@ -2155,10 +2153,11 @@ where Ok(array_buffer.into()) } -#[op] +#[op(fast)] fn op_ffi_buf_copy_into<FP>( state: &mut deno_core::OpState, src: usize, + offset: usize, dst: &mut [u8], len: usize, ) -> Result<(), AnyError> @@ -2175,10 +2174,14 @@ where "Destination length is smaller than source length", )) } else { - let src = src as *const u8; + let src = src as *const c_void; + + // SAFETY: Offset is user defined. + let src = unsafe { src.add(offset) as *const u8 }; + // SAFETY: src is user defined. // dest is properly aligned and is valid for writes of len * size_of::<T>() bytes. - unsafe { ptr::copy(src, dst.as_mut_ptr(), len) }; + unsafe { ptr::copy::<u8>(src, dst.as_mut_ptr(), len) }; Ok(()) } } @@ -2188,6 +2191,7 @@ fn op_ffi_cstr_read<FP, 'scope>( scope: &mut v8::HandleScope<'scope>, state: &mut deno_core::OpState, ptr: usize, + offset: usize, ) -> Result<serde_v8::Value<'scope>, AnyError> where FP: FfiPermissions + 'static, @@ -2197,6 +2201,15 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid CString pointer, pointer is null")); + } + + // SAFETY: Offset is user defined. + let ptr = unsafe { ptr.add(offset) }; + // SAFETY: Pointer is user provided. let cstr = unsafe { CStr::from_ptr(ptr as *const c_char) } .to_str() @@ -2209,10 +2222,11 @@ where Ok(value.into()) } -#[op] +#[op(fast)] fn op_ffi_read_bool<FP>( state: &mut deno_core::OpState, ptr: usize, + offset: usize, ) -> Result<bool, AnyError> where FP: FfiPermissions + 'static, @@ -2222,15 +2236,22 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const bool) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid bool pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { ptr::read_unaligned::<bool>(ptr.add(offset) as *const bool) }) } -#[op] +#[op(fast)] fn op_ffi_read_u8<FP>( state: &mut deno_core::OpState, ptr: usize, -) -> Result<u8, AnyError> + offset: usize, +) -> Result<u32, AnyError> where FP: FfiPermissions + 'static, { @@ -2239,15 +2260,22 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const u8) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid u8 pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { ptr::read_unaligned::<u8>(ptr.add(offset) as *const u8) as u32 }) } -#[op] +#[op(fast)] fn op_ffi_read_i8<FP>( state: &mut deno_core::OpState, ptr: usize, -) -> Result<i8, AnyError> + offset: usize, +) -> Result<i32, AnyError> where FP: FfiPermissions + 'static, { @@ -2256,15 +2284,22 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const i8) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid i8 pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { ptr::read_unaligned::<i8>(ptr.add(offset) as *const i8) as i32 }) } -#[op] +#[op(fast)] fn op_ffi_read_u16<FP>( state: &mut deno_core::OpState, ptr: usize, -) -> Result<u16, AnyError> + offset: usize, +) -> Result<u32, AnyError> where FP: FfiPermissions + 'static, { @@ -2273,15 +2308,24 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const u16) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid u16 pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { + ptr::read_unaligned::<u16>(ptr.add(offset) as *const u16) as u32 + }) } -#[op] +#[op(fast)] fn op_ffi_read_i16<FP>( state: &mut deno_core::OpState, ptr: usize, -) -> Result<i16, AnyError> + offset: usize, +) -> Result<i32, AnyError> where FP: FfiPermissions + 'static, { @@ -2290,14 +2334,23 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const i16) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid i16 pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { + ptr::read_unaligned::<i16>(ptr.add(offset) as *const i16) as i32 + }) } -#[op] +#[op(fast)] fn op_ffi_read_u32<FP>( state: &mut deno_core::OpState, ptr: usize, + offset: usize, ) -> Result<u32, AnyError> where FP: FfiPermissions + 'static, @@ -2307,14 +2360,23 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const u32) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid u32 pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { + ptr::read_unaligned::<u32>(ptr.add(offset) as *const u32) as u32 + }) } -#[op] +#[op(fast)] fn op_ffi_read_i32<FP>( state: &mut deno_core::OpState, ptr: usize, + offset: usize, ) -> Result<i32, AnyError> where FP: FfiPermissions + 'static, @@ -2324,69 +2386,96 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const i32) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid i32 pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { + ptr::read_unaligned::<i32>(ptr.add(offset) as *const i32) as i32 + }) } -#[op(v8)] -fn op_ffi_read_u64<FP, 'scope>( - scope: &mut v8::HandleScope<'scope>, +#[op] +fn op_ffi_read_u64<FP>( state: &mut deno_core::OpState, ptr: usize, -) -> Result<serde_v8::Value<'scope>, AnyError> + offset: usize, + out: &mut [u32], +) -> Result<(), AnyError> where FP: FfiPermissions + 'static, - 'scope: 'scope, { check_unstable(state, "Deno.UnsafePointerView#getBigUint64"); let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - let result = unsafe { ptr::read_unaligned(ptr as *const u64) }; + let outptr = out.as_mut_ptr() as *mut u64; - let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as u64 { - v8::BigInt::new_from_u64(scope, result).into() - } else { - v8::Number::new(scope, result as f64).into() - }; + assert!( + out.len() >= (std::mem::size_of::<u64>() / std::mem::size_of::<u32>()) + ); + assert_eq!((outptr as usize % std::mem::size_of::<u64>()), 0); - Ok(integer.into()) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid u64 pointer, pointer is null")); + } + + let value = + // SAFETY: ptr and offset are user provided. + unsafe { ptr::read_unaligned::<u64>(ptr.add(offset) as *const u64) }; + + // SAFETY: Length and alignment of out slice were asserted to be correct. + unsafe { *outptr = value }; + Ok(()) } -#[op(v8)] -fn op_ffi_read_i64<FP, 'scope>( - scope: &mut v8::HandleScope<'scope>, +#[op(fast)] +fn op_ffi_read_i64<FP>( state: &mut deno_core::OpState, ptr: usize, -) -> Result<serde_v8::Value<'scope>, AnyError> + offset: usize, + out: &mut [u32], +) -> Result<(), AnyError> where FP: FfiPermissions + 'static, - 'scope: 'scope, { check_unstable(state, "Deno.UnsafePointerView#getBigUint64"); let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - let result = unsafe { ptr::read_unaligned(ptr as *const i64) }; + let outptr = out.as_mut_ptr() as *mut i64; - let integer: v8::Local<v8::Value> = - if result > MAX_SAFE_INTEGER as i64 || result < MIN_SAFE_INTEGER as i64 { - v8::BigInt::new_from_i64(scope, result).into() - } else { - v8::Number::new(scope, result as f64).into() - }; + assert!( + out.len() >= (std::mem::size_of::<i64>() / std::mem::size_of::<u32>()) + ); + assert_eq!((outptr as usize % std::mem::size_of::<i64>()), 0); - Ok(integer.into()) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid i64 pointer, pointer is null")); + } + + let value = + // SAFETY: ptr and offset are user provided. + unsafe { ptr::read_unaligned::<i64>(ptr.add(offset) as *const i64) }; + // SAFETY: Length and alignment of out slice were asserted to be correct. + unsafe { *outptr = value }; + Ok(()) } -#[op] +#[op(fast)] fn op_ffi_read_f32<FP>( state: &mut deno_core::OpState, ptr: usize, + offset: usize, ) -> Result<f32, AnyError> where FP: FfiPermissions + 'static, @@ -2396,14 +2485,21 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const f32) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid f32 pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { ptr::read_unaligned::<f32>(ptr.add(offset) as *const f32) }) } -#[op] +#[op(fast)] fn op_ffi_read_f64<FP>( state: &mut deno_core::OpState, ptr: usize, + offset: usize, ) -> Result<f64, AnyError> where FP: FfiPermissions + 'static, @@ -2413,8 +2509,14 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - // SAFETY: ptr is user provided. - Ok(unsafe { ptr::read_unaligned(ptr as *const f64) }) + let ptr = ptr as *const c_void; + + if ptr.is_null() { + return Err(type_error("Invalid f64 pointer, pointer is null")); + } + + // SAFETY: ptr and offset are user provided. + Ok(unsafe { ptr::read_unaligned::<f64>(ptr.add(offset) as *const f64) }) } #[cfg(test)] |