Skip to content

Commit 426f8cb

Browse files
committed
perf(codegen): reduce checks printing strings (#10341)
Speed up printing strings. I had wrongly assumed that `bytes.next().unwrap_unchecked()` would skip checks, but it seems it behaves the same as `bytes.next()` - i.e. check iterator is not empty, and only advance if it's not. Use `assert_unchecked!` instead to inform compiler that there are definitely the required number of bytes remaining in `bytes` iterator before consuming them. This reduces instruction count considerably, and removes a branch on every byte consumed. https://godbolt.org/z/TWzfK1eKj The mysteries of the compiler!
1 parent 0370363 commit 426f8cb

File tree

1 file changed

+13
-7
lines changed

1 file changed

+13
-7
lines changed

crates/oxc_codegen/src/str.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,13 @@ impl PrintStringState<'_> {
118118
/// before calling other methods e.g. `flush`.
119119
#[inline]
120120
unsafe fn consume_byte_unchecked(&mut self) {
121-
debug_assert!(self.bytes.clone().next().is_some());
121+
// `assert_unchecked!` produces less instructions than `self.bytes.next().unwrap_unchecked()`
122+
// https://godbolt.org/z/TWzfK1eKj
123+
122124
// SAFETY: Caller guarantees there is a byte to consume in `bytes` iterator,
123125
// and that consuming it leaves the iterator on a UTF-8 char boundary.
124-
unsafe { self.bytes.next().unwrap_unchecked() };
126+
unsafe { assert_unchecked!(!self.bytes.as_slice().is_empty()) };
127+
self.bytes.next().unwrap();
125128
}
126129

127130
/// Advance the `bytes` iterator by `N` bytes.
@@ -132,13 +135,16 @@ impl PrintStringState<'_> {
132135
/// * After this call, `bytes` iterator must be left on a UTF-8 character boundary.
133136
#[inline]
134137
unsafe fn consume_bytes_unchecked<const N: usize>(&mut self) {
135-
debug_assert!(self.bytes.as_slice().len() >= N);
138+
// `assert_unchecked!` produces many less instructions than
139+
// `for _i in 0..N { self.bytes.next().unwrap_unchecked(); }`.
140+
// The `unwrap` in loop below is required for compact assembly.
141+
// https://godbolt.org/z/TWzfK1eKj
142+
136143
// SAFETY: Caller guarantees there are `N` bytes to consume in `bytes` iterator,
137144
// and that consuming them leaves the iterator on a UTF-8 char boundary.
138-
unsafe {
139-
for _i in 0..N {
140-
self.bytes.next().unwrap_unchecked();
141-
}
145+
unsafe { assert_unchecked!(self.bytes.as_slice().len() >= N) };
146+
for _i in 0..N {
147+
self.bytes.next().unwrap();
142148
}
143149
}
144150

0 commit comments

Comments
 (0)