summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/dts/lib.deno.unstable.d.ts12
-rw-r--r--ext/ffi/00_ffi.js77
-rw-r--r--ext/ffi/lib.rs45
-rw-r--r--test_ffi/tests/ffi_types.ts24
-rw-r--r--test_ffi/tests/integration_tests.rs8
-rw-r--r--test_ffi/tests/test.js8
6 files changed, 120 insertions, 54 deletions
diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts
index b8eb886e4..12f53b784 100644
--- a/cli/dts/lib.deno.unstable.d.ts
+++ b/cli/dts/lib.deno.unstable.d.ts
@@ -372,17 +372,25 @@ declare namespace Deno {
}
/** All possible number types interfacing with foreign functions */
- type StaticNativeNumberType = Exclude<NativeType, "void" | "pointer">;
+ type StaticNativeNumberType = Exclude<
+ NativeType,
+ "void" | "pointer" | StaticNativeBigIntType
+ >;
+
+ /** All possible bigint types interfacing with foreign functions */
+ type StaticNativeBigIntType = "u64" | "i64" | "usize" | "isize";
/** Infers a foreign function return type */
type StaticForeignFunctionResult<T extends NativeType> = T extends "void"
? void
+ : T extends StaticNativeBigIntType ? bigint
: T extends StaticNativeNumberType ? number
: T extends "pointer" ? UnsafePointer
: never;
type StaticForeignFunctionParameter<T> = T extends "void" ? void
- : T extends StaticNativeNumberType ? number
+ : T extends StaticNativeNumberType | StaticNativeBigIntType
+ ? number | bigint
: T extends "pointer" ? Deno.UnsafePointer | Deno.TypedArray | null
: unknown;
diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js
index 3debeef14..fb4fcbfb8 100644
--- a/ext/ffi/00_ffi.js
+++ b/ext/ffi/00_ffi.js
@@ -14,12 +14,12 @@
TypeError,
} = window.__bootstrap.primordials;
- function unpackU64([hi, lo]) {
- return BigInt(hi) << 32n | BigInt(lo);
+ function pack64(value) {
+ return [Number(value >> 32n) >>> 0, Number(value & 0xFFFFFFFFn)];
}
- function packU64(value) {
- return [Number(value >> 32n), Number(value & 0xFFFFFFFFn)];
+ function unpackU64([hi, lo]) {
+ return BigInt(hi) << 32n | BigInt(lo);
}
function unpackI64([hi, lo]) {
@@ -37,77 +37,77 @@
getUint8(offset = 0) {
return core.opSync(
"op_ffi_read_u8",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getInt8(offset = 0) {
return core.opSync(
"op_ffi_read_i8",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getUint16(offset = 0) {
return core.opSync(
"op_ffi_read_u16",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getInt16(offset = 0) {
return core.opSync(
"op_ffi_read_i16",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getUint32(offset = 0) {
return core.opSync(
"op_ffi_read_u32",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getInt32(offset = 0) {
return core.opSync(
"op_ffi_read_i32",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getBigUint64(offset = 0) {
return unpackU64(core.opSync(
"op_ffi_read_u64",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
));
}
getBigInt64(offset = 0) {
return unpackI64(core.opSync(
"op_ffi_read_u64",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
));
}
getFloat32(offset = 0) {
return core.opSync(
"op_ffi_read_f32",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getFloat64(offset = 0) {
return core.opSync(
"op_ffi_read_f64",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getCString(offset = 0) {
return core.opSync(
"op_ffi_cstr_read",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
@@ -119,7 +119,7 @@
copyInto(destination, offset = 0) {
core.opSync("op_ffi_buf_copy_into", [
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
destination,
destination.byteLength,
]);
@@ -161,7 +161,7 @@
parameters.push(buffers.length);
buffers.push(arg);
} else if (ObjectPrototypeIsPrototypeOf(UnsafePointerPrototype, arg)) {
- parameters.push(packU64(arg.value));
+ parameters.push(pack64(arg.value));
buffers.push(undefined);
} else if (arg === null) {
parameters.push(null);
@@ -171,6 +171,14 @@
"Invalid ffi arg value, expected TypedArray, UnsafePointer or null",
);
}
+ } else if (typeof arg === "bigint") {
+ if (arg > 0xffffffffffffffffn) {
+ throw new TypeError(
+ "Invalid ffi arg value, it needs to be less than 0xffffffffffffffff",
+ );
+ }
+
+ parameters.push(pack64(arg));
} else {
parameters.push(arg);
}
@@ -179,6 +187,23 @@
return { parameters, buffers };
}
+ function unpackResult(type, result) {
+ switch (type) {
+ case "pointer":
+ return new UnsafePointer(unpackU64(result));
+ case "u64":
+ return unpackU64(result);
+ case "i64":
+ return unpackI64(result);
+ case "usize":
+ return unpackU64(result);
+ case "isize":
+ return unpackI64(result);
+ default:
+ return result;
+ }
+ }
+
class UnsafeFnPointer {
pointer;
definition;
@@ -195,7 +220,7 @@
);
if (this.definition.nonblocking) {
const promise = core.opAsync("op_ffi_call_ptr_nonblocking", {
- pointer: packU64(this.pointer.value),
+ pointer: pack64(this.pointer.value),
def: this.definition,
parameters,
buffers,
@@ -208,7 +233,7 @@
return promise;
} else {
const result = core.opSync("op_ffi_call_ptr", {
- pointer: packU64(this.pointer.value),
+ pointer: pack64(this.pointer.value),
def: this.definition,
parameters,
buffers,
@@ -268,8 +293,10 @@
);
continue;
}
+
const isNonBlocking = symbols[symbol].nonblocking;
const types = symbols[symbol].parameters;
+ const resultType = symbols[symbol].result;
const fn = (...args) => {
const { parameters, buffers } = prepareArgs(types, args);
@@ -282,10 +309,8 @@
buffers,
});
- if (symbols[symbol].result === "pointer") {
- return promise.then((value) =>
- new UnsafePointer(unpackU64(value))
- );
+ if (resultType === "pointer") {
+ return promise.then((result) => unpackResult(resultType, result));
}
return promise;
@@ -297,11 +322,7 @@
buffers,
});
- if (symbols[symbol].result === "pointer") {
- return new UnsafePointer(unpackU64(result));
- }
-
- return result;
+ return unpackResult(resultType, result);
}
};
diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs
index 01aa17698..8a1a75b1d 100644
--- a/ext/ffi/lib.rs
+++ b/ext/ffi/lib.rs
@@ -311,6 +311,11 @@ impl NativeValue {
}
fn value_as_uint<T: TryFrom<u64>>(value: Value) -> Result<T, AnyError> {
+ if value.is_array() {
+ let value = U32x2::try_from(value)?;
+ return T::try_from(u64::from(value)).map_err(|_| type_error(format!("Found U32x2 FFI argument but it could not be converted to an unsigned integer, got {:?}", value)));
+ }
+
match value.as_u64().and_then(|v| T::try_from(v).ok()) {
Some(value) => Ok(value),
None => Err(type_error(format!(
@@ -321,6 +326,11 @@ fn value_as_uint<T: TryFrom<u64>>(value: Value) -> Result<T, AnyError> {
}
fn value_as_int<T: TryFrom<i64>>(value: Value) -> Result<T, AnyError> {
+ if value.is_array() {
+ let value = U32x2::try_from(value)?;
+ return T::try_from(u64::from(value) as i64).map_err(|_| type_error(format!("Found U32x2 FFI argument but it could not be converted to a signed integer, got {:?}", value)));
+ }
+
match value.as_i64().and_then(|v| T::try_from(v).ok()) {
Some(value) => Ok(value),
None => Err(type_error(format!(
@@ -359,6 +369,25 @@ impl From<U32x2> for u64 {
}
}
+impl TryFrom<Value> for U32x2 {
+ type Error = AnyError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ if let Some(value) = value.as_array() {
+ if let Some(hi) = value[0].as_u64() {
+ if let Some(lo) = value[1].as_u64() {
+ return Ok(U32x2(hi as u32, lo as u32));
+ }
+ }
+ }
+
+ Err(type_error(format!(
+ "Expected FFI argument to be a signed integer, but got {:?}",
+ value
+ )))
+ }
+}
+
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct ForeignFunction {
@@ -627,16 +656,24 @@ fn ffi_call(args: FfiCallArgs, symbol: &Symbol) -> Result<Value, AnyError> {
json!(unsafe { symbol.cif.call::<i32>(symbol.ptr, &call_args) })
}
NativeType::U64 => {
- json!(unsafe { symbol.cif.call::<u64>(symbol.ptr, &call_args) })
+ json!(U32x2::from(unsafe {
+ symbol.cif.call::<u64>(symbol.ptr, &call_args)
+ }))
}
NativeType::I64 => {
- json!(unsafe { symbol.cif.call::<i64>(symbol.ptr, &call_args) })
+ json!(U32x2::from(unsafe {
+ symbol.cif.call::<i64>(symbol.ptr, &call_args)
+ } as u64))
}
NativeType::USize => {
- json!(unsafe { symbol.cif.call::<usize>(symbol.ptr, &call_args) })
+ json!(U32x2::from(unsafe {
+ symbol.cif.call::<usize>(symbol.ptr, &call_args)
+ } as u64))
}
NativeType::ISize => {
- json!(unsafe { symbol.cif.call::<isize>(symbol.ptr, &call_args) })
+ json!(U32x2::from(unsafe {
+ symbol.cif.call::<isize>(symbol.ptr, &call_args)
+ } as u64))
}
NativeType::F32 => {
json!(unsafe { symbol.cif.call::<f32>(symbol.ptr, &call_args) })
diff --git a/test_ffi/tests/ffi_types.ts b/test_ffi/tests/ffi_types.ts
index 0aab6a8fa..9ad51e67c 100644
--- a/test_ffi/tests/ffi_types.ts
+++ b/test_ffi/tests/ffi_types.ts
@@ -45,7 +45,7 @@ const remote = Deno.dlopen(
remote.symbols.method1(0);
// @ts-expect-error: Invalid return type
<number> remote.symbols.method1(0, 0);
-<void> remote.symbols.method1(0, 0);
+<void> remote.symbols.method1(0n, 0n);
// @ts-expect-error: Invalid argument
remote.symbols.method2(null);
@@ -53,11 +53,11 @@ remote.symbols.method2(void 0);
// @ts-expect-error: Invalid argument
remote.symbols.method3(null);
-remote.symbols.method3(0);
+remote.symbols.method3(0n);
// @ts-expect-error: Invalid argument
remote.symbols.method4(null);
-remote.symbols.method4(0);
+remote.symbols.method4(0n);
// @ts-expect-error: Invalid argument
remote.symbols.method5(null);
@@ -73,7 +73,7 @@ remote.symbols.method7(0);
// @ts-expect-error: Invalid argument
remote.symbols.method8(null);
-remote.symbols.method8(0);
+remote.symbols.method8(0n);
// @ts-expect-error: Invalid argument
remote.symbols.method9(null);
@@ -89,7 +89,7 @@ remote.symbols.method11(0);
// @ts-expect-error: Invalid argument
remote.symbols.method12(null);
-remote.symbols.method12(0);
+remote.symbols.method12(0n);
// @ts-expect-error: Invalid argument
remote.symbols.method13(null);
@@ -107,12 +107,12 @@ remote.symbols.method15({} as Deno.UnsafePointer);
const result = remote.symbols.method16();
// @ts-expect-error: Invalid argument
let r_0: string = result;
-let r_1: number = result;
+let r_1: number | bigint = result;
const result2 = remote.symbols.method17();
// @ts-expect-error: Invalid argument
result2.then((_0: string) => {});
-result2.then((_1: number) => {});
+result2.then((_1: number | bigint) => {});
const result3 = remote.symbols.method18();
// @ts-expect-error: Invalid argument
@@ -138,16 +138,16 @@ fnptr.call(0, null);
// @ts-expect-error: Invalid member type
const static1_wrong: null = remote.symbols.static1;
-const static1_right: number = remote.symbols.static1;
+const static1_right: bigint = remote.symbols.static1;
// @ts-expect-error: Invalid member type
const static2_wrong: null = remote.symbols.static2;
const static2_right: Deno.UnsafePointer = remote.symbols.static2;
// @ts-expect-error: Invalid member type
const static3_wrong: null = remote.symbols.static3;
-const static3_right: number = remote.symbols.static3;
+const static3_right: bigint = remote.symbols.static3;
// @ts-expect-error: Invalid member type
const static4_wrong: null = remote.symbols.static4;
-const static4_right: number = remote.symbols.static4;
+const static4_right: bigint = remote.symbols.static4;
// @ts-expect-error: Invalid member type
const static5_wrong: null = remote.symbols.static5;
const static5_right: number = remote.symbols.static5;
@@ -159,7 +159,7 @@ const static7_wrong: null = remote.symbols.static7;
const static7_right: number = remote.symbols.static7;
// @ts-expect-error: Invalid member type
const static8_wrong: null = remote.symbols.static8;
-const static8_right: number = remote.symbols.static8;
+const static8_right: bigint = remote.symbols.static8;
// @ts-expect-error: Invalid member type
const static9_wrong: null = remote.symbols.static9;
const static9_right: number = remote.symbols.static9;
@@ -171,7 +171,7 @@ const static11_wrong: null = remote.symbols.static11;
const static11_right: number = remote.symbols.static11;
// @ts-expect-error: Invalid member type
const static12_wrong: null = remote.symbols.static12;
-const static12_right: number = remote.symbols.static12;
+const static12_right: bigint = remote.symbols.static12;
// @ts-expect-error: Invalid member type
const static13_wrong: null = remote.symbols.static13;
const static13_right: number = remote.symbols.static13;
diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs
index fea5b5fbd..5b9bb2fc2 100644
--- a/test_ffi/tests/integration_tests.rs
+++ b/test_ffi/tests/integration_tests.rs
@@ -59,10 +59,10 @@ fn basic() {
true\n\
579\n\
579\n\
- 579\n\
- 579\n\
- 579\n\
- 579\n\
+ 8589934590n\n\
+ -8589934590n\n\
+ 8589934590n\n\
+ -8589934590n\n\
579.9119873046875\n\
579.912\n\
After sleep_blocking\n\
diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js
index 943f86ae8..b89dca648 100644
--- a/test_ffi/tests/test.js
+++ b/test_ffi/tests/test.js
@@ -145,10 +145,10 @@ assertThrows(
"Expected FFI argument to be an unsigned integer, but got Null",
);
console.log(dylib.symbols.add_i32(123, 456));
-console.log(dylib.symbols.add_u64(123, 456));
-console.log(dylib.symbols.add_i64(123, 456));
-console.log(dylib.symbols.add_usize(123, 456));
-console.log(dylib.symbols.add_isize(123, 456));
+console.log(dylib.symbols.add_u64(0xffffffffn, 0xffffffffn));
+console.log(dylib.symbols.add_i64(-0xffffffffn, -0xffffffffn));
+console.log(dylib.symbols.add_usize(0xffffffffn, 0xffffffffn));
+console.log(dylib.symbols.add_isize(-0xffffffffn, -0xffffffffn));
console.log(dylib.symbols.add_f32(123.123, 456.789));
console.log(dylib.symbols.add_f64(123.123, 456.789));