mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
perf(codegen): remove branch from print_space_before_identifier (#27842)
Perf optimization. Continuation of #27841. That PR simplified `print_space_before_identifier`. Remove the branch on "was last byte ASCII?" by using a small lookup table. This removes 2 or 3 instructions from this very hot path. The previous implementation already used a lookup table for ASCII bytes. The table here is twice as large (128 bytes -> 256 bytes) but the 2nd half of it is only read when the source code contains an identifier ending in a non-ASCII character, which is extremely rare. So in 99.99% of cases, the cache usage of this larger table is no greater than the previous version.
This commit is contained in:
1 parent
eeff416a60
commit
a6456b7506
2 files changed
+38
-13
No files matched your search
@@ -47,6 +47,39 @@ pub use options::{CodegenOptions, CommentOptions, LegalComment};
|
||||
// Re-export `IndentChar` from `oxc_data_structures`
|
||||
pub use oxc_data_structures::code_buffer::IndentChar;
|
||||
|
||||
#[repr(C, align(128))]
|
||||
struct Align128<T>(pub(crate) T);
|
||||
|
||||
/// Lookup table for whether a byte which is last byte of output when printing an identifier
|
||||
/// is one that needs a space printed after it.
|
||||
///
|
||||
/// Used by [`print_space_before_identifier`].
|
||||
///
|
||||
/// Non-ASCII characters can appear in various places (e.g. in strings),
|
||||
/// but in such cases an ASCII character (e.g. `"`) is always printed after them.
|
||||
/// Only case in which last byte of output can be non-ASCII when printing an identifier
|
||||
/// or keyword (when [`print_space_before_identifier`] is called) is when what was
|
||||
/// last printed was an identifier ending with a non-ASCII character.
|
||||
/// So non-ASCII must be an identifier, and a space is required.
|
||||
///
|
||||
/// Non-ASCII characters in identifiers are extremely rare in real-world code,
|
||||
/// so only the first 128 bytes of this table will ever be read.
|
||||
/// Aligned on 128, so occupies 2 x 128-byte cache lines on Apple Silicon,
|
||||
/// and 2 pairs of 64-byte cache lines on x86.
|
||||
///
|
||||
/// [`print_space_before_identifier`]: Codegen::print_space_before_identifier
|
||||
static IDENT_BYTES: Align128<[bool; 256]> = {
|
||||
let mut slots = [true; 256];
|
||||
|
||||
let mut i = 0u8;
|
||||
while i < 128 {
|
||||
slots[i as usize] = is_identifier_part_ascii(i as char);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Align128(slots)
|
||||
};
|
||||
|
||||
/// Output from [`Codegen::build`]
|
||||
#[non_exhaustive]
|
||||
pub struct CodegenReturn<'a> {
|
||||
@@ -683,19 +716,11 @@ impl<'a> Codegen<'a> {
|
||||
fn print_space_before_identifier(&mut self) {
|
||||
let Some(byte) = self.last_byte() else { return };
|
||||
|
||||
if self.need_space_before_identifier != self.code.len() {
|
||||
// Non-ASCII characters can appear in various places (e.g. in strings),
|
||||
// but in such cases an ASCII character (e.g. `"`) is always printed after them.
|
||||
// Only case in which last byte of output can be non-ASCII when printing an identifier
|
||||
// or keyword (when this function is called) is when what was last printed was
|
||||
// an identifier ending with a non-ASCII character.
|
||||
// So non-ASCII must be an identifier, and a space is required.
|
||||
if byte.is_ascii() && !is_identifier_part_ascii(byte as char) {
|
||||
return;
|
||||
}
|
||||
let force_print_space = self.need_space_before_identifier == self.code.len();
|
||||
let last_byte_is_ident = IDENT_BYTES.0[byte as usize];
|
||||
if force_print_space || last_byte_is_ident {
|
||||
self.print_hard_space();
|
||||
}
|
||||
|
||||
self.print_hard_space();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -131,7 +131,7 @@ pub fn is_identifier_part(c: char) -> bool {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_identifier_part_ascii(c: char) -> bool {
|
||||
pub const fn is_identifier_part_ascii(c: char) -> bool {
|
||||
ASCII_ID_FLAGS.0[c as usize] & ID_CONTINUE != 0
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user