Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions src/runtime/ffi/FFI.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ BUN_FFI_IMPORT extern struct NapiEnv Bun__thisFFIModuleNapiEnv;
#define TagValueNull (OtherTag)
#define NotCellMask (int64_t)(NumberTag | OtherTag)

#define MAX_INT32 2147483648
#define MAX_INT32 2147483647
#define MIN_INT32 (-MAX_INT32 - 1)
#define MAX_INT52 9007199254740991

// If all bits in the mask are set, this indicates an integer number,
Expand Down Expand Up @@ -248,16 +249,32 @@ static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
return res;
}

// ECMAScript ToInt32, ported from JSC's toIntImpl<int32_t> (MathCommon.h); ToUint32 is the same bits.
static int32_t JSVALUE_TO_INT32(EncodedJSValue val) {
if (JSVALUE_IS_INT32(val)) {
return (int32_t)val.asInt64;
}
// Decode a double-encoded integer (JIT tier-up, Math.* provenance, etc.);
// int64_t intermediate keeps u32 callers (uint32_t)JSVALUE_TO_INT32(...) defined.
if (val.asInt64 == TagValueTrue) {
return 1;
}
val.asInt64 -= DoubleEncodeOffset;
// NaN check also catches undefined/null/bool, whose decoded bits are all NaNs.
if (val.asDouble != val.asDouble) return 0;
return (int32_t)(int64_t)val.asDouble;
uint64_t bits = (uint64_t)val.asInt64;
int32_t exp = (int32_t)((bits >> 52) & 0x7ff) - 0x3ff;
// Also 0, NaN, +-Infinity, and false/undefined/null/cells, whose decoded bits are NaNs.
if (exp < 0 || exp > 83) {
return 0;
}
uint32_t result = exp > 52 ? (uint32_t)(bits << (exp - 52)) : (uint32_t)(bits >> (52 - exp));
if (exp < 32) {
// Reinsert the implicit leading 1; mask off the shifted-in sign/exponent bits.
uint32_t implicit_one = (uint32_t)1 << exp;
result &= implicit_one - 1;
result += implicit_one;
}
if (bits >> 63) {
result = -result;
}
return (int32_t)result;
}

static EncodedJSValue INT32_TO_JSVALUE(int32_t val) {
Expand Down Expand Up @@ -339,7 +356,7 @@ static int64_t JSVALUE_TO_INT64(EncodedJSValue value) {
}

static EncodedJSValue UINT64_TO_JSVALUE(void* jsGlobalObject, uint64_t val) {
if (val < MAX_INT32) {
if (val <= MAX_INT32) {
return INT32_TO_JSVALUE((int32_t)val);
}

Expand All @@ -351,7 +368,7 @@ static EncodedJSValue UINT64_TO_JSVALUE(void* jsGlobalObject, uint64_t val) {
}

static EncodedJSValue INT64_TO_JSVALUE(void* jsGlobalObject, int64_t val) {
if (val >= -MAX_INT32 && val <= MAX_INT32) {
if (val >= MIN_INT32 && val <= MAX_INT32) {
return INT32_TO_JSVALUE((int32_t)val);
}

Expand Down
14 changes: 0 additions & 14 deletions src/runtime/ffi/abi_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,20 +191,6 @@ impl ABIType {
})
}

/// Types that we can directly pass through as an `int64_t`
pub(crate) fn needs_a_cast_in_c(self) -> bool {
!matches!(
self,
ABIType::Char
| ABIType::Int8T
| ABIType::Uint8T
| ABIType::Int16T
| ABIType::Uint16T
| ABIType::Int32T
| ABIType::Uint32T
)
}

pub(crate) fn is_floating_point(self) -> bool {
matches!(self, ABIType::Double | ABIType::Float)
}
Expand Down
37 changes: 9 additions & 28 deletions src/runtime/ffi/ffi_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2165,32 +2165,17 @@ impl Function {
" napi_env arg{} = (napi_env)&Bun__thisFFIModuleNapiEnv;\n argsPtr++;\n",
i
)?;
} else if *arg == ABIType::NapiValue {
} else {
let slot = if i + 1 < self.arg_types.len() {
"*argsPtr++"
} else {
"*argsPtr"
};
// Not an initializer: TinyCC zero-fills an initialized aggregate with a memset() call.
writeln!(
writer,
" EncodedJSValue arg{} = {{ .asInt64 = *argsPtr++ }};",
i
" EncodedJSValue arg{i};\n arg{i}.asInt64 = {slot};"
)?;
} else if arg.needs_a_cast_in_c() {
if i < self.arg_types.len() - 1 {
writeln!(
writer,
" EncodedJSValue arg{} = {{ .asInt64 = *argsPtr++ }};",
i
)?;
} else {
write!(
writer,
" EncodedJSValue arg{};\n arg{}.asInt64 = *argsPtr;\n",
i, i
)?;
}
} else {
if i < self.arg_types.len() - 1 {
writeln!(writer, " int64_t arg{} = *argsPtr++;", i)?;
} else {
writeln!(writer, " int64_t arg{} = *argsPtr;", i)?;
}
}
}
}
Expand Down Expand Up @@ -2222,11 +2207,7 @@ impl Function {

let length_buf = bun_core::fmt::print_int(&mut arg_buf[3..], i);
let arg_name = &arg_buf[0..3 + length_buf];
if arg.needs_a_cast_in_c() {
write!(writer, "{}", arg.to_c(arg_name))?;
} else {
writer.write_all(arg_name)?;
}
write!(writer, "{}", arg.to_c(arg_name))?;
}
writer.write_all(b");\n")?;

Expand Down
Loading
Loading