From ae0ca8dd25ce91b7775fde71337248443abc7d64 Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:23:45 -0700 Subject: [PATCH] ffi: preserve uint8 semantics for bool fast calls Normalize bool to kUint8 when creating Fast API metadata. This keeps optimized calls consistent with generic FFI behavior, including numeric return values and rejection of JavaScript Boolean values. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.6-sol --- doc/contributing/ffi-fast-api-internals.md | 4 ++-- src/ffi/fast.cc | 4 +--- src/ffi/fast.h | 1 - src/ffi/platforms/arm64.cc | 1 - src/ffi/platforms/loong64.cc | 1 - src/ffi/platforms/ppc64.cc | 1 - src/ffi/platforms/riscv64.cc | 1 - src/ffi/platforms/s390x.cc | 1 - src/ffi/platforms/x64.cc | 4 ---- test/ffi/test-ffi-calls.js | 14 +++++++++++--- 10 files changed, 14 insertions(+), 18 deletions(-) diff --git a/doc/contributing/ffi-fast-api-internals.md b/doc/contributing/ffi-fast-api-internals.md index 280fa44251199a..478d7c493f4952 100644 --- a/doc/contributing/ffi-fast-api-internals.md +++ b/doc/contributing/ffi-fast-api-internals.md @@ -200,7 +200,6 @@ surface. It models the ABI categories that the generated trampoline knows how to marshal directly: * `kVoid` -* `kBool` * signed and unsigned 8-bit, 16-bit, 32-bit, and 64-bit integers * `kFloat32` * `kFloat64` @@ -208,7 +207,8 @@ marshal directly: * `kBuffer` Public aliases are normalized in `FastScalarTypeFromName()` and -`FastArgTypeFromName()`. +`FastArgTypeFromName()`. In particular, `bool` is normalized to `kUint8` to +match its documented 8-bit unsigned integer semantics. `pointer`, `ptr`, `string`, `str`, `buffer`, and `arraybuffer` all represent pointer-sized native values at the target ABI boundary. They differ in how diff --git a/src/ffi/fast.cc b/src/ffi/fast.cc index 13c039c0da3f17..105de8c1e755e7 100644 --- a/src/ffi/fast.cc +++ b/src/ffi/fast.cc @@ -37,7 +37,7 @@ bool FastScalarTypeFromName(std::string_view type, FastFFIType* out) { if (type == "void") { *out = FastFFIType::kVoid; } else if (type == "bool") { - *out = FastFFIType::kBool; + *out = FastFFIType::kUint8; } else if (IsTypeName(type, {"i8", "int8"})) { *out = FastFFIType::kInt8; } else if (IsTypeName(type, {"u8", "uint8"})) { @@ -96,8 +96,6 @@ CTypeInfo::Type ToV8Type(FastFFIType type, bool is_return) { switch (type) { case FastFFIType::kVoid: return CTypeInfo::Type::kVoid; - case FastFFIType::kBool: - return CTypeInfo::Type::kBool; case FastFFIType::kUint8: return CTypeInfo::Type::kUint32; case FastFFIType::kInt8: diff --git a/src/ffi/fast.h b/src/ffi/fast.h index bd0a2bac88f824..1330e3b68958ba 100644 --- a/src/ffi/fast.h +++ b/src/ffi/fast.h @@ -17,7 +17,6 @@ struct FFIFunction; enum class FastFFIType : uint8_t { kVoid, - kBool, kInt8, kUint8, kInt16, diff --git a/src/ffi/platforms/arm64.cc b/src/ffi/platforms/arm64.cc index ccb7a8cf3d04ff..a3132966b560bb 100644 --- a/src/ffi/platforms/arm64.cc +++ b/src/ffi/platforms/arm64.cc @@ -136,7 +136,6 @@ uint32_t UxthW(unsigned reg) { // to the ABI width expected by the native target before the final call. bool EmitNarrow(uint32_t** cursor, FastFFIType type, unsigned reg) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kUint8: *(*cursor)++ = UxtbW(reg); return true; diff --git a/src/ffi/platforms/loong64.cc b/src/ffi/platforms/loong64.cc index 9b3bd5dfd90102..6bc90358cfcaa1 100644 --- a/src/ffi/platforms/loong64.cc +++ b/src/ffi/platforms/loong64.cc @@ -19,7 +19,6 @@ bool IsFloatType(FastFFIType type) { bool IsNarrowType(FastFFIType type) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kInt8: case FastFFIType::kUint8: case FastFFIType::kInt16: diff --git a/src/ffi/platforms/ppc64.cc b/src/ffi/platforms/ppc64.cc index 4549b98186f5e7..a0a53cfdb44363 100644 --- a/src/ffi/platforms/ppc64.cc +++ b/src/ffi/platforms/ppc64.cc @@ -23,7 +23,6 @@ bool IsFloatType(FastFFIType type) { bool IsNarrowType(FastFFIType type) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kInt8: case FastFFIType::kUint8: case FastFFIType::kInt16: diff --git a/src/ffi/platforms/riscv64.cc b/src/ffi/platforms/riscv64.cc index 306dd5bbce77c4..0497f38619a8d5 100644 --- a/src/ffi/platforms/riscv64.cc +++ b/src/ffi/platforms/riscv64.cc @@ -19,7 +19,6 @@ bool IsFloatType(FastFFIType type) { bool IsNarrowType(FastFFIType type) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kInt8: case FastFFIType::kUint8: case FastFFIType::kInt16: diff --git a/src/ffi/platforms/s390x.cc b/src/ffi/platforms/s390x.cc index 2d8a0c0bea7cb6..dd8606de82bcaf 100644 --- a/src/ffi/platforms/s390x.cc +++ b/src/ffi/platforms/s390x.cc @@ -19,7 +19,6 @@ bool IsFloatType(FastFFIType type) { bool IsNarrowType(FastFFIType type) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kInt8: case FastFFIType::kUint8: case FastFFIType::kInt16: diff --git a/src/ffi/platforms/x64.cc b/src/ffi/platforms/x64.cc index 1073508d365b18..51de3c5452f33a 100644 --- a/src/ffi/platforms/x64.cc +++ b/src/ffi/platforms/x64.cc @@ -232,7 +232,6 @@ void EmitNarrowInstruction(uint8_t** cursor, uint8_t opcode, unsigned reg) { // consumes the declared low 8/16 bits. bool EmitNarrowReturn(uint8_t** cursor, FastFFIType type, unsigned reg) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kUint8: EmitNarrowInstruction(cursor, 0xb6, reg); return true; @@ -252,7 +251,6 @@ bool EmitNarrowReturn(uint8_t** cursor, FastFFIType type, unsigned reg) { bool NeedsNarrow(FastFFIType type) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kUint8: case FastFFIType::kInt8: case FastFFIType::kUint16: @@ -655,7 +653,6 @@ void EmitNarrowInstruction(uint8_t** cursor, uint8_t opcode, unsigned reg) { bool EmitNarrowReturn(uint8_t** cursor, FastFFIType type, unsigned reg) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kUint8: EmitNarrowInstruction(cursor, 0xb6, reg); return true; @@ -675,7 +672,6 @@ bool EmitNarrowReturn(uint8_t** cursor, FastFFIType type, unsigned reg) { bool NeedsNarrow(FastFFIType type) { switch (type) { - case FastFFIType::kBool: case FastFFIType::kUint8: case FastFFIType::kInt8: case FastFFIType::kUint16: diff --git a/test/ffi/test-ffi-calls.js b/test/ffi/test-ffi-calls.js index 192fa74fa3fbed..e966809de666d1 100644 --- a/test/ffi/test-ffi-calls.js +++ b/test/ffi/test-ffi-calls.js @@ -1,4 +1,4 @@ -// Flags: --experimental-ffi --expose-gc +// Flags: --experimental-ffi --expose-gc --allow-natives-syntax 'use strict'; const common = require('../common'); common.skipIfFFIMissing(); @@ -62,8 +62,16 @@ test('ffi bool signatures use uint8 values', () => { arguments: ['bool', 'bool'], return: 'bool', }); - assert.strictEqual(boolAdder(1, 0), 1); - assert.throws(() => boolAdder(true, false), /Argument 0 must be a uint8/); + function callBoolAdder(a, b) { + return boolAdder(a, b); + } + + eval('%PrepareFunctionForOptimization(callBoolAdder)'); + assert.strictEqual(callBoolAdder(1, 0), 1); + eval('%OptimizeFunctionOnNextCall(callBoolAdder)'); + assert.strictEqual(callBoolAdder(1, 0), 1); + assert.throws( + () => callBoolAdder(true, false), /Argument 0 must be a uint8/); } finally { lib.close(); }