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 | |
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.
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_10.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_11.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_12.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_13.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_14.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_15.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_5.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_6.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_7.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_8.js | 2 | ||||
-rw-r--r-- | cli/tests/testdata/run/ffi/unstable_ffi_9.js | 2 | ||||
-rw-r--r-- | ext/ffi/00_ffi.js | 64 | ||||
-rw-r--r-- | ext/ffi/lib.rs | 242 | ||||
-rw-r--r-- | ops/lib.rs | 29 | ||||
-rw-r--r-- | test_ffi/tests/bench.js | 50 |
15 files changed, 305 insertions, 102 deletions
diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_10.js b/cli/tests/testdata/run/ffi/unstable_ffi_10.js index 83687c584..80ee896bd 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_10.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_10.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_i16(0n); +Deno.core.ops.op_ffi_read_i16(0n, 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_11.js b/cli/tests/testdata/run/ffi/unstable_ffi_11.js index 5538753be..6324a8fbd 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_11.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_11.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_u32(0n); +Deno.core.ops.op_ffi_read_u32(0n, 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_12.js b/cli/tests/testdata/run/ffi/unstable_ffi_12.js index 089c9b5b1..7888684e9 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_12.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_12.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_i32(0n); +Deno.core.ops.op_ffi_read_i32(0n, 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_13.js b/cli/tests/testdata/run/ffi/unstable_ffi_13.js index 630be2e6d..b9afff9de 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_13.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_13.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_u64(0n); +Deno.core.ops.op_ffi_read_u64(0n, 0, new Uint32Array(2)); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_14.js b/cli/tests/testdata/run/ffi/unstable_ffi_14.js index b04c7865e..b8c1bf5b5 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_14.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_14.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_f32(0n); +Deno.core.ops.op_ffi_read_f32(0n, 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_15.js b/cli/tests/testdata/run/ffi/unstable_ffi_15.js index 865f63c75..92242fe3f 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_15.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_15.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_f64(0n); +Deno.core.ops.op_ffi_read_f64(0n, 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_5.js b/cli/tests/testdata/run/ffi/unstable_ffi_5.js index d08d8eaa4..9834a9a80 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_5.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_5.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_buf_copy_into(0n, new Uint8Array(0), 0); +Deno.core.ops.op_ffi_buf_copy_into(0n, 0, new Uint8Array(0), 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_6.js b/cli/tests/testdata/run/ffi/unstable_ffi_6.js index 9e4f1c761..0bd847f8c 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_6.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_6.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_cstr_read(0n); +Deno.core.ops.op_ffi_cstr_read(0n, 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_7.js b/cli/tests/testdata/run/ffi/unstable_ffi_7.js index 96e60f377..143138a6a 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_7.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_7.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_u8(0n); +Deno.core.ops.op_ffi_read_u8(0n, 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_8.js b/cli/tests/testdata/run/ffi/unstable_ffi_8.js index 187b83891..6b2d89a48 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_8.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_8.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_i8(0n); +Deno.core.ops.op_ffi_read_i8(0n, 0); diff --git a/cli/tests/testdata/run/ffi/unstable_ffi_9.js b/cli/tests/testdata/run/ffi/unstable_ffi_9.js index e968e534c..852e11f10 100644 --- a/cli/tests/testdata/run/ffi/unstable_ffi_9.js +++ b/cli/tests/testdata/run/ffi/unstable_ffi_9.js @@ -1 +1 @@ -Deno.core.ops.op_ffi_read_u16(0n); +Deno.core.ops.op_ffi_read_u16(0n, 0); diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 3f5c57a9c..f5b0fb4c3 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -6,7 +6,6 @@ const ops = core.ops; const __bootstrap = window.__bootstrap; const { - BigInt, ObjectDefineProperty, ArrayPrototypeMap, Number, @@ -17,9 +16,13 @@ Int32Array, Uint32Array, BigInt64Array, + BigUint64Array, Function, } = window.__bootstrap.primordials; + const U32_BUFFER = new Uint32Array(2); + const U64_BUFFER = new BigUint64Array(U32_BUFFER.buffer); + const I64_BUFFER = new BigInt64Array(U32_BUFFER.buffer); class UnsafePointerView { pointer; @@ -29,99 +32,119 @@ getBool(offset = 0) { return ops.op_ffi_read_bool( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getUint8(offset = 0) { return ops.op_ffi_read_u8( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getInt8(offset = 0) { return ops.op_ffi_read_i8( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getUint16(offset = 0) { return ops.op_ffi_read_u16( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getInt16(offset = 0) { return ops.op_ffi_read_i16( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getUint32(offset = 0) { return ops.op_ffi_read_u32( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getInt32(offset = 0) { return ops.op_ffi_read_i32( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getBigUint64(offset = 0) { - return ops.op_ffi_read_u64( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + ops.op_ffi_read_u64( + this.pointer, + offset, + U32_BUFFER, ); + return U64_BUFFER[0]; } getBigInt64(offset = 0) { - return ops.op_ffi_read_i64( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + ops.op_ffi_read_i64( + this.pointer, + offset, + U32_BUFFER, ); + return I64_BUFFER[0]; } getFloat32(offset = 0) { return ops.op_ffi_read_f32( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getFloat64(offset = 0) { return ops.op_ffi_read_f64( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } getCString(offset = 0) { return ops.op_ffi_cstr_read( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, ); } static getCString(pointer, offset = 0) { return ops.op_ffi_cstr_read( - offset ? BigInt(pointer) + BigInt(offset) : pointer, + pointer, + offset, ); } getArrayBuffer(byteLength, offset = 0) { return ops.op_ffi_get_buf( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, byteLength, ); } static getArrayBuffer(pointer, byteLength, offset = 0) { return ops.op_ffi_get_buf( - offset ? BigInt(pointer) + BigInt(offset) : pointer, + pointer, + offset, byteLength, ); } copyInto(destination, offset = 0) { ops.op_ffi_buf_copy_into( - offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer, + this.pointer, + offset, destination, destination.byteLength, ); @@ -129,7 +152,8 @@ static copyInto(pointer, destination, offset = 0) { ops.op_ffi_buf_copy_into( - offset ? BigInt(pointer) + BigInt(offset) : pointer, + pointer, + offset, destination, destination.byteLength, ); 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)] diff --git a/ops/lib.rs b/ops/lib.rs index 3200a6d34..adc50e69c 100644 --- a/ops/lib.rs +++ b/ops/lib.rs @@ -774,6 +774,35 @@ fn is_fast_scalar( match tokens(&ty).as_str() { "u32" => Some(quote! { #core::v8::fast_api::#cty::Uint32 }), "i32" => Some(quote! { #core::v8::fast_api::#cty::Int32 }), + "u64" => { + if is_ret { + None + } else { + Some(quote! { #core::v8::fast_api::#cty::Uint64 }) + } + } + "i64" => { + if is_ret { + None + } else { + Some(quote! { #core::v8::fast_api::#cty::Int64 }) + } + } + // TODO(@aapoalas): Support 32 bit machines + "usize" => { + if is_ret { + None + } else { + Some(quote! { #core::v8::fast_api::#cty::Uint64 }) + } + } + "isize" => { + if is_ret { + None + } else { + Some(quote! { #core::v8::fast_api::#cty::Int64 }) + } + } "f32" => Some(quote! { #core::v8::fast_api::#cty::Float32 }), "f64" => Some(quote! { #core::v8::fast_api::#cty::Float64 }), "bool" => Some(quote! { #core::v8::fast_api::#cty::Bool }), diff --git a/test_ffi/tests/bench.js b/test_ffi/tests/bench.js index b59097082..a20ee3c80 100644 --- a/test_ffi/tests/bench.js +++ b/test_ffi/tests/bench.js @@ -251,7 +251,7 @@ Deno.bench("hash()", () => { const { ffi_string } = dylib.symbols; Deno.bench( "c string", - () => new Deno.UnsafePointerView(ffi_string()).getCString(), + () => Deno.UnsafePointerView.getCString(ffi_string()), ); const { add_u32 } = dylib.symbols; @@ -643,3 +643,51 @@ const cstringPointerView = new Deno.UnsafePointerView( Deno.bench("Deno.UnsafePointerView#getCString", () => { cstringPointerView.getCString(); }); + +const bufferPointerView = new Deno.UnsafePointerView( + Deno.UnsafePointer.of(buffer), +); + +Deno.bench("Deno.UnsafePointerView#getBool", () => { + bufferPointerView.getBool(); +}); + +Deno.bench("Deno.UnsafePointerView#getUint8", () => { + bufferPointerView.getUint8(); +}); + +Deno.bench("Deno.UnsafePointerView#getInt8", () => { + bufferPointerView.getInt8(); +}); + +Deno.bench("Deno.UnsafePointerView#getUint16", () => { + bufferPointerView.getUint16(); +}); + +Deno.bench("Deno.UnsafePointerView#getInt16", () => { + bufferPointerView.getInt16(); +}); + +Deno.bench("Deno.UnsafePointerView#getUint32", () => { + bufferPointerView.getUint32(); +}); + +Deno.bench("Deno.UnsafePointerView#getInt32", () => { + bufferPointerView.getInt32(); +}); + +Deno.bench("Deno.UnsafePointerView#getBigUint64", () => { + bufferPointerView.getBigUint64(); +}); + +Deno.bench("Deno.UnsafePointerView#getBigInt64", () => { + bufferPointerView.getBigInt64(); +}); + +Deno.bench("Deno.UnsafePointerView#getFloat32", () => { + bufferPointerView.getFloat32(); +}); + +Deno.bench("Deno.UnsafePointerView#getFloat64", () => { + bufferPointerView.getFloat64(); +}); |