diff options
author | Aapo Alasuutari <aapo.alasuutari@gmail.com> | 2022-07-22 14:07:35 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-22 16:37:35 +0530 |
commit | 244c00d95b7ec8f30a5e81b743b4b618049b6c37 (patch) | |
tree | e32602ab92d4c117dbbd72ea9c7436964466187d | |
parent | 4e71a9424e12a9711b41edce049ee026f0a904b4 (diff) |
perf(ext/ffi): Optimise common pointer related APIs (#15144)
-rw-r--r-- | ext/ffi/00_ffi.js | 24 | ||||
-rw-r--r-- | ext/ffi/lib.rs | 49 | ||||
-rw-r--r-- | test_ffi/tests/bench.js | 14 |
3 files changed, 66 insertions, 21 deletions
diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 22e442e51..cdaf69e0d 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -32,77 +32,77 @@ getUint8(offset = 0) { return core.opSync( "op_ffi_read_u8", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getInt8(offset = 0) { return core.opSync( "op_ffi_read_i8", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getUint16(offset = 0) { return core.opSync( "op_ffi_read_u16", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getInt16(offset = 0) { return core.opSync( "op_ffi_read_i16", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getUint32(offset = 0) { return core.opSync( "op_ffi_read_u32", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getInt32(offset = 0) { return core.opSync( "op_ffi_read_i32", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getBigUint64(offset = 0) { return core.opSync( "op_ffi_read_u64", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getBigInt64(offset = 0) { return core.opSync( "op_ffi_read_u64", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getFloat32(offset = 0) { return core.opSync( "op_ffi_read_f32", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getFloat64(offset = 0) { return core.opSync( "op_ffi_read_f64", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } getCString(offset = 0) { return core.opSync( "op_ffi_cstr_read", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, ); } @@ -115,7 +115,7 @@ copyInto(destination, offset = 0) { core.opSync( "op_ffi_buf_copy_into", - this.pointer + BigInt(offset), + offset ? this.pointer + BigInt(offset) : this.pointer, destination, destination.byteLength, ); diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index 926d88ac7..05dcba362 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -1873,7 +1873,7 @@ fn op_ffi_call_nonblocking<'scope>( fn op_ffi_ptr_of<FP, 'scope>( scope: &mut v8::HandleScope<'scope>, state: &mut deno_core::OpState, - buf: ZeroCopyBuf, + buf: serde_v8::Value<'scope>, ) -> Result<serde_v8::Value<'scope>, AnyError> where FP: FfiPermissions + 'static, @@ -1882,8 +1882,33 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; + let pointer = if let Ok(value) = + v8::Local::<v8::ArrayBufferView>::try_from(buf.v8_value) + { + let backing_store = value + .buffer(scope) + .ok_or_else(|| { + type_error("Invalid FFI ArrayBufferView, expected data in the buffer") + })? + .get_backing_store(); + let byte_offset = value.byte_offset(); + if byte_offset > 0 { + &backing_store[byte_offset..] as *const _ as *const u8 + } else { + &backing_store[..] as *const _ as *const u8 + } + } else if let Ok(value) = v8::Local::<v8::ArrayBuffer>::try_from(buf.v8_value) + { + let backing_store = value.get_backing_store(); + &backing_store[..] as *const _ as *const u8 + } else { + return Err(type_error( + "Invalid FFI buffer, expected ArrayBuffer, or ArrayBufferView", + )); + }; + let big_int: v8::Local<v8::Value> = - v8::BigInt::new_from_u64(scope, buf.as_ptr() as u64).into(); + v8::BigInt::new_from_u64(scope, pointer as u64).into(); Ok(big_int.into()) } @@ -1915,11 +1940,12 @@ where } } -#[op] -fn op_ffi_cstr_read<FP>( +#[op(v8)] +fn op_ffi_cstr_read<FP, 'scope>( + scope: &mut v8::HandleScope<'scope>, state: &mut deno_core::OpState, ptr: u64, -) -> Result<String, AnyError> +) -> Result<serde_v8::Value<'scope>, AnyError> where FP: FfiPermissions + 'static, { @@ -1928,10 +1954,15 @@ where let permissions = state.borrow_mut::<FP>(); permissions.check(None)?; - let ptr = ptr as *const c_char; - // SAFETY: ptr is user provided - // lifetime validity is not an issue because we allocate a new string. - Ok(unsafe { CStr::from_ptr(ptr) }.to_str()?.to_string()) + // SAFETY: Pointer is user provided. + let cstr = unsafe { CStr::from_ptr(ptr as *const c_char) }.to_bytes(); + let value: v8::Local<v8::Value> = + v8::String::new_from_utf8(scope, cstr, v8::NewStringType::Normal) + .ok_or_else(|| { + type_error("Invalid CString pointer, string exceeds max length") + })? + .into(); + Ok(value.into()) } #[op] diff --git a/test_ffi/tests/bench.js b/test_ffi/tests/bench.js index 54a9e0acc..165b395e2 100644 --- a/test_ffi/tests/bench.js +++ b/test_ffi/tests/bench.js @@ -571,3 +571,17 @@ Deno.bench("nop_many_parameters_nonblocking()", () => { buffer2, ); }); + +Deno.bench("Deno.UnsafePointer.of", () => { + Deno.UnsafePointer.of(buffer); +}); + +const cstringBuffer = new TextEncoder().encode("Best believe it!\0"); +// Make sure the buffer does not get collected +globalThis.cstringBuffer = cstringBuffer; +const cstringPointerView = new Deno.UnsafePointerView( + Deno.UnsafePointer.of(cstringBuffer), +); +Deno.bench("Deno.UnsafePointerView#getCString", () => { + cstringPointerView.getCString(); +}); |