FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

ffi: prefer canonical type names · nodejs/node@7670c81 · GitHub

/ node Public

Commit 7670c81

Browse files
authored andcommitted
ffi: prefer canonical type names
Document long type names as canonical and use them in examples. Group alternative spellings separately in the documentation and internal type maps while retaining support for every existing alias. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: codex:gpt-5.6-sol PR-URL: #65417 Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Aviv Keller <me@aviv.sh> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
1 parent eb1ebbb commit 7670c81

5 files changed

Lines changed: 115 additions & 94 deletions

File tree

‎doc/api/ffi.md‎

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,40 @@ Supported type names:
6363

6464
* `void`
6565
* `char`
66-
* `i8`, `int8`
67-
* `u8`, `uint8`, `bool`
68-
* `i16`, `int16`
69-
* `u16`, `uint16`
70-
* `i32`, `int32`
71-
* `u32`, `uint32`
72-
* `i64`, `int64`
73-
* `u64`, `uint64`
74-
* `f32`, `float`, `float32`
75-
* `f64`, `double`, `float64`
76-
* `pointer`, `ptr`
77-
* `string`, `str`
66+
* `int8`
67+
* `uint8`
68+
* `int16`
69+
* `uint16`
70+
* `int32`
71+
* `uint32`
72+
* `int64`
73+
* `uint64`
74+
* `float32`
75+
* `float64`
76+
* `pointer`
77+
* `string`
7878
* `buffer`
7979
* `arraybuffer`
8080
* `function`
8181

82+
<details>
83+
<summary>Alternative spellings</summary>
84+
85+
* `i8` for `int8`
86+
* `u8` and `bool` for `uint8`
87+
* `i16` for `int16`
88+
* `u16` for `uint16`
89+
* `i32` for `int32`
90+
* `u32` for `uint32`
91+
* `i64` for `int64`
92+
* `u64` for `uint64`
93+
* `f32` and `float` for `float32`
94+
* `f64` and `double` for `float64`
95+
* `ptr` for `pointer`
96+
* `str` for `string`
97+
98+
</details>
99+
82100
These type names are also exposed as constants on `ffi.types`:
83101

84102
* `ffi.types.VOID` = `'void'`
@@ -116,15 +134,15 @@ through reentrant JavaScript such as FFI callbacks. Doing so may crash the
116134
process, produce incorrect output, or corrupt memory.
117135

118136
The `char` type follows the platform C ABI. On platforms where plain C `char`
119-
is signed it behaves like `i8`; otherwise it behaves like `u8`.
137+
is signed it behaves like `int8`; otherwise it behaves like `uint8`.
120138

121139
The `bool` type is marshaled as an 8-bit unsigned integer. Pass numeric values
122140
such as `0` and `1`; JavaScript `true` and `false` are not accepted.
123141

124-
On optimized Fast FFI calls, `pointer`, `ptr`, and `function` parameters accept
125-
raw pointer `bigint` values. For pointer-like parameters, `null`, `undefined`,
126-
strings, `Buffer`, typed array, `DataView`, and `ArrayBuffer` values are
127-
converted on the JavaScript side before calling the optimized native wrapper.
142+
On optimized Fast FFI calls, `pointer` and `function` parameters accept raw
143+
pointer `bigint` values. For pointer-like parameters, `null`, `undefined`,
144+
strings, `Buffer`, typed array, `DataView`, and `ArrayBuffer` values are converted
145+
on the JavaScript side before calling the optimized native wrapper.
128146

129147
Optimized Fast FFI calls fall back to the generic FFI call path when a
130148
function's arguments or return type do not fit the platform-specific fast
@@ -161,8 +179,8 @@ optional:
161179

162180
```js
163181
const signature = {
164-
return: 'i32',
165-
arguments: ['i32', 'i32'],
182+
return: 'int32',
183+
arguments: ['int32', 'int32'],
166184
};
167185
```
168186

@@ -220,7 +238,7 @@ import { dlopen, suffix } from 'node:ffi';
220238

221239
{
222240
using handle = dlopen(`./mylib.${suffix}`, {
223-
add_i32: { arguments: ['i32', 'i32'], return: 'i32' },
241+
add_i32: { arguments: ['int32', 'int32'], return: 'int32' },
224242
});
225243
console.log(handle.functions.add_i32(20, 22));
226244
} // handle.lib.close() is invoked automatically here.
@@ -230,8 +248,8 @@ import { dlopen, suffix } from 'node:ffi';
230248
import { dlopen, suffix } from 'node:ffi';
231249

232250
const { lib, functions } = dlopen(`./mylib.${suffix}`, {
233-
add_i32: { arguments: ['i32', 'i32'], return: 'i32' },
234-
string_length: { arguments: ['pointer'], return: 'u64' },
251+
add_i32: { arguments: ['int32', 'int32'], return: 'int32' },
252+
string_length: { arguments: ['pointer'], return: 'uint64' },
235253
});
236254

237255
console.log(functions.add_i32(20, 22));
@@ -241,8 +259,8 @@ console.log(functions.add_i32(20, 22));
241259
const { dlopen, suffix } = require('node:ffi');
242260

243261
const { lib, functions } = dlopen(`./mylib.${suffix}`, {
244-
add_i32: { arguments: ['i32', 'i32'], return: 'i32' },
245-
string_length: { arguments: ['pointer'], return: 'u64' },
262+
add_i32: { arguments: ['int32', 'int32'], return: 'int32' },
263+
string_length: { arguments: ['pointer'], return: 'uint64' },
246264
});
247265

248266
console.log(functions.add_i32(20, 22));
@@ -384,8 +402,8 @@ const { DynamicLibrary, suffix } = require('node:ffi');
384402

385403
const lib = new DynamicLibrary(`./mylib.${suffix}`);
386404
const add = lib.getFunction('add_i32', {
387-
arguments: ['i32', 'i32'],
388-
return: 'i32',
405+
arguments: ['int32', 'int32'],
406+
return: 'int32',
389407
});
390408

391409
console.log(add(20, 22));
@@ -435,7 +453,7 @@ const { DynamicLibrary, suffix } = require('node:ffi');
435453
const lib = new DynamicLibrary(`./mylib.${suffix}`);
436454

437455
const callback = lib.registerCallback(
438-
{ arguments: ['i32'], return: 'i32' },
456+
{ arguments: ['int32'], return: 'int32' },
439457
(value) => value * 2,
440458
);
441459
```
@@ -498,7 +516,8 @@ Argument conversion depends on the declared FFI type.
498516
For 8-, 16-, and 32-bit integer types and for floating-point types, pass
499517
JavaScript `number` values that match the declared type.
500518

501-
For 64-bit integer types (`i64` and `u64`), pass JavaScript `bigint` values.
519+
For 64-bit integer types (`int64` and `uint64`), pass JavaScript `bigint`
520+
values.
502521

503522
For pointer-like arguments:
504523

‎lib/internal/ffi-shared-buffer.js‎

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,38 +64,40 @@ const gF64 = DataViewPrototypeGetFloat64;
6464

6565
const sbTypeInfo = {
6666
__proto__: null,
67-
i8: { set: sI8, get: gI8, kind: 'int', min: -128, max: 127, label: 'an int8' },
68-
int8: { set: sI8, get: gI8, kind: 'int', min: -128, max: 127, label: 'an int8' },
6967
char: charIsSigned ?
7068
{ set: sI8, get: gI8, kind: 'int', min: -128, max: 127, label: 'an int8' } :
7169
{ set: sU8, get: gU8, kind: 'int', min: 0, max: 255, label: 'a uint8' },
72-
u8: { set: sU8, get: gU8, kind: 'int', min: 0, max: 255, label: 'a uint8' },
70+
int8: { set: sI8, get: gI8, kind: 'int', min: -128, max: 127, label: 'an int8' },
7371
uint8: { set: sU8, get: gU8, kind: 'int', min: 0, max: 255, label: 'a uint8' },
72+
int16: { set: sI16, get: gI16, kind: 'int', min: -32768, max: 32767, label: 'an int16' },
73+
uint16: { set: sU16, get: gU16, kind: 'int', min: 0, max: 65535, label: 'a uint16' },
74+
int32: { set: sI32, get: gI32, kind: 'int', min: -2147483648, max: 2147483647, label: 'an int32' },
75+
uint32: { set: sU32, get: gU32, kind: 'int', min: 0, max: 4294967295, label: 'a uint32' },
76+
int64: { set: sI64, get: gI64, kind: 'i64', label: 'an int64' },
77+
uint64: { set: sU64, get: gU64, kind: 'u64', label: 'a uint64' },
78+
float32: { set: sF32, get: gF32, kind: 'float', label: 'a float' },
79+
float64: { set: sF64, get: gF64, kind: 'float', label: 'a double' },
80+
pointer: { set: sU64, get: gU64, kind: 'pointer' },
81+
string: { set: sU64, get: gU64, kind: 'pointer' },
82+
buffer: { set: sU64, get: gU64, kind: 'pointer' },
83+
arraybuffer: { set: sU64, get: gU64, kind: 'pointer' },
84+
function: { set: sU64, get: gU64, kind: 'pointer' },
85+
86+
// Alternative spellings.
87+
i8: { set: sI8, get: gI8, kind: 'int', min: -128, max: 127, label: 'an int8' },
88+
u8: { set: sU8, get: gU8, kind: 'int', min: 0, max: 255, label: 'a uint8' },
7489
bool: { set: sU8, get: gU8, kind: 'int', min: 0, max: 255, label: 'a uint8' },
7590
i16: { set: sI16, get: gI16, kind: 'int', min: -32768, max: 32767, label: 'an int16' },
76-
int16: { set: sI16, get: gI16, kind: 'int', min: -32768, max: 32767, label: 'an int16' },
7791
u16: { set: sU16, get: gU16, kind: 'int', min: 0, max: 65535, label: 'a uint16' },
78-
uint16: { set: sU16, get: gU16, kind: 'int', min: 0, max: 65535, label: 'a uint16' },
7992
i32: { set: sI32, get: gI32, kind: 'int', min: -2147483648, max: 2147483647, label: 'an int32' },
80-
int32: { set: sI32, get: gI32, kind: 'int', min: -2147483648, max: 2147483647, label: 'an int32' },
8193
u32: { set: sU32, get: gU32, kind: 'int', min: 0, max: 4294967295, label: 'a uint32' },
82-
uint32: { set: sU32, get: gU32, kind: 'int', min: 0, max: 4294967295, label: 'a uint32' },
8394
i64: { set: sI64, get: gI64, kind: 'i64', label: 'an int64' },
84-
int64: { set: sI64, get: gI64, kind: 'i64', label: 'an int64' },
8595
u64: { set: sU64, get: gU64, kind: 'u64', label: 'a uint64' },
86-
uint64: { set: sU64, get: gU64, kind: 'u64', label: 'a uint64' },
8796
f32: { set: sF32, get: gF32, kind: 'float', label: 'a float' },
8897
float: { set: sF32, get: gF32, kind: 'float', label: 'a float' },
89-
float32: { set: sF32, get: gF32, kind: 'float', label: 'a float' },
9098
f64: { set: sF64, get: gF64, kind: 'float', label: 'a double' },
9199
double: { set: sF64, get: gF64, kind: 'float', label: 'a double' },
92-
float64: { set: sF64, get: gF64, kind: 'float', label: 'a double' },
93-
pointer: { set: sU64, get: gU64, kind: 'pointer' },
94100
ptr: { set: sU64, get: gU64, kind: 'pointer' },
95-
function: { set: sU64, get: gU64, kind: 'pointer' },
96-
buffer: { set: sU64, get: gU64, kind: 'pointer' },
97-
arraybuffer: { set: sU64, get: gU64, kind: 'pointer' },
98-
string: { set: sU64, get: gU64, kind: 'pointer' },
99101
str: { set: sU64, get: gU64, kind: 'pointer' },
100102
};
101103

‎lib/internal/ffi/fast-api.js‎

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,28 @@ const fastLibraryStates = new SafeWeakMap();
4747
// conversions, so the public FFI ranges must be checked before the raw call.
4848
const fastIntegerTypeInfo = {
4949
__proto__: null,
50-
i8: { kind: 'number', min: -128, max: 127, label: 'an int8' },
51-
int8: { kind: 'number', min: -128, max: 127, label: 'an int8' },
5250
char: charIsSigned ?
5351
{ kind: 'number', min: -128, max: 127, label: 'an int8' } :
5452
{ kind: 'number', min: 0, max: 255, label: 'a uint8' },
55-
u8: { kind: 'number', min: 0, max: 255, label: 'a uint8' },
53+
int8: { kind: 'number', min: -128, max: 127, label: 'an int8' },
5654
uint8: { kind: 'number', min: 0, max: 255, label: 'a uint8' },
55+
int16: { kind: 'number', min: -32768, max: 32767, label: 'an int16' },
56+
uint16: { kind: 'number', min: 0, max: 65535, label: 'a uint16' },
57+
int32: { kind: 'number', min: -2147483648, max: 2147483647, label: 'an int32' },
58+
uint32: { kind: 'number', min: 0, max: 4294967295, label: 'a uint32' },
59+
int64: { kind: 'bigint', min: I64_MIN, max: I64_MAX, label: 'an int64' },
60+
uint64: { kind: 'bigint', min: 0n, max: U64_MAX, label: 'a uint64' },
61+
62+
// Alternative spellings.
63+
i8: { kind: 'number', min: -128, max: 127, label: 'an int8' },
64+
u8: { kind: 'number', min: 0, max: 255, label: 'a uint8' },
5765
bool: { kind: 'number', min: 0, max: 255, label: 'a uint8' },
5866
i16: { kind: 'number', min: -32768, max: 32767, label: 'an int16' },
59-
int16: { kind: 'number', min: -32768, max: 32767, label: 'an int16' },
6067
u16: { kind: 'number', min: 0, max: 65535, label: 'a uint16' },
61-
uint16: { kind: 'number', min: 0, max: 65535, label: 'a uint16' },
6268
i32: { kind: 'number', min: -2147483648, max: 2147483647, label: 'an int32' },
63-
int32: { kind: 'number', min: -2147483648, max: 2147483647, label: 'an int32' },
6469
u32: { kind: 'number', min: 0, max: 4294967295, label: 'a uint32' },
65-
uint32: { kind: 'number', min: 0, max: 4294967295, label: 'a uint32' },
6670
i64: { kind: 'bigint', min: I64_MIN, max: I64_MAX, label: 'an int64' },
67-
int64: { kind: 'bigint', min: I64_MIN, max: I64_MAX, label: 'an int64' },
6871
u64: { kind: 'bigint', min: 0n, max: U64_MAX, label: 'a uint64' },
69-
uint64: { kind: 'bigint', min: 0n, max: U64_MAX, label: 'a uint64' },
7072
};
7173

7274
function throwFFIArgError(msg) {
@@ -97,8 +99,8 @@ function needsRawPointerConversion(type) {
9799
}
98100

99101
function needsPointerLikeConversion(type) {
100-
return type === 'pointer' || type === 'ptr' || type === 'function' ||
101-
type === 'buffer' || type === 'arraybuffer';
102+
return type === 'pointer' || type === 'function' || type === 'buffer' ||
103+
type === 'arraybuffer' || type === 'ptr';
102104
}
103105

104106
function needsStringPointerConversion(type) {

‎src/ffi/fast.cc‎

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,34 +36,32 @@ bool FastScalarTypeFromName(std::string_view type, FastFFIType* out) {
3636
// JavaScript wrappers handle strings and object-to-pointer conversions.
3737
if (type == "void") {
3838
*out = FastFFIType::kVoid;
39-
} else if (type == "bool") {
40-
*out = FastFFIType::kUint8;
41-
} else if (IsTypeName(type, {"i8", "int8"})) {
42-
*out = FastFFIType::kInt8;
43-
} else if (IsTypeName(type, {"u8", "uint8"})) {
44-
*out = FastFFIType::kUint8;
4539
} else if (type == "char") {
4640
*out = CHAR_MIN < 0 ? FastFFIType::kInt8 : FastFFIType::kUint8;
47-
} else if (IsTypeName(type, {"i16", "int16"})) {
41+
} else if (IsTypeName(type, {"int8", "i8"})) {
42+
*out = FastFFIType::kInt8;
43+
} else if (IsTypeName(type, {"uint8", "u8", "bool"})) {
44+
*out = FastFFIType::kUint8;
45+
} else if (IsTypeName(type, {"int16", "i16"})) {
4846
*out = FastFFIType::kInt16;
49-
} else if (IsTypeName(type, {"u16", "uint16"})) {
47+
} else if (IsTypeName(type, {"uint16", "u16"})) {
5048
*out = FastFFIType::kUint16;
51-
} else if (IsTypeName(type, {"i32", "int32"})) {
49+
} else if (IsTypeName(type, {"int32", "i32"})) {
5250
*out = FastFFIType::kInt32;
53-
} else if (IsTypeName(type, {"u32", "uint32"})) {
51+
} else if (IsTypeName(type, {"uint32", "u32"})) {
5452
*out = FastFFIType::kUint32;
55-
} else if (IsTypeName(type, {"i64", "int64"})) {
53+
} else if (IsTypeName(type, {"int64", "i64"})) {
5654
*out = FastFFIType::kInt64;
57-
} else if (IsTypeName(type, {"u64", "uint64"})) {
55+
} else if (IsTypeName(type, {"uint64", "u64"})) {
5856
*out = FastFFIType::kUint64;
59-
} else if (IsTypeName(type, {"f32", "float", "float32"})) {
57+
} else if (IsTypeName(type, {"float32", "f32", "float"})) {
6058
*out = FastFFIType::kFloat32;
61-
} else if (IsTypeName(type, {"f64", "double", "float64"})) {
59+
} else if (IsTypeName(type, {"float64", "f64", "double"})) {
6260
*out = FastFFIType::kFloat64;
6361
} else if (IsTypeName(type, {"buffer", "arraybuffer"})) {
6462
*out = FastFFIType::kPointer;
6563
} else if (IsTypeName(type,
66-
{"pointer", "ptr", "string", "str", "function"})) {
64+
{"pointer", "string", "function", "ptr", "str"})) {
6765
*out = FastFFIType::kPointer;
6866
} else {
6967
return false;
@@ -162,11 +160,12 @@ bool SignatureNeedsFastIntegerValidation(const FFIFunction& fn) {
162160
// V8 widens narrow integers to 32 bits and truncates BigInts to 64 bits for
163161
// Fast API calls. These types need a JS range check before the trampoline.
164162
for (const std::string& name : fn.arg_type_names) {
165-
if (name == "bool" || name == "char" || name == "i8" || name == "int8" ||
166-
name == "u8" || name == "uint8" || name == "i16" || name == "int16" ||
167-
name == "u16" || name == "uint16" || name == "i32" || name == "int32" ||
168-
name == "u32" || name == "uint32" || name == "i64" || name == "int64" ||
169-
name == "u64" || name == "uint64") {
163+
if (name == "char" || name == "int8" || name == "uint8" ||
164+
name == "int16" || name == "uint16" || name == "int32" ||
165+
name == "uint32" || name == "int64" || name == "uint64" ||
166+
name == "i8" || name == "u8" || name == "bool" || name == "i16" ||
167+
name == "u16" || name == "i32" || name == "u32" || name == "i64" ||
168+
name == "u64") {
170169
return true;
171170
}
172171
}
@@ -176,7 +175,7 @@ bool SignatureNeedsFastIntegerValidation(const FFIFunction& fn) {
176175
bool IsPointerTypeName(const std::string& name) {
177176
// `pointer`, `ptr`, and `function` all use the same uintptr ABI slot; only
178177
// the public type spelling differs.
179-
return name == "pointer" || name == "ptr" || name == "function";
178+
return name == "pointer" || name == "function" || name == "ptr";
180179
}
181180

182181
bool IsBufferTypeName(const std::string& name) {

‎src/ffi/types.cc‎

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -552,34 +552,33 @@ void WriteFFIReturnToBuffer(ffi_type* type,
552552
v8::Maybe<ffi_type*> ToFFIType(Environment* env, std::string_view type_str) {
553553
if (type_str == "void") {
554554
return Just(&ffi_type_void);
555-
} else if (type_str == "i8" || type_str == "int8") {
556-
return Just(&ffi_type_sint8);
557-
} else if (type_str == "u8" || type_str == "uint8" || type_str == "bool") {
558-
return Just(&ffi_type_uint8);
559555
} else if (type_str == "char") {
560556
return Just(CHAR_MIN < 0 ? &ffi_type_sint8 : &ffi_type_uint8);
561-
} else if (type_str == "i16" || type_str == "int16") {
557+
} else if (type_str == "int8" || type_str == "i8") {
558+
return Just(&ffi_type_sint8);
559+
} else if (type_str == "uint8" || type_str == "u8" || type_str == "bool") {
560+
return Just(&ffi_type_uint8);
561+
} else if (type_str == "int16" || type_str == "i16") {
562562
return Just(&ffi_type_sint16);
563-
} else if (type_str == "u16" || type_str == "uint16") {
563+
} else if (type_str == "uint16" || type_str == "u16") {
564564
return Just(&ffi_type_uint16);
565-
} else if (type_str == "i32" || type_str == "int32") {
565+
} else if (type_str == "int32" || type_str == "i32") {
566566
return Just(&ffi_type_sint32);
567-
} else if (type_str == "u32" || type_str == "uint32") {
567+
} else if (type_str == "uint32" || type_str == "u32") {
568568
return Just(&ffi_type_uint32);
569-
} else if (type_str == "i64" || type_str == "int64") {
569+
} else if (type_str == "int64" || type_str == "i64") {
570570
return Just(&ffi_type_sint64);
571-
} else if (type_str == "u64" || type_str == "uint64") {
571+
} else if (type_str == "uint64" || type_str == "u64") {
572572
return Just(&ffi_type_uint64);
573-
} else if (type_str == "f32" || type_str == "float" ||
574-
type_str == "float32") {
573+
} else if (type_str == "float32" || type_str == "f32" ||
574+
type_str == "float") {
575575
return Just(&ffi_type_float);
576-
} else if (type_str == "f64" || type_str == "double" ||
577-
type_str == "float64") {
576+
} else if (type_str == "float64" || type_str == "f64" ||
577+
type_str == "double") {
578578
return Just(&ffi_type_double);
579-
} else if (type_str == "buffer" || type_str == "arraybuffer" ||
580-
type_str == "string" || type_str == "str" ||
581-
type_str == "pointer" || type_str == "ptr" ||
582-
type_str == "function") {
579+
} else if (type_str == "pointer" || type_str == "string" ||
580+
type_str == "buffer" || type_str == "arraybuffer" ||
581+
type_str == "function" || type_str == "ptr" || type_str == "str") {
583582
return Just(&ffi_type_pointer);
584583
} else {
585584
THROW_ERR_INVALID_ARG_VALUE(env, "Unsupported FFI type: %s", type_str);

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL