Skip to content
Merged
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
6 changes: 5 additions & 1 deletion scripts/verify-baseline-static/allowlist-aarch64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

# ----------------------------------------------------------------------------
# Bun's Highway SVE/SVE2 targets. Gate: hwy::SupportedTargets via getauxval(AT_HWCAP).
# (76 symbols)
# (80 symbols)
# ----------------------------------------------------------------------------
_ZN3bun10N_SVE2_12810MemMemImplEPKhmS2_m [SVE]
_ZN3bun10N_SVE2_12815CopyU16ToU8ImplEPKtmPh [SVE]
_ZN3bun10N_SVE2_12815IndexOfCharImplEPKhmh [SVE]
_ZN3bun10N_SVE2_12818EncodeHexLowerImplEPKhmPh [SVE]
_ZN3bun10N_SVE2_12818FirstNonAscii8ImplEPKhm [SVE]
_ZN3bun10N_SVE2_12818IndexOfAnyCharImplEPKhmS2_m [SVE]
_ZN3bun10N_SVE2_12819CopyAsciiPrefixImplEPKhmPh [SVE]
Expand All @@ -29,6 +30,7 @@ _ZN3bun10N_SVE2_12849IndexOfNeedsEscapeForJavaScriptStringImplBacktickEPKhmh [S
_ZN3bun5N_SVE10MemMemImplEPKhmS2_m [SVE]
_ZN3bun5N_SVE15CopyU16ToU8ImplEPKtmPh [SVE]
_ZN3bun5N_SVE15IndexOfCharImplEPKhmh [SVE]
_ZN3bun5N_SVE18EncodeHexLowerImplEPKhmPh [SVE]
_ZN3bun5N_SVE18FirstNonAscii8ImplEPKhm [SVE]
_ZN3bun5N_SVE18IndexOfAnyCharImplEPKhmS2_m [SVE]
_ZN3bun5N_SVE19CopyAsciiPrefixImplEPKhmPh [SVE]
Expand All @@ -48,6 +50,7 @@ _ZN3bun5N_SVE49IndexOfNeedsEscapeForJavaScriptStringImplBacktickEPKhmh [S
_ZN3bun6N_SVE210MemMemImplEPKhmS2_m [SVE]
_ZN3bun6N_SVE215CopyU16ToU8ImplEPKtmPh [SVE]
_ZN3bun6N_SVE215IndexOfCharImplEPKhmh [SVE]
_ZN3bun6N_SVE218EncodeHexLowerImplEPKhmPh [SVE]
_ZN3bun6N_SVE218FirstNonAscii8ImplEPKhm [SVE]
_ZN3bun6N_SVE218IndexOfAnyCharImplEPKhmS2_m [SVE]
_ZN3bun6N_SVE219CopyAsciiPrefixImplEPKhmPh [SVE]
Expand All @@ -67,6 +70,7 @@ _ZN3bun6N_SVE249IndexOfNeedsEscapeForJavaScriptStringImplBacktickEPKhmh [S
_ZN3bun9N_SVE_25610MemMemImplEPKhmS2_m [SVE]
_ZN3bun9N_SVE_25615CopyU16ToU8ImplEPKtmPh [SVE]
_ZN3bun9N_SVE_25615IndexOfCharImplEPKhmh [SVE]
_ZN3bun9N_SVE_25618EncodeHexLowerImplEPKhmPh [SVE]
_ZN3bun9N_SVE_25618FirstNonAscii8ImplEPKhm [SVE]
_ZN3bun9N_SVE_25618IndexOfAnyCharImplEPKhmS2_m [SVE]
_ZN3bun9N_SVE_25619CopyAsciiPrefixImplEPKhmPh [SVE]
Expand Down
8 changes: 7 additions & 1 deletion scripts/verify-baseline-static/allowlist-x64-windows.txt
Original file line number Diff line number Diff line change
Expand Up @@ -437,12 +437,13 @@ ctiMasmProbeTrampolineAVX [AVX]

# ----------------------------------------------------------------------------
# Highway. MSVC-mangled bun::N_AVX* names.
# (114 symbols)
# (120 symbols)
# ----------------------------------------------------------------------------
bun::N_AVX10_2::ContainsNewlineOrNonASCIIOrQuoteImpl [AVX, AVX512BW, AVX512F]
bun::N_AVX10_2::CopyAsciiPrefixImpl [AVX, AVX512BW, AVX512F, AVX512VL]
bun::N_AVX10_2::CopyU16ToU8Impl [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI]
bun::N_AVX10_2::CountPrintableAscii16Impl [AVX, AVX2, AVX512BW, AVX512DQ, AVX512F, AVX512VL]
bun::N_AVX10_2::EncodeHexLowerImpl [AVX, AVX2, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI, GFNI]
bun::N_AVX10_2::FillWithSkipMaskImpl [AVX, AVX512DQ, AVX512F]
bun::N_AVX10_2::FirstNonAscii16Impl [AVX, AVX512BW, AVX512F]
bun::N_AVX10_2::FirstNonAscii8Impl [AVX, AVX512BW]
Expand All @@ -462,6 +463,7 @@ bun::N_AVX2::ContainsNewlineOrNonASCIIOrQuoteImpl [AVX, AVX2]
bun::N_AVX2::CopyAsciiPrefixImpl [AVX, AVX2]
bun::N_AVX2::CopyU16ToU8Impl [AVX, AVX2]
bun::N_AVX2::CountPrintableAscii16Impl [AVX, AVX2]
bun::N_AVX2::EncodeHexLowerImpl [AVX, AVX2]
bun::N_AVX2::FillWithSkipMaskImpl [AVX]
bun::N_AVX2::FirstNonAscii16Impl [AVX, AVX2, BMI2]
bun::N_AVX2::FirstNonAscii8Impl [AVX, AVX2]
Expand All @@ -481,6 +483,7 @@ bun::N_AVX3::ContainsNewlineOrNonASCIIOrQuoteImpl [AVX, AVX51
bun::N_AVX3::CopyAsciiPrefixImpl [AVX, AVX512BW, AVX512F]
bun::N_AVX3::CopyU16ToU8Impl [AVX, AVX512BW, AVX512F, AVX512VL]
bun::N_AVX3::CountPrintableAscii16Impl [AVX, AVX2, AVX512BW, AVX512DQ, AVX512F, AVX512VL]
bun::N_AVX3::EncodeHexLowerImpl [AVX, AVX2, AVX512BW, AVX512F]
bun::N_AVX3::FillWithSkipMaskImpl [AVX, AVX512DQ, AVX512F]
bun::N_AVX3::FirstNonAscii16Impl [AVX, AVX512BW, AVX512F]
bun::N_AVX3::FirstNonAscii8Impl [AVX, AVX512BW]
Expand All @@ -500,6 +503,7 @@ bun::N_AVX3_DL::ContainsNewlineOrNonASCIIOrQuoteImpl [AVX, AVX51
bun::N_AVX3_DL::CopyAsciiPrefixImpl [AVX, AVX512BW, AVX512F]
bun::N_AVX3_DL::CopyU16ToU8Impl [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI]
bun::N_AVX3_DL::CountPrintableAscii16Impl [AVX, AVX2, AVX512BW, AVX512DQ, AVX512F, AVX512VL]
bun::N_AVX3_DL::EncodeHexLowerImpl [AVX, AVX2, AVX512BW, AVX512DQ, AVX512F, AVX512VL, AVX512_VBMI, GFNI]
bun::N_AVX3_DL::FillWithSkipMaskImpl [AVX, AVX512DQ, AVX512F]
bun::N_AVX3_DL::FirstNonAscii16Impl [AVX, AVX512BW, AVX512F]
bun::N_AVX3_DL::FirstNonAscii8Impl [AVX, AVX512BW]
Expand All @@ -519,6 +523,7 @@ bun::N_AVX3_SPR::ContainsNewlineOrNonASCIIOrQuoteImpl [AVX, AVX51
bun::N_AVX3_SPR::CopyAsciiPrefixImpl [AVX, AVX512BW, AVX512F]
bun::N_AVX3_SPR::CopyU16ToU8Impl [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI]
bun::N_AVX3_SPR::CountPrintableAscii16Impl [AVX, AVX2, AVX512BW, AVX512DQ, AVX512F, AVX512VL]
bun::N_AVX3_SPR::EncodeHexLowerImpl [AVX, AVX2, AVX512BW, AVX512DQ, AVX512F, AVX512VL, AVX512_VBMI, GFNI]
bun::N_AVX3_SPR::FillWithSkipMaskImpl [AVX, AVX512DQ, AVX512F]
bun::N_AVX3_SPR::FirstNonAscii16Impl [AVX, AVX512BW, AVX512F]
bun::N_AVX3_SPR::FirstNonAscii8Impl [AVX, AVX512BW]
Expand All @@ -538,6 +543,7 @@ bun::N_AVX3_ZEN4::ContainsNewlineOrNonASCIIOrQuoteImpl [AVX, AVX51
bun::N_AVX3_ZEN4::CopyAsciiPrefixImpl [AVX, AVX512BW, AVX512F]
bun::N_AVX3_ZEN4::CopyU16ToU8Impl [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI]
bun::N_AVX3_ZEN4::CountPrintableAscii16Impl [AVX, AVX2, AVX512BW, AVX512DQ, AVX512F, AVX512VL]
bun::N_AVX3_ZEN4::EncodeHexLowerImpl [AVX, AVX2, AVX512BW, AVX512DQ, AVX512F, AVX512VL, AVX512_VBMI, GFNI]
bun::N_AVX3_ZEN4::FillWithSkipMaskImpl [AVX, AVX512DQ, AVX512F]
bun::N_AVX3_ZEN4::FirstNonAscii16Impl [AVX, AVX512BW, AVX512F]
bun::N_AVX3_ZEN4::FirstNonAscii8Impl [AVX, AVX512BW]
Expand Down
8 changes: 7 additions & 1 deletion scripts/verify-baseline-static/allowlist-x64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -459,11 +459,12 @@ ctiMasmProbeTrampolineAVX [AVX]

# ----------------------------------------------------------------------------
# Bun's Highway SIMD. Gate: HWY_DYNAMIC_DISPATCH via hwy::SupportedTargets.
# (114 symbols)
# (120 symbols)
# ----------------------------------------------------------------------------
_ZN3bun10N_AVX3_SPR10MemMemImplEPKhmS2_m [AVX, AVX512BW, AVX512F, BMI1]
_ZN3bun10N_AVX3_SPR15CopyU16ToU8ImplEPKtmPh [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI]
_ZN3bun10N_AVX3_SPR15IndexOfCharImplEPKhmh [AVX, AVX512BW, BMI2]
_ZN3bun10N_AVX3_SPR18EncodeHexLowerImplEPKhmPh [AVX, AVX2, AVX512BW, AVX512F, AVX512_VBMI, GFNI]
_ZN3bun10N_AVX3_SPR18FirstNonAscii8ImplEPKhm [AVX, AVX512BW]
_ZN3bun10N_AVX3_SPR18IndexOfAnyCharImplEPKhmS2_m [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_FP16]
_ZN3bun10N_AVX3_SPR19CopyAsciiPrefixImplEPKhmPh [AVX, AVX512BW, AVX512F]
Expand All @@ -483,6 +484,7 @@ _ZN3bun10N_AVX3_SPR49IndexOfNeedsEscapeForJavaScriptStringImplBacktickEPKhmh [
_ZN3bun11N_AVX3_ZEN410MemMemImplEPKhmS2_m [AVX, AVX512BW, AVX512F, BMI1]
_ZN3bun11N_AVX3_ZEN415CopyU16ToU8ImplEPKtmPh [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI]
_ZN3bun11N_AVX3_ZEN415IndexOfCharImplEPKhmh [AVX, AVX512BW, BMI2]
_ZN3bun11N_AVX3_ZEN418EncodeHexLowerImplEPKhmPh [AVX, AVX2, AVX512BW, AVX512F, AVX512_VBMI, GFNI]
_ZN3bun11N_AVX3_ZEN418FirstNonAscii8ImplEPKhm [AVX, AVX512BW]
_ZN3bun11N_AVX3_ZEN418IndexOfAnyCharImplEPKhmS2_m [AVX, AVX512BW, AVX512F, AVX512VL]
_ZN3bun11N_AVX3_ZEN419CopyAsciiPrefixImplEPKhmPh [AVX, AVX512BW, AVX512F]
Expand All @@ -502,6 +504,7 @@ _ZN3bun11N_AVX3_ZEN449IndexOfNeedsEscapeForJavaScriptStringImplBacktickEPKhmh [
_ZN3bun6N_AVX210MemMemImplEPKhmS2_m [AVX, AVX2]
_ZN3bun6N_AVX215CopyU16ToU8ImplEPKtmPh [AVX, AVX2]
_ZN3bun6N_AVX215IndexOfCharImplEPKhmh [AVX, AVX2]
_ZN3bun6N_AVX218EncodeHexLowerImplEPKhmPh [AVX, AVX2]
_ZN3bun6N_AVX218FirstNonAscii8ImplEPKhm [AVX, AVX2]
_ZN3bun6N_AVX218IndexOfAnyCharImplEPKhmS2_m [AVX, AVX2]
_ZN3bun6N_AVX219CopyAsciiPrefixImplEPKhmPh [AVX, AVX2]
Expand All @@ -521,6 +524,7 @@ _ZN3bun6N_AVX249IndexOfNeedsEscapeForJavaScriptStringImplBacktickEPKhmh [
_ZN3bun6N_AVX310MemMemImplEPKhmS2_m [AVX, AVX512BW, AVX512F, BMI1]
_ZN3bun6N_AVX315CopyU16ToU8ImplEPKtmPh [AVX, AVX512BW, AVX512F, AVX512VL]
_ZN3bun6N_AVX315IndexOfCharImplEPKhmh [AVX, AVX512BW, BMI2]
_ZN3bun6N_AVX318EncodeHexLowerImplEPKhmPh [AVX, AVX2, AVX512BW, AVX512F]
_ZN3bun6N_AVX318FirstNonAscii8ImplEPKhm [AVX, AVX512BW]
_ZN3bun6N_AVX318IndexOfAnyCharImplEPKhmS2_m [AVX, AVX512BW, AVX512F, AVX512VL]
_ZN3bun6N_AVX319CopyAsciiPrefixImplEPKhmPh [AVX, AVX512BW, AVX512F]
Expand All @@ -540,6 +544,7 @@ _ZN3bun6N_AVX349IndexOfNeedsEscapeForJavaScriptStringImplBacktickEPKhmh [
_ZN3bun9N_AVX10_210MemMemImplEPKhmS2_m [AVX, AVX512BW, AVX512F, BMI1]
_ZN3bun9N_AVX10_215CopyU16ToU8ImplEPKtmPh [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI]
_ZN3bun9N_AVX10_215IndexOfCharImplEPKhmh [AVX, AVX512BW, BMI2]
_ZN3bun9N_AVX10_218EncodeHexLowerImplEPKhmPh [AVX, AVX2, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI, GFNI]
_ZN3bun9N_AVX10_218FirstNonAscii8ImplEPKhm [AVX, AVX512BW]
_ZN3bun9N_AVX10_218IndexOfAnyCharImplEPKhmS2_m [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_FP16]
_ZN3bun9N_AVX10_219CopyAsciiPrefixImplEPKhmPh [AVX, AVX512BW, AVX512F, AVX512VL]
Expand All @@ -559,6 +564,7 @@ _ZN3bun9N_AVX10_249IndexOfNeedsEscapeForJavaScriptStringImplBacktickEPKhmh [
_ZN3bun9N_AVX3_DL10MemMemImplEPKhmS2_m [AVX, AVX512BW, AVX512F, BMI1]
_ZN3bun9N_AVX3_DL15CopyU16ToU8ImplEPKtmPh [AVX, AVX512BW, AVX512F, AVX512VL, AVX512_VBMI]
_ZN3bun9N_AVX3_DL15IndexOfCharImplEPKhmh [AVX, AVX512BW, BMI2]
_ZN3bun9N_AVX3_DL18EncodeHexLowerImplEPKhmPh [AVX, AVX2, AVX512BW, AVX512F, AVX512_VBMI, GFNI]
_ZN3bun9N_AVX3_DL18FirstNonAscii8ImplEPKhm [AVX, AVX512BW]
_ZN3bun9N_AVX3_DL18IndexOfAnyCharImplEPKhmS2_m [AVX, AVX512BW, AVX512F, AVX512VL]
_ZN3bun9N_AVX3_DL19CopyAsciiPrefixImplEPKhmPh [AVX, AVX512BW, AVX512F]
Expand Down
12 changes: 9 additions & 3 deletions src/bun_core/string/immutable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1980,9 +1980,15 @@ pub fn encode_bytes_to_hex(destination: &mut [u8], source: &[u8]) -> usize {

let to_read = to_write / 2;

// PERF(port): Zig had a @Vector(16,u8) interlace fast path. Scalar loop here;
// consider a portable_simd shuffle or LUT if hot.
crate::fmt::bytes_to_hex_lower(&source[..to_read], &mut destination[..to_read * 2])
// Runtime-dispatched SIMD kernel for bulk encodes (Buffer.toString("hex"));
// the scalar LUT loop wins below this size because of the dispatch overhead.
const HIGHWAY_MIN_LEN: usize = 64;
if to_read >= HIGHWAY_MIN_LEN {
highway::encode_hex_lower(&source[..to_read], &mut destination[..to_write]);
return to_write;
}

crate::fmt::bytes_to_hex_lower(&source[..to_read], &mut destination[..to_write])
}

/// Leave a single leading char
Expand Down
23 changes: 23 additions & 0 deletions src/highway/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ unsafe extern "C" {
fn highway_copy_u16_to_u8(input: *const u16, count: usize, output: *mut u8);

fn highway_copy_ascii_prefix(src: *const u8, len: usize, dst: *mut u8) -> usize;

fn highway_encode_hex_lower(input: *const u8, len: usize, output: *mut u8);
}

// NOTE: every public wrapper below is `#[inline(always)]`. They are thin
Expand Down Expand Up @@ -258,6 +260,27 @@ pub fn copy_ascii_prefix(src: &[u8], dst: &mut [u8]) -> usize {
copied
}

/// Lowercase hex encode: writes exactly `2 * src.len()` bytes to `dst`.
#[inline(always)]
pub fn encode_hex_lower(src: &[u8], dst: &mut [u8]) {
// Runtime check (not just debug): this is a safe wrapper around an FFI
// write, so a too-small `dst` must panic instead of corrupting memory.
assert!(
dst.len() / 2 >= src.len(),
"encode_hex_lower: destination too small ({} bytes for {} source bytes)",
dst.len(),
src.len()
);
if src.is_empty() {
return;
}

// SAFETY: `src` is readable for `src.len()` bytes and `dst` is writable
// for `2 * src.len()` bytes (asserted above); the kernel writes exactly
// that many bytes and the slices cannot overlap (`&`/`&mut`).
unsafe { highway_encode_hex_lower(src.as_ptr(), src.len(), dst.as_mut_ptr()) }
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/// Apply a WebSocket mask to data using SIMD acceleration
/// If skip_mask is true, data is copied without masking
#[inline(always)]
Expand Down
43 changes: 43 additions & 0 deletions src/jsc/bindings/highway_strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,43 @@ size_t CopyAsciiPrefixImpl(const uint8_t* HWY_RESTRICT src, size_t len, uint8_t*
return len;
}

// Lowercase hex encode: writes 2 output bytes per input byte.
// Per 16-byte block: split each byte into nibbles, map both nibble vectors
// through the hex-digit table (TableLookupBytes), then interleave so the
// high-nibble digit precedes the low-nibble digit of every byte.
void EncodeHexLowerImpl(const uint8_t* HWY_RESTRICT input, size_t len, uint8_t* HWY_RESTRICT output)
{
alignas(16) static constexpr uint8_t kHexDigits[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};

D8 d;
const size_t N = hn::Lanes(d);

const auto table = hn::LoadDup128(d, kHexDigits);
const auto low_nibble_mask = hn::Set(d, uint8_t { 0x0F });

size_t i = 0;
if (len >= N) {
const size_t simd_len = len - (len % N);
for (; i < simd_len; i += N) {
const auto bytes = hn::LoadU(d, input + i);
const auto hi = hn::ShiftRight<4>(bytes);
const auto lo = hn::And(bytes, low_nibble_mask);
const auto hi_chars = hn::TableLookupBytes(table, hi);
const auto lo_chars = hn::TableLookupBytes(table, lo);
hn::StoreInterleaved2(hi_chars, lo_chars, d, output + i * 2);
}
}

for (; i < len; ++i) {
const uint8_t byte = input[i];
output[i * 2] = kHexDigits[byte >> 4];
output[i * 2 + 1] = kHexDigits[byte & 0x0F];
}
}

// Implementation for WebSocket mask application
void FillWithSkipMaskImpl(const uint8_t* HWY_RESTRICT mask, size_t mask_len, uint8_t* HWY_RESTRICT output, const uint8_t* HWY_RESTRICT input, size_t length, bool skip_mask)
{
Expand Down Expand Up @@ -1251,6 +1288,7 @@ HWY_EXPORT(ContainsNewlineOrNonASCIIOrQuoteImpl);
HWY_EXPORT(CopyAsciiPrefixImpl);
HWY_EXPORT(CopyU16ToU8Impl);
HWY_EXPORT(CountPrintableAscii16Impl);
HWY_EXPORT(EncodeHexLowerImpl);
HWY_EXPORT(FillWithSkipMaskImpl);
HWY_EXPORT(FirstNonAscii16Impl);
HWY_EXPORT(FirstNonAscii8Impl);
Expand Down Expand Up @@ -1412,6 +1450,11 @@ size_t highway_copy_ascii_prefix(const uint8_t* HWY_RESTRICT src, size_t len, ui
return HWY_DYNAMIC_DISPATCH(CopyAsciiPrefixImpl)(src, len, dst);
}

void highway_encode_hex_lower(const uint8_t* HWY_RESTRICT input, size_t len, uint8_t* HWY_RESTRICT output)
{
HWY_DYNAMIC_DISPATCH(EncodeHexLowerImpl)(input, len, output);
}

} // extern "C"

} // namespace bun
Expand Down
Loading
Loading