jcayzac
jcayzac2y ago

FFI how to pass (or get) 128-bit bigints to (or from) Rust functions?

I want to pass bigints from Deno and get i128 or u128 in Rust. Do I have to use typed arrays for that?
3 Replies
AapoAlas
AapoAlas2y ago
Yes. There is currently no "i128" / "u128" option in the FFI parameter / return value types, ie. we do not have a "natively supported" way to pass such arguments. Additionally, the libffi library Deno uses "under the hood" to implement the C API calls does not support 128 bit integer parameters, so I'm not sure if we even could support these directly. To a degree it's also a question of machine architecture and calling conventions: How are u128 and i128 passed as parameters? Are they passed in two integer registers (on a 64-bit machine)? Or are there special 128-bit registers that are utilized? (Answer seems to be two integer registers, but it may depend on the machine.) If you control both the JS and Rust side, then I do recommend using a Uint8Array for passing the data: It will be by far fastest that way as this gets to utilize the V8 Fast API path. ie.
const u128 = BigUint64Array(2);
const u128Param = new Uint8Array(u128.buffer); // Not a copy, but a reference
u128[0] = BigInt(235234568686);
u128[1] = BigInt(2363447347)
lib.symbols.call(u128Param);
const u128 = BigUint64Array(2);
const u128Param = new Uint8Array(u128.buffer); // Not a copy, but a reference
u128[0] = BigInt(235234568686);
u128[1] = BigInt(2363447347)
lib.symbols.call(u128Param);
and on Rust side:
extern "C" fn call(u128Param: *mut u128) {
printf("Got u128 from JavaScript: {}", unsafe { *u128Param });
}
extern "C" fn call(u128Param: *mut u128) {
printf("Got u128 from JavaScript: {}", unsafe { *u128Param });
}
divy
divy2y ago
It is not possible to safely pass i128 thru FFI https://github.com/rust-lang/rust/issues/54341
GitHub
i128 / u128 are not compatible with C's definition. · Issue #54341 ...
While fixing various bindgen bugs related to long double, int128, (rust-lang/rust-bindgen#1370, etc). I realized that the following Rust program, in my x86_64 Linux machine: #[repr(C)] struct Foo {...
divy
divy2y ago
you should convert it into 2 x 64 bit parts