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 280fa4425119..478d7c493f49 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 13c039c0da3f..105de8c1e755 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 bd0a2bac88f8..1330e3b68958 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 ccb7a8cf3d04..a3132966b560 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 9b3bd5dfd901..6bc90358cfca 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 4549b98186f5..a0a53cfdb443 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 306dd5bbce77..0497f38619a8 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 2d8a0c0bea7c..dd8606de82bc 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 1073508d365b..51de3c5452f3 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 192fa74fa3fb..e966809de666 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(); }