Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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, AVX512F, 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, AVX512F, 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, AVX512F, 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
16 changes: 16 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,20 @@ 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]) {
debug_assert!(dst.len() >= src.len() * 2);
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