Skip to content

Commit

Permalink
feat(ext/ffi): Safe number pointers (denoland#15173)
Browse files Browse the repository at this point in the history
  • Loading branch information
aapoalas committed Jul 24, 2022
1 parent e1cbd23 commit f8fee6c
Show file tree
Hide file tree
Showing 8 changed files with 713 additions and 443 deletions.
27 changes: 18 additions & 9 deletions cli/dts/lib.deno.unstable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,9 @@ declare namespace Deno {

type ToNativeTypeMap =
& Record<NativeNumberType, number>
& Record<NativeBigIntType, bigint | number>
& Record<NativePointerType, TypedArray | bigint | null>
& Record<NativeFunctionType, bigint | null>;
& Record<NativeBigIntType, PointerValue>
& Record<NativePointerType, TypedArray | PointerValue | null>
& Record<NativeFunctionType, PointerValue | null>;

/** Type conversion for foreign symbol parameters and unsafe callback return types */
type ToNativeType<T extends NativeType = NativeType> = ToNativeTypeMap[T];
Expand All @@ -391,9 +391,9 @@ declare namespace Deno {

type FromNativeTypeMap =
& Record<NativeNumberType, number>
& Record<NativeBigIntType, bigint>
& Record<NativePointerType, bigint>
& Record<NativeFunctionType, bigint>;
& Record<NativeBigIntType, PointerValue>
& Record<NativePointerType, PointerValue>
& Record<NativeFunctionType, PointerValue>;

/** Type conversion for foreign symbol return types and unsafe callback parameters */
type FromNativeType<T extends NativeType = NativeType> = FromNativeTypeMap[T];
Expand Down Expand Up @@ -481,6 +481,15 @@ declare namespace Deno {
| BigInt64Array
| BigUint64Array;

/**
* Pointer type depends on the architecture and actual pointer value.
*
* On a 32 bit system all pointer values are plain numbers. On a 64 bit
* system pointer values are represented as numbers if the value is below
* `Number.MAX_SAFE_INTEGER`.
*/
export type PointerValue = number | bigint;

/** **UNSTABLE**: Unsafe and new API, beware!
*
* An unsafe pointer to a memory location for passing and returning pointers to and from the ffi
Expand All @@ -489,7 +498,7 @@ declare namespace Deno {
/**
* Return the direct memory pointer to the typed array in memory
*/
static of(value: Deno.UnsafeCallback | TypedArray): bigint;
static of(value: Deno.UnsafeCallback | TypedArray): PointerValue;
}

/** **UNSTABLE**: Unsafe and new API, beware!
Expand Down Expand Up @@ -517,9 +526,9 @@ declare namespace Deno {
/** Gets a signed 32-bit integer at the specified byte offset from the pointer. */
getInt32(offset?: number): number;
/** Gets an unsigned 64-bit integer at the specified byte offset from the pointer. */
getBigUint64(offset?: number): bigint;
getBigUint64(offset?: number): PointerValue;
/** Gets a signed 64-bit integer at the specified byte offset from the pointer. */
getBigInt64(offset?: number): bigint;
getBigInt64(offset?: number): PointerValue;
/** Gets a signed 32-bit float at the specified byte offset from the pointer. */
getFloat32(offset?: number): number;
/** Gets a signed 64-bit float at the specified byte offset from the pointer. */
Expand Down
38 changes: 23 additions & 15 deletions ext/ffi/00_ffi.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,19 @@
TypeError,
} = window.__bootstrap.primordials;

function unpackU64([hi, lo]) {
function unpackU64(returnValue) {
if (typeof returnValue === "number") {
return returnValue;
}
const [hi, lo] = returnValue;
return BigInt(hi) << 32n | BigInt(lo);
}

function unpackI64([hi, lo]) {
function unpackI64(returnValue) {
if (typeof returnValue === "number") {
return returnValue;
}
const [hi, lo] = returnValue;
const u64 = unpackU64([hi, lo]);
return u64 >> 63n ? u64 - 0x10000000000000000n : u64;
}
Expand All @@ -31,77 +39,77 @@
getUint8(offset = 0) {
return core.opSync(
"op_ffi_read_u8",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getInt8(offset = 0) {
return core.opSync(
"op_ffi_read_i8",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getUint16(offset = 0) {
return core.opSync(
"op_ffi_read_u16",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getInt16(offset = 0) {
return core.opSync(
"op_ffi_read_i16",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getUint32(offset = 0) {
return core.opSync(
"op_ffi_read_u32",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getInt32(offset = 0) {
return core.opSync(
"op_ffi_read_i32",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getBigUint64(offset = 0) {
return core.opSync(
"op_ffi_read_u64",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getBigInt64(offset = 0) {
return core.opSync(
"op_ffi_read_u64",
offset ? this.pointer + BigInt(offset) : this.pointer,
"op_ffi_read_i64",
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getFloat32(offset = 0) {
return core.opSync(
"op_ffi_read_f32",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getFloat64(offset = 0) {
return core.opSync(
"op_ffi_read_f64",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

getCString(offset = 0) {
return core.opSync(
"op_ffi_cstr_read",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
);
}

Expand All @@ -116,7 +124,7 @@
copyInto(destination, offset = 0) {
core.opSync(
"op_ffi_buf_copy_into",
offset ? this.pointer + BigInt(offset) : this.pointer,
offset ? BigInt(this.pointer) + BigInt(offset) : this.pointer,
destination,
destination.byteLength,
);
Expand Down
27 changes: 17 additions & 10 deletions ext/ffi/jit_trampoline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use crate::{tcc::Compiler, Symbol};
use std::ffi::c_void;
use std::ffi::CString;
use std::fmt::Write as _;
use std::mem::size_of;

const _: () = assert!(size_of::<fn()>() == size_of::<usize>());

pub(crate) struct Allocation {
pub addr: *mut c_void,
Expand All @@ -22,12 +25,14 @@ fn native_arg_to_c(ty: &NativeType) -> &'static str {
match ty {
NativeType::U8 | NativeType::U16 | NativeType::U32 => "uint32_t",
NativeType::I8 | NativeType::I16 | NativeType::I32 => "int32_t",
NativeType::U64 | NativeType::USize => "uint64_t",
NativeType::I64 | NativeType::ISize => "int64_t",
NativeType::Void => "void",
NativeType::F32 => "float",
NativeType::F64 => "double",
_ => unimplemented!(),
NativeType::U64 => "uint64_t",
NativeType::I64 => "int64_t",
NativeType::ISize => "intptr_t",
NativeType::USize => "uintptr_t",
NativeType::Pointer | NativeType::Function => "void*",
}
}

Expand All @@ -42,9 +47,11 @@ fn native_to_c(ty: &NativeType) -> &'static str {
NativeType::Void => "void",
NativeType::F32 => "float",
NativeType::F64 => "double",
NativeType::U64 | NativeType::USize => "uint64_t",
NativeType::I64 | NativeType::ISize => "int64_t",
_ => unimplemented!(),
NativeType::U64 => "uint64_t",
NativeType::I64 => "int64_t",
NativeType::ISize => "intptr_t",
NativeType::USize => "uintptr_t",
NativeType::Pointer | NativeType::Function => "void*",
}
}

Expand Down Expand Up @@ -180,16 +187,16 @@ mod tests {
assert_eq!(
codegen(vec![NativeType::ISize, NativeType::U64], NativeType::Void),
"#include <stdint.h>\n\n\
extern void func(int64_t p0, uint64_t p1);\n\n\
void func_trampoline(void* recv, int64_t p0, uint64_t p1) {\
extern void func(intptr_t p0, uint64_t p1);\n\n\
void func_trampoline(void* recv, intptr_t p0, uint64_t p1) {\
\n return func(p0, p1);\n\
}\n\n"
);
assert_eq!(
codegen(vec![NativeType::USize, NativeType::USize], NativeType::U32),
"#include <stdint.h>\n\n\
extern uint32_t func(uint64_t p0, uint64_t p1);\n\n\
uint32_t func_trampoline(void* recv, uint64_t p0, uint64_t p1) {\
extern uint32_t func(uintptr_t p0, uintptr_t p1);\n\n\
uint32_t func_trampoline(void* recv, uintptr_t p0, uintptr_t p1) {\
\n return func(p0, p1);\n\
}\n\n"
);
Expand Down
Loading

0 comments on commit f8fee6c

Please sign in to comment.