Skip to content

Commit

Permalink
wasm simd
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Jul 28, 2024
1 parent 56b7f0c commit 3957e5f
Showing 1 changed file with 83 additions and 41 deletions.
124 changes: 83 additions & 41 deletions crates/oxc_sourcemap/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,26 +319,12 @@ fn escape_json_string<S: AsRef<str>>(s: S) -> String {
}

// Process remaining bytes
for &b in &bytes[i..] {
let e = ESCAPE[b as usize];
if e == 0 {
result.push(b as char);
} else if e == UU {
// For control characters, use unicode escape
result.push_str(&format!("\\u{b:04x}"));
} else {
// For other escaped characters
result.push('\\');
result.push(e as char);
}
}

result.push('"');
escape_json_string_fallback(&bytes[i..], &mut result);

result
}

#[cfg(target_arch = "x86_64")]
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
#[inline]
fn escape_json_string<S: AsRef<str>>(s: S) -> String {
use std::arch::x86_64::{
Expand All @@ -348,12 +334,12 @@ fn escape_json_string<S: AsRef<str>>(s: S) -> String {

let bytes = s.as_ref().as_bytes();
let len = bytes.len();
let mut result = String::with_capacity(len * 2 + 2);
let mut i = 0;

result.push('"');

if is_x86_feature_detected!("avx2") {
let mut result = String::with_capacity(len * 2 + 2);
let mut i = 0;

result.push('"');
// Safety: simd is naturally unsafe.
unsafe {
let escape_table = _mm256_loadu_si256(ESCAPE.as_ptr().cast::<__m256i>());
Expand Down Expand Up @@ -382,9 +368,16 @@ fn escape_json_string<S: AsRef<str>>(s: S) -> String {
i += 32;
}
}
// Process remaining bytes
escape_json_string_fallback(&bytes[i..], &mut result);
return result;
}

if is_x86_feature_detected!("sse2") {
let mut result = String::with_capacity(len * 2 + 2);
let mut i = 0;

result.push('"');
// Safety: simd is naturally unsafe.
unsafe {
while i + 16 <= len {
Expand Down Expand Up @@ -413,39 +406,89 @@ fn escape_json_string<S: AsRef<str>>(s: S) -> String {
}
}
// Process remaining bytes
for &b in &bytes[i..] {
let e = ESCAPE[b as usize];
if e == 0 {
result.push(b as char);
} else if e == UU {
result.push_str(&format!("\\u{b:04x}"));
escape_json_string_fallback(&bytes[i..], &mut result);
return result;
}

let mut result = String::with_capacity(bytes.len() * 2 + 2);
result.push('"');

// Old processor and Apple Rosetta 2 doesn't support AVX2/SSE.
escape_json_string_fallback(bytes, &mut result);

result
}

#[cfg(target_arch = "wasm32")]
#[inline]
fn escape_json_string<S: AsRef<str>>(s: S) -> String {
use core::arch::wasm32::*;

let bytes = s.as_ref().as_bytes();
let len = bytes.len();
let mut result = String::with_capacity(len * 2 + 2);
let mut i = 0;

result.push('"');

// Safety: SIMD operations are unsafe
unsafe {
let escape_table = v128_load(ESCAPE.as_ptr() as *const v128);

while i + 16 <= len {
let chunk = v128_load(bytes[i..].as_ptr() as *const v128);

// Perform table lookup to get escape characters
let escape = u8x16_swizzle(escape_table, chunk);

// Check if any byte needs escaping
let need_escape = v128_any_true(escape);

if !need_escape {
// No escaping needed, append the chunk as-is
result.push_str(std::str::from_utf8_unchecked(&bytes[i..i + 16]));
} else {
result.push('\\');
result.push(e as char);
// Process each byte individually
for j in 0..16 {
let b = bytes[i + j];
let e = ESCAPE[b as usize];
if e == 0 {
result.push(b as char);
} else if e == b'u' {
// Unicode escape
result.push_str(&format!("\\u{:04x}", b));
} else {
// Other escapes
result.push('\\');
result.push(e as char);
}
}
}
}

result.push('"');
result
} else {
// Apple Rosetta 2 doesn't support AVX2/SSE.
escape_json_string_fallback(s)
i += 16;
}
}
escape_json_string_fallback(&bytes[i..], &mut result);
result
}

#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
#[cfg(not(any(
target_arch = "aarch64",
target_arch = "x86_64",
target_arch = "x86",
target_arch = "wasm32"
)))]
#[inline]
fn escape_json_string<S: AsRef<str>>(s: S) -> String {
let mut result = String::with_capacity(bytes.len() * 2 + 2);
result.push('"');
escape_json_string_fallback(s)
}

#[allow(unused)]
#[inline]
fn escape_json_string_fallback<S: AsRef<str>>(s: S) -> String {
let s = s.as_ref();
let mut result = String::with_capacity(s.len() * 2 + 2);
result.push('"');
for &b in s.as_bytes() {
fn escape_json_string_fallback(bytes: &[u8], result: &mut String) {
for &b in bytes {
let e = ESCAPE[b as usize];
if e == 0 {
result.push(b as char);
Expand All @@ -459,7 +502,6 @@ fn escape_json_string_fallback<S: AsRef<str>>(s: S) -> String {
}
}
result.push('"');
result
}

#[test]
Expand Down

0 comments on commit 3957e5f

Please sign in to comment.