mirror of
https://github.com/denoland/deno.git
synced 2025-02-08 15:21:26 -05:00
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.
This commit is contained in:
parent
973069b341
commit
722ea20e86
15 changed files with 330 additions and 127 deletions
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_i16(0n);
|
Deno.core.ops.op_ffi_read_i16(0n, 0);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_u32(0n);
|
Deno.core.ops.op_ffi_read_u32(0n, 0);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_i32(0n);
|
Deno.core.ops.op_ffi_read_i32(0n, 0);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_u64(0n);
|
Deno.core.ops.op_ffi_read_u64(0n, 0, new Uint32Array(2));
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_f32(0n);
|
Deno.core.ops.op_ffi_read_f32(0n, 0);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_f64(0n);
|
Deno.core.ops.op_ffi_read_f64(0n, 0);
|
||||||
|
|
2
cli/tests/testdata/run/ffi/unstable_ffi_5.js
vendored
2
cli/tests/testdata/run/ffi/unstable_ffi_5.js
vendored
|
@ -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);
|
||||||
|
|
2
cli/tests/testdata/run/ffi/unstable_ffi_6.js
vendored
2
cli/tests/testdata/run/ffi/unstable_ffi_6.js
vendored
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_cstr_read(0n);
|
Deno.core.ops.op_ffi_cstr_read(0n, 0);
|
||||||
|
|
2
cli/tests/testdata/run/ffi/unstable_ffi_7.js
vendored
2
cli/tests/testdata/run/ffi/unstable_ffi_7.js
vendored
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_u8(0n);
|
Deno.core.ops.op_ffi_read_u8(0n, 0);
|
||||||
|
|
2
cli/tests/testdata/run/ffi/unstable_ffi_8.js
vendored
2
cli/tests/testdata/run/ffi/unstable_ffi_8.js
vendored
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_i8(0n);
|
Deno.core.ops.op_ffi_read_i8(0n, 0);
|
||||||
|
|
2
cli/tests/testdata/run/ffi/unstable_ffi_9.js
vendored
2
cli/tests/testdata/run/ffi/unstable_ffi_9.js
vendored
|
@ -1 +1 @@
|
||||||
Deno.core.ops.op_ffi_read_u16(0n);
|
Deno.core.ops.op_ffi_read_u16(0n, 0);
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
const ops = core.ops;
|
const ops = core.ops;
|
||||||
const __bootstrap = window.__bootstrap;
|
const __bootstrap = window.__bootstrap;
|
||||||
const {
|
const {
|
||||||
BigInt,
|
|
||||||
ObjectDefineProperty,
|
ObjectDefineProperty,
|
||||||
ArrayPrototypeMap,
|
ArrayPrototypeMap,
|
||||||
Number,
|
Number,
|
||||||
|
@ -17,9 +16,13 @@
|
||||||
Int32Array,
|
Int32Array,
|
||||||
Uint32Array,
|
Uint32Array,
|
||||||
BigInt64Array,
|
BigInt64Array,
|
||||||
|
BigUint64Array,
|
||||||
Function,
|
Function,
|
||||||
} = window.__bootstrap.primordials;
|
} = 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 {
|
class UnsafePointerView {
|
||||||
pointer;
|
pointer;
|
||||||
|
|
||||||
|
@ -29,99 +32,119 @@
|
||||||
|
|
||||||
getBool(offset = 0) {
|
getBool(offset = 0) {
|
||||||
return ops.op_ffi_read_bool(
|
return ops.op_ffi_read_bool(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUint8(offset = 0) {
|
getUint8(offset = 0) {
|
||||||
return ops.op_ffi_read_u8(
|
return ops.op_ffi_read_u8(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getInt8(offset = 0) {
|
getInt8(offset = 0) {
|
||||||
return ops.op_ffi_read_i8(
|
return ops.op_ffi_read_i8(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUint16(offset = 0) {
|
getUint16(offset = 0) {
|
||||||
return ops.op_ffi_read_u16(
|
return ops.op_ffi_read_u16(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getInt16(offset = 0) {
|
getInt16(offset = 0) {
|
||||||
return ops.op_ffi_read_i16(
|
return ops.op_ffi_read_i16(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUint32(offset = 0) {
|
getUint32(offset = 0) {
|
||||||
return ops.op_ffi_read_u32(
|
return ops.op_ffi_read_u32(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getInt32(offset = 0) {
|
getInt32(offset = 0) {
|
||||||
return ops.op_ffi_read_i32(
|
return ops.op_ffi_read_i32(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBigUint64(offset = 0) {
|
getBigUint64(offset = 0) {
|
||||||
return ops.op_ffi_read_u64(
|
ops.op_ffi_read_u64(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
|
U32_BUFFER,
|
||||||
);
|
);
|
||||||
|
return U64_BUFFER[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
getBigInt64(offset = 0) {
|
getBigInt64(offset = 0) {
|
||||||
return ops.op_ffi_read_i64(
|
ops.op_ffi_read_i64(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
|
U32_BUFFER,
|
||||||
);
|
);
|
||||||
|
return I64_BUFFER[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
getFloat32(offset = 0) {
|
getFloat32(offset = 0) {
|
||||||
return ops.op_ffi_read_f32(
|
return ops.op_ffi_read_f32(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFloat64(offset = 0) {
|
getFloat64(offset = 0) {
|
||||||
return ops.op_ffi_read_f64(
|
return ops.op_ffi_read_f64(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCString(offset = 0) {
|
getCString(offset = 0) {
|
||||||
return ops.op_ffi_cstr_read(
|
return ops.op_ffi_cstr_read(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getCString(pointer, offset = 0) {
|
static getCString(pointer, offset = 0) {
|
||||||
return ops.op_ffi_cstr_read(
|
return ops.op_ffi_cstr_read(
|
||||||
offset ? BigInt(pointer) + BigInt(offset) : pointer,
|
pointer,
|
||||||
|
offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getArrayBuffer(byteLength, offset = 0) {
|
getArrayBuffer(byteLength, offset = 0) {
|
||||||
return ops.op_ffi_get_buf(
|
return ops.op_ffi_get_buf(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
byteLength,
|
byteLength,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getArrayBuffer(pointer, byteLength, offset = 0) {
|
static getArrayBuffer(pointer, byteLength, offset = 0) {
|
||||||
return ops.op_ffi_get_buf(
|
return ops.op_ffi_get_buf(
|
||||||
offset ? BigInt(pointer) + BigInt(offset) : pointer,
|
pointer,
|
||||||
|
offset,
|
||||||
byteLength,
|
byteLength,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyInto(destination, offset = 0) {
|
copyInto(destination, offset = 0) {
|
||||||
ops.op_ffi_buf_copy_into(
|
ops.op_ffi_buf_copy_into(
|
||||||
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
|
this.pointer,
|
||||||
|
offset,
|
||||||
destination,
|
destination,
|
||||||
destination.byteLength,
|
destination.byteLength,
|
||||||
);
|
);
|
||||||
|
@ -129,7 +152,8 @@
|
||||||
|
|
||||||
static copyInto(pointer, destination, offset = 0) {
|
static copyInto(pointer, destination, offset = 0) {
|
||||||
ops.op_ffi_buf_copy_into(
|
ops.op_ffi_buf_copy_into(
|
||||||
offset ? BigInt(pointer) + BigInt(offset) : pointer,
|
pointer,
|
||||||
|
offset,
|
||||||
destination,
|
destination,
|
||||||
destination.byteLength,
|
destination.byteLength,
|
||||||
);
|
);
|
||||||
|
|
292
ext/ffi/lib.rs
292
ext/ffi/lib.rs
|
@ -2117,7 +2117,8 @@ unsafe extern "C" fn noop_deleter_callback(
|
||||||
fn op_ffi_get_buf<FP, 'scope>(
|
fn op_ffi_get_buf<FP, 'scope>(
|
||||||
scope: &mut v8::HandleScope<'scope>,
|
scope: &mut v8::HandleScope<'scope>,
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
src: serde_v8::Value<'scope>,
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<serde_v8::Value<'scope>, AnyError>
|
) -> Result<serde_v8::Value<'scope>, AnyError>
|
||||||
where
|
where
|
||||||
|
@ -2128,18 +2129,15 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
let ptr = if let Ok(value) = v8::Local::<v8::Number>::try_from(src.v8_value) {
|
let ptr = ptr as *mut c_void;
|
||||||
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"));
|
|
||||||
};
|
|
||||||
|
|
||||||
if std::ptr::eq(ptr, std::ptr::null()) {
|
if ptr.is_null() {
|
||||||
return Err(type_error("Invalid FFI pointer value, got nullptr"));
|
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.
|
// 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 {
|
let backing_store = unsafe {
|
||||||
v8::ArrayBuffer::new_backing_store_from_ptr(
|
v8::ArrayBuffer::new_backing_store_from_ptr(
|
||||||
|
@ -2155,10 +2153,11 @@ where
|
||||||
Ok(array_buffer.into())
|
Ok(array_buffer.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op(fast)]
|
||||||
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,
|
||||||
|
offset: usize,
|
||||||
dst: &mut [u8],
|
dst: &mut [u8],
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<(), AnyError>
|
) -> Result<(), AnyError>
|
||||||
|
@ -2175,10 +2174,14 @@ where
|
||||||
"Destination length is smaller than source length",
|
"Destination length is smaller than source length",
|
||||||
))
|
))
|
||||||
} else {
|
} 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.
|
// SAFETY: src is user defined.
|
||||||
// dest is properly aligned and is valid for writes of len * size_of::<T>() bytes.
|
// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2188,6 +2191,7 @@ fn op_ffi_cstr_read<FP, 'scope>(
|
||||||
scope: &mut v8::HandleScope<'scope>,
|
scope: &mut v8::HandleScope<'scope>,
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
) -> Result<serde_v8::Value<'scope>, AnyError>
|
) -> Result<serde_v8::Value<'scope>, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
|
@ -2197,6 +2201,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_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.
|
// SAFETY: Pointer is user provided.
|
||||||
let cstr = unsafe { CStr::from_ptr(ptr as *const c_char) }
|
let cstr = unsafe { CStr::from_ptr(ptr as *const c_char) }
|
||||||
.to_str()
|
.to_str()
|
||||||
|
@ -2209,10 +2222,11 @@ where
|
||||||
Ok(value.into())
|
Ok(value.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op(fast)]
|
||||||
fn op_ffi_read_bool<FP>(
|
fn op_ffi_read_bool<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
) -> Result<bool, AnyError>
|
) -> Result<bool, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
|
@ -2222,15 +2236,22 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const bool) })
|
|
||||||
|
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>(
|
fn op_ffi_read_u8<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
) -> Result<u8, AnyError>
|
offset: usize,
|
||||||
|
) -> Result<u32, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
{
|
{
|
||||||
|
@ -2239,15 +2260,22 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const u8) })
|
|
||||||
|
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>(
|
fn op_ffi_read_i8<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
) -> Result<i8, AnyError>
|
offset: usize,
|
||||||
|
) -> Result<i32, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
{
|
{
|
||||||
|
@ -2256,15 +2284,22 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const i8) })
|
|
||||||
|
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>(
|
fn op_ffi_read_u16<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
) -> Result<u16, AnyError>
|
offset: usize,
|
||||||
|
) -> Result<u32, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
{
|
{
|
||||||
|
@ -2273,15 +2308,24 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const u16) })
|
|
||||||
|
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>(
|
fn op_ffi_read_i16<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
) -> Result<i16, AnyError>
|
offset: usize,
|
||||||
|
) -> Result<i32, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
{
|
{
|
||||||
|
@ -2290,14 +2334,23 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const i16) })
|
|
||||||
|
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>(
|
fn op_ffi_read_u32<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
) -> Result<u32, AnyError>
|
) -> Result<u32, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
|
@ -2307,14 +2360,23 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const u32) })
|
|
||||||
|
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>(
|
fn op_ffi_read_i32<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
) -> Result<i32, AnyError>
|
) -> Result<i32, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
|
@ -2324,69 +2386,96 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const i32) })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op(v8)]
|
if ptr.is_null() {
|
||||||
fn op_ffi_read_u64<FP, 'scope>(
|
return Err(type_error("Invalid i32 pointer, pointer is null"));
|
||||||
scope: &mut v8::HandleScope<'scope>,
|
}
|
||||||
state: &mut deno_core::OpState,
|
|
||||||
ptr: usize,
|
|
||||||
) -> Result<serde_v8::Value<'scope>, AnyError>
|
|
||||||
where
|
|
||||||
FP: FfiPermissions + 'static,
|
|
||||||
'scope: 'scope,
|
|
||||||
{
|
|
||||||
check_unstable(state, "Deno.UnsafePointerView#getBigUint64");
|
|
||||||
|
|
||||||
let permissions = state.borrow_mut::<FP>();
|
// SAFETY: ptr and offset are user provided.
|
||||||
permissions.check(None)?;
|
Ok(unsafe {
|
||||||
|
ptr::read_unaligned::<i32>(ptr.add(offset) as *const i32) as i32
|
||||||
// SAFETY: ptr is user provided.
|
})
|
||||||
let result = unsafe { ptr::read_unaligned(ptr as *const 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()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(integer.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[op(v8)]
|
|
||||||
fn op_ffi_read_i64<FP, 'scope>(
|
|
||||||
scope: &mut v8::HandleScope<'scope>,
|
|
||||||
state: &mut deno_core::OpState,
|
|
||||||
ptr: usize,
|
|
||||||
) -> Result<serde_v8::Value<'scope>, 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 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()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(integer.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
|
fn op_ffi_read_u64<FP>(
|
||||||
|
state: &mut deno_core::OpState,
|
||||||
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
|
out: &mut [u32],
|
||||||
|
) -> Result<(), AnyError>
|
||||||
|
where
|
||||||
|
FP: FfiPermissions + 'static,
|
||||||
|
{
|
||||||
|
check_unstable(state, "Deno.UnsafePointerView#getBigUint64");
|
||||||
|
|
||||||
|
let permissions = state.borrow_mut::<FP>();
|
||||||
|
permissions.check(None)?;
|
||||||
|
|
||||||
|
let outptr = out.as_mut_ptr() as *mut u64;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
out.len() >= (std::mem::size_of::<u64>() / std::mem::size_of::<u32>())
|
||||||
|
);
|
||||||
|
assert_eq!((outptr as usize % std::mem::size_of::<u64>()), 0);
|
||||||
|
|
||||||
|
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(fast)]
|
||||||
|
fn op_ffi_read_i64<FP>(
|
||||||
|
state: &mut deno_core::OpState,
|
||||||
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
|
out: &mut [u32],
|
||||||
|
) -> Result<(), AnyError>
|
||||||
|
where
|
||||||
|
FP: FfiPermissions + 'static,
|
||||||
|
{
|
||||||
|
check_unstable(state, "Deno.UnsafePointerView#getBigUint64");
|
||||||
|
|
||||||
|
let permissions = state.borrow_mut::<FP>();
|
||||||
|
permissions.check(None)?;
|
||||||
|
|
||||||
|
let outptr = out.as_mut_ptr() as *mut i64;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
out.len() >= (std::mem::size_of::<i64>() / std::mem::size_of::<u32>())
|
||||||
|
);
|
||||||
|
assert_eq!((outptr as usize % std::mem::size_of::<i64>()), 0);
|
||||||
|
|
||||||
|
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(fast)]
|
||||||
fn op_ffi_read_f32<FP>(
|
fn op_ffi_read_f32<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
) -> Result<f32, AnyError>
|
) -> Result<f32, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
|
@ -2396,14 +2485,21 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const f32) })
|
|
||||||
|
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>(
|
fn op_ffi_read_f64<FP>(
|
||||||
state: &mut deno_core::OpState,
|
state: &mut deno_core::OpState,
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
|
offset: usize,
|
||||||
) -> Result<f64, AnyError>
|
) -> Result<f64, AnyError>
|
||||||
where
|
where
|
||||||
FP: FfiPermissions + 'static,
|
FP: FfiPermissions + 'static,
|
||||||
|
@ -2413,8 +2509,14 @@ where
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check(None)?;
|
permissions.check(None)?;
|
||||||
|
|
||||||
// SAFETY: ptr is user provided.
|
let ptr = ptr as *const c_void;
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr as *const f64) })
|
|
||||||
|
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)]
|
#[cfg(test)]
|
||||||
|
|
29
ops/lib.rs
29
ops/lib.rs
|
@ -774,6 +774,35 @@ fn is_fast_scalar(
|
||||||
match tokens(&ty).as_str() {
|
match tokens(&ty).as_str() {
|
||||||
"u32" => Some(quote! { #core::v8::fast_api::#cty::Uint32 }),
|
"u32" => Some(quote! { #core::v8::fast_api::#cty::Uint32 }),
|
||||||
"i32" => Some(quote! { #core::v8::fast_api::#cty::Int32 }),
|
"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 }),
|
"f32" => Some(quote! { #core::v8::fast_api::#cty::Float32 }),
|
||||||
"f64" => Some(quote! { #core::v8::fast_api::#cty::Float64 }),
|
"f64" => Some(quote! { #core::v8::fast_api::#cty::Float64 }),
|
||||||
"bool" => Some(quote! { #core::v8::fast_api::#cty::Bool }),
|
"bool" => Some(quote! { #core::v8::fast_api::#cty::Bool }),
|
||||||
|
|
|
@ -251,7 +251,7 @@ Deno.bench("hash()", () => {
|
||||||
const { ffi_string } = dylib.symbols;
|
const { ffi_string } = dylib.symbols;
|
||||||
Deno.bench(
|
Deno.bench(
|
||||||
"c string",
|
"c string",
|
||||||
() => new Deno.UnsafePointerView(ffi_string()).getCString(),
|
() => Deno.UnsafePointerView.getCString(ffi_string()),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { add_u32 } = dylib.symbols;
|
const { add_u32 } = dylib.symbols;
|
||||||
|
@ -643,3 +643,51 @@ const cstringPointerView = new Deno.UnsafePointerView(
|
||||||
Deno.bench("Deno.UnsafePointerView#getCString", () => {
|
Deno.bench("Deno.UnsafePointerView#getCString", () => {
|
||||||
cstringPointerView.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();
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue