0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 17:34:47 -05:00

perf(ext/ffi): Optimise common pointer related APIs (#15144)

This commit is contained in:
Aapo Alasuutari 2022-07-22 14:07:35 +03:00 committed by GitHub
parent 4e71a9424e
commit 244c00d95b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 21 deletions

View file

@ -32,77 +32,77 @@
getUint8(offset = 0) { getUint8(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_u8", "op_ffi_read_u8",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getInt8(offset = 0) { getInt8(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_i8", "op_ffi_read_i8",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getUint16(offset = 0) { getUint16(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_u16", "op_ffi_read_u16",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getInt16(offset = 0) { getInt16(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_i16", "op_ffi_read_i16",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getUint32(offset = 0) { getUint32(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_u32", "op_ffi_read_u32",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getInt32(offset = 0) { getInt32(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_i32", "op_ffi_read_i32",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getBigUint64(offset = 0) { getBigUint64(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_u64", "op_ffi_read_u64",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getBigInt64(offset = 0) { getBigInt64(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_u64", "op_ffi_read_u64",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getFloat32(offset = 0) { getFloat32(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_f32", "op_ffi_read_f32",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getFloat64(offset = 0) { getFloat64(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_read_f64", "op_ffi_read_f64",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
getCString(offset = 0) { getCString(offset = 0) {
return core.opSync( return core.opSync(
"op_ffi_cstr_read", "op_ffi_cstr_read",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
); );
} }
@ -115,7 +115,7 @@
copyInto(destination, offset = 0) { copyInto(destination, offset = 0) {
core.opSync( core.opSync(
"op_ffi_buf_copy_into", "op_ffi_buf_copy_into",
this.pointer + BigInt(offset), offset ? this.pointer + BigInt(offset) : this.pointer,
destination, destination,
destination.byteLength, destination.byteLength,
); );

View file

@ -1873,7 +1873,7 @@ fn op_ffi_call_nonblocking<'scope>(
fn op_ffi_ptr_of<FP, 'scope>( fn op_ffi_ptr_of<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>, scope: &mut v8::HandleScope<'scope>,
state: &mut deno_core::OpState, state: &mut deno_core::OpState,
buf: ZeroCopyBuf, buf: serde_v8::Value<'scope>,
) -> Result<serde_v8::Value<'scope>, AnyError> ) -> Result<serde_v8::Value<'scope>, AnyError>
where where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
@ -1882,8 +1882,33 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; 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> = 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()) Ok(big_int.into())
} }
@ -1915,11 +1940,12 @@ where
} }
} }
#[op] #[op(v8)]
fn op_ffi_cstr_read<FP>( fn op_ffi_cstr_read<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>,
state: &mut deno_core::OpState, state: &mut deno_core::OpState,
ptr: u64, ptr: u64,
) -> Result<String, AnyError> ) -> Result<serde_v8::Value<'scope>, AnyError>
where where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
@ -1928,10 +1954,15 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
let ptr = ptr as *const c_char; // SAFETY: Pointer is user provided.
// SAFETY: ptr is user provided let cstr = unsafe { CStr::from_ptr(ptr as *const c_char) }.to_bytes();
// lifetime validity is not an issue because we allocate a new string. let value: v8::Local<v8::Value> =
Ok(unsafe { CStr::from_ptr(ptr) }.to_str()?.to_string()) 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] #[op]

View file

@ -571,3 +571,17 @@ Deno.bench("nop_many_parameters_nonblocking()", () => {
buffer2, 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();
});