Skip to content

Commit f854d51

Browse files
authoredMar 13, 2023
perf(es/lexer): Use jump table for skip_space (#7073)
1 parent 9c29666 commit f854d51

File tree

4 files changed

+121
-33
lines changed

4 files changed

+121
-33
lines changed
 

‎crates/swc_ecma_parser/scripts/instrument/bench.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ set -eu
44
export RUST_LOG=off
55
export MIMALLOC_SHOW_STATS=1
66

7-
cargo profile instruments --release -t time --features tracing/release_max_level_info --features swc_common/concurrent --features swc_common/parking_lot --bench parser -- --bench --color
7+
cargo profile instruments --release -t time --features tracing/release_max_level_info --features swc_common/concurrent --features swc_common/parking_lot --bench parser -- --bench --color $@

‎crates/swc_ecma_parser/src/lexer/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ mod table;
3434
#[cfg(test)]
3535
mod tests;
3636
pub mod util;
37+
mod whitespace;
3738

3839
pub(crate) type LexResult<T> = Result<T, Error>;
3940

‎crates/swc_ecma_parser/src/lexer/util.rs

+19-32
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use swc_common::{
1212
use swc_ecma_ast::Ident;
1313
use tracing::warn;
1414

15-
use super::{comments_buffer::BufferedComment, input::Input, Char, LexResult, Lexer};
15+
use super::{
16+
comments_buffer::BufferedComment, input::Input, whitespace::SkipWhitespace, Char, LexResult,
17+
Lexer,
18+
};
1619
use crate::{
1720
error::{Error, SyntaxError},
1821
lexer::comments_buffer::BufferedCommentKind,
@@ -184,18 +187,20 @@ impl<'a> Lexer<'a> {
184187
/// See https://tc39.github.io/ecma262/#sec-white-space
185188
pub(super) fn skip_space<const LEX_COMMENTS: bool>(&mut self) -> LexResult<()> {
186189
loop {
187-
let cur_b = self.input.cur_as_ascii();
190+
let (offset, newline) = {
191+
let mut skip = SkipWhitespace {
192+
input: self.input.as_str(),
193+
newline: false,
194+
offset: 0,
195+
};
188196

189-
if matches!(cur_b, Some(b'\n' | b'\r')) {
190-
self.input.bump();
191-
self.state.had_line_break = true;
192-
continue;
193-
}
197+
skip.scan();
194198

195-
if matches!(cur_b, Some(b'\x09' | b'\x0b' | b'\x0c' | b'\x20' | b'\xa0')) {
196-
self.input.bump();
197-
continue;
198-
}
199+
(skip.offset, skip.newline)
200+
};
201+
202+
self.input.bump_bytes(offset);
203+
self.state.had_line_break |= newline;
199204

200205
if LEX_COMMENTS && self.input.is_byte(b'/') {
201206
if self.peek() == Some('/') {
@@ -205,34 +210,15 @@ impl<'a> Lexer<'a> {
205210
self.skip_block_comment()?;
206211
continue;
207212
}
208-
break;
209-
}
210-
211-
let c = self.cur();
212-
let c = match c {
213-
Some(v) => v,
214-
None => break,
215-
};
216-
217-
match c {
218-
// white spaces
219-
'\u{feff}' => {}
220-
// line breaks
221-
'\u{2028}' | '\u{2029}' => {
222-
self.state.had_line_break = true;
223-
}
224-
225-
_ if c.is_whitespace() => {}
226-
227-
_ => break,
228213
}
229214

230-
self.bump();
215+
break;
231216
}
232217

233218
Ok(())
234219
}
235220

221+
#[inline(never)]
236222
pub(super) fn skip_line_comment(&mut self, start_skip: usize) {
237223
let start = self.cur_pos();
238224
self.input.bump_bytes(start_skip);
@@ -282,6 +268,7 @@ impl<'a> Lexer<'a> {
282268
}
283269

284270
/// Expects current char to be '/' and next char to be '*'.
271+
#[inline(never)]
285272
pub(super) fn skip_block_comment(&mut self) -> LexResult<()> {
286273
let start = self.cur_pos();
287274

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/// Returns true if it's done
2+
pub(super) type ByteHandler = Option<for<'aa> fn(&mut SkipWhitespace<'aa>) -> usize>;
3+
4+
/// Lookup table for whitespace
5+
static BYTE_HANDLERS: [ByteHandler; 256] = [
6+
// 0 1 2 3 4 5 6 7 8 9 A B C D E F //
7+
___, ___, ___, ___, ___, ___, ___, ___, ___, SPC, NLN, SPC, SPC, NLN, ___, ___, // 0
8+
___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, // 1
9+
SPC, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, // 2
10+
___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, // 3
11+
___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, // 4
12+
___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, // 5
13+
___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, // 6
14+
___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, // 7
15+
UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, // 8
16+
UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, // 9
17+
UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, // A
18+
UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, // B
19+
UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, // C
20+
UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, // D
21+
UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, // E
22+
UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, UNI, // F
23+
];
24+
25+
/// Stop
26+
const ___: ByteHandler = None;
27+
28+
/// Newline
29+
const NLN: ByteHandler = Some(|skip| {
30+
skip.newline = true;
31+
32+
1
33+
});
34+
35+
/// Space
36+
const SPC: ByteHandler = Some(|_| 1);
37+
38+
/// Unicode
39+
const UNI: ByteHandler = Some(|skip| {
40+
let s = unsafe {
41+
// Safety: `skip.offset` is always valid
42+
skip.input.get_unchecked(skip.offset..)
43+
};
44+
45+
let c = unsafe {
46+
// Safety: Byte handlers are called only when `skip.input` is not empty
47+
s.chars().next().unwrap_unchecked()
48+
};
49+
50+
match c {
51+
// white spaces
52+
'\u{feff}' => {}
53+
// line breaks
54+
'\u{2028}' | '\u{2029}' => {
55+
skip.newline = true;
56+
}
57+
58+
_ if c.is_whitespace() => {}
59+
60+
_ => return 0,
61+
}
62+
63+
c.len_utf8()
64+
});
65+
66+
/// API is taked from oxc by Boshen (https://github.com/Boshen/oxc/pull/26)
67+
pub(super) struct SkipWhitespace<'a> {
68+
pub input: &'a str,
69+
70+
/// Total offset
71+
pub offset: usize,
72+
73+
/// Found newline
74+
pub newline: bool,
75+
}
76+
77+
impl SkipWhitespace<'_> {
78+
#[inline(always)]
79+
pub fn scan(&mut self) {
80+
let mut byte;
81+
loop {
82+
byte = match self.input.as_bytes().get(self.offset).copied() {
83+
Some(v) => v,
84+
None => return,
85+
};
86+
87+
let handler = unsafe { *(&BYTE_HANDLERS as *const ByteHandler).offset(byte as isize) };
88+
89+
if let Some(handler) = handler {
90+
let delta = handler(self);
91+
if delta == 0 {
92+
return;
93+
}
94+
self.offset += delta;
95+
} else {
96+
return;
97+
}
98+
}
99+
}
100+
}

1 commit comments

Comments
 (1)

github-actions[bot] commented on Mar 13, 2023

@github-actions[bot]

Benchmark

Benchmark suite Current: f854d51 Previous: 11d4874 Ratio
es/full/bugs-1 362829 ns/iter (± 19163) 311882 ns/iter (± 5390) 1.16
es/full/minify/libraries/antd 1771996901 ns/iter (± 24747418) 1676125955 ns/iter (± 28199276) 1.06
es/full/minify/libraries/d3 359329795 ns/iter (± 18531051) 310312819 ns/iter (± 6997234) 1.16
es/full/minify/libraries/echarts 1359615640 ns/iter (± 19000088) 1261496650 ns/iter (± 15514273) 1.08
es/full/minify/libraries/jquery 100872098 ns/iter (± 2860005) 92240018 ns/iter (± 1100088) 1.09
es/full/minify/libraries/lodash 112584515 ns/iter (± 3516634) 105904743 ns/iter (± 1210531) 1.06
es/full/minify/libraries/moment 56143773 ns/iter (± 1386286) 52442047 ns/iter (± 591676) 1.07
es/full/minify/libraries/react 21337388 ns/iter (± 779084) 19031883 ns/iter (± 183286) 1.12
es/full/minify/libraries/terser 278341765 ns/iter (± 7633880) 245803998 ns/iter (± 4324879) 1.13
es/full/minify/libraries/three 496238802 ns/iter (± 12899179) 444357105 ns/iter (± 6968596) 1.12
es/full/minify/libraries/typescript 3291680614 ns/iter (± 29261715) 3061958376 ns/iter (± 25372413) 1.08
es/full/minify/libraries/victory 757688713 ns/iter (± 18246283) 657696825 ns/iter (± 13818352) 1.15
es/full/minify/libraries/vue 142236724 ns/iter (± 2843522) 129925983 ns/iter (± 1311388) 1.09
es/full/codegen/es3 26191 ns/iter (± 80) 26420 ns/iter (± 282) 0.99
es/full/codegen/es5 26382 ns/iter (± 66) 26507 ns/iter (± 157) 1.00
es/full/codegen/es2015 26345 ns/iter (± 87) 26492 ns/iter (± 85) 0.99
es/full/codegen/es2016 26299 ns/iter (± 57) 26512 ns/iter (± 77) 0.99
es/full/codegen/es2017 26334 ns/iter (± 49) 26590 ns/iter (± 50) 0.99
es/full/codegen/es2018 26302 ns/iter (± 70) 26589 ns/iter (± 123) 0.99
es/full/codegen/es2019 26252 ns/iter (± 61) 26506 ns/iter (± 52) 0.99
es/full/codegen/es2020 26340 ns/iter (± 59) 26491 ns/iter (± 62) 0.99
es/full/all/es3 195824665 ns/iter (± 5889318) 180926987 ns/iter (± 2985911) 1.08
es/full/all/es5 182559376 ns/iter (± 3251090) 173212713 ns/iter (± 3258910) 1.05
es/full/all/es2015 145182796 ns/iter (± 3679409) 135932165 ns/iter (± 1085418) 1.07
es/full/all/es2016 144160105 ns/iter (± 4205450) 134014489 ns/iter (± 2431510) 1.08
es/full/all/es2017 142780354 ns/iter (± 3391322) 131675577 ns/iter (± 2043211) 1.08
es/full/all/es2018 140151140 ns/iter (± 4183230) 128537029 ns/iter (± 2284060) 1.09
es/full/all/es2019 139688717 ns/iter (± 6097224) 125026460 ns/iter (± 1660441) 1.12
es/full/all/es2020 130429226 ns/iter (± 2251981) 118460641 ns/iter (± 788665) 1.10
es/full/parser 531971 ns/iter (± 9054) 537212 ns/iter (± 8157) 0.99
es/full/base/fixer 22513 ns/iter (± 65) 22348 ns/iter (± 29) 1.01
es/full/base/resolver_and_hygiene 81709 ns/iter (± 81) 82189 ns/iter (± 176) 0.99
serialization of ast node 124 ns/iter (± 0) 125 ns/iter (± 0) 0.99
serialization of serde 127 ns/iter (± 0) 127 ns/iter (± 0) 1
css/minify/libraries/bootstrap 29236158 ns/iter (± 194850) 28468297 ns/iter (± 214616) 1.03
css/visitor/compare/clone 2119251 ns/iter (± 30582) 2095838 ns/iter (± 17677) 1.01
css/visitor/compare/visit_mut_span 2322690 ns/iter (± 5677) 2257958 ns/iter (± 50065) 1.03
css/visitor/compare/visit_mut_span_panic 2384962 ns/iter (± 27421) 2332797 ns/iter (± 5178) 1.02
css/visitor/compare/fold_span 3084756 ns/iter (± 23484) 3032901 ns/iter (± 24048) 1.02
css/visitor/compare/fold_span_panic 3230277 ns/iter (± 30361) 3218762 ns/iter (± 28690) 1.00
css/lexer/bootstrap_5_1_3 5145419 ns/iter (± 7578) 5145481 ns/iter (± 13142) 1.00
css/lexer/foundation_6_7_4 4337985 ns/iter (± 4058) 4341172 ns/iter (± 4114) 1.00
css/lexer/tailwind_3_1_1 823792 ns/iter (± 271) 823524 ns/iter (± 539) 1.00
css/parser/bootstrap_5_1_3 22405290 ns/iter (± 170932) 21960790 ns/iter (± 81135) 1.02
css/parser/foundation_6_7_4 17569093 ns/iter (± 100563) 17597065 ns/iter (± 108897) 1.00
css/parser/tailwind_3_1_1 3329762 ns/iter (± 3294) 3337868 ns/iter (± 2897) 1.00
es/codegen/colors 327700 ns/iter (± 185154) 330272 ns/iter (± 186667) 0.99
es/codegen/large 1199983 ns/iter (± 627236) 1230730 ns/iter (± 643705) 0.98
es/codegen/with-parser/colors 48273 ns/iter (± 316) 47005 ns/iter (± 287) 1.03
es/codegen/with-parser/large 523535 ns/iter (± 1399) 519859 ns/iter (± 1099) 1.01
es/minify/libraries/antd 1579091825 ns/iter (± 24467967) 1418795322 ns/iter (± 8023977) 1.11
es/minify/libraries/d3 286016567 ns/iter (± 8100275) 249947576 ns/iter (± 2587571) 1.14
es/minify/libraries/echarts 1168057942 ns/iter (± 25291827) 1088201657 ns/iter (± 21325234) 1.07
es/minify/libraries/jquery 82745047 ns/iter (± 1493053) 78586964 ns/iter (± 893411) 1.05
es/minify/libraries/lodash 103529427 ns/iter (± 2825454) 94549853 ns/iter (± 1406714) 1.09
es/minify/libraries/moment 49520639 ns/iter (± 2074280) 45408642 ns/iter (± 293413) 1.09
es/minify/libraries/react 19294170 ns/iter (± 1194606) 16915967 ns/iter (± 110931) 1.14
es/minify/libraries/terser 234434579 ns/iter (± 8960927) 208958891 ns/iter (± 2685676) 1.12
es/minify/libraries/three 404043847 ns/iter (± 12118984) 364015445 ns/iter (± 4507882) 1.11
es/minify/libraries/typescript 2773898855 ns/iter (± 25165964) 2601891341 ns/iter (± 17268816) 1.07
es/minify/libraries/victory 659887296 ns/iter (± 18313615) 543972776 ns/iter (± 7283181) 1.21
es/minify/libraries/vue 121203267 ns/iter (± 2957558) 116260963 ns/iter (± 1047385) 1.04
es/visitor/compare/clone 2380632 ns/iter (± 34832) 2363822 ns/iter (± 9662) 1.01
es/visitor/compare/visit_mut_span 2742246 ns/iter (± 14937) 2722947 ns/iter (± 6237) 1.01
es/visitor/compare/visit_mut_span_panic 2778673 ns/iter (± 23860) 2777810 ns/iter (± 5652) 1.00
es/visitor/compare/fold_span 3882371 ns/iter (± 17429) 3850058 ns/iter (± 19245) 1.01
es/visitor/compare/fold_span_panic 4049291 ns/iter (± 24483) 3994215 ns/iter (± 11402) 1.01
es/lexer/colors 15783 ns/iter (± 8) 15117 ns/iter (± 32) 1.04
es/lexer/angular 7714476 ns/iter (± 3530) 7367328 ns/iter (± 6762) 1.05
es/lexer/backbone 999478 ns/iter (± 272) 988536 ns/iter (± 1223) 1.01
es/lexer/jquery 5596550 ns/iter (± 4311) 5509121 ns/iter (± 3815) 1.02
es/lexer/jquery mobile 8648497 ns/iter (± 5151) 8494005 ns/iter (± 9114) 1.02
es/lexer/mootools 4433764 ns/iter (± 1656) 4353318 ns/iter (± 2557) 1.02
es/lexer/underscore 842963 ns/iter (± 360) 827178 ns/iter (± 249) 1.02
es/lexer/three 26217572 ns/iter (± 20998) 25772931 ns/iter (± 20752) 1.02
es/lexer/yui 4733599 ns/iter (± 1342) 4602086 ns/iter (± 1994) 1.03
es/parser/colors 29143 ns/iter (± 56) 29785 ns/iter (± 103) 0.98
es/parser/angular 16262931 ns/iter (± 168651) 15479082 ns/iter (± 191160) 1.05
es/parser/backbone 2242607 ns/iter (± 11163) 2253915 ns/iter (± 14684) 0.99
es/parser/jquery 12705016 ns/iter (± 75607) 12325004 ns/iter (± 154262) 1.03
es/parser/jquery mobile 20440847 ns/iter (± 257757) 19674821 ns/iter (± 485728) 1.04
es/parser/mootools 9444322 ns/iter (± 79295) 9301967 ns/iter (± 49418) 1.02
es/parser/underscore 1895760 ns/iter (± 8914) 1904529 ns/iter (± 10898) 1.00
es/parser/three 58635099 ns/iter (± 430471) 56320967 ns/iter (± 1369436) 1.04
es/parser/yui 9390937 ns/iter (± 72660) 9290268 ns/iter (± 53548) 1.01
es/preset-env/usage/builtin_type 141321 ns/iter (± 33797) 142862 ns/iter (± 34536) 0.99
es/preset-env/usage/property 21161 ns/iter (± 125) 20750 ns/iter (± 18) 1.02
es/resolver/typescript 118969330 ns/iter (± 2282912) 114212512 ns/iter (± 1560753) 1.04
es/fixer/typescript 90448406 ns/iter (± 1106277) 85227025 ns/iter (± 613225) 1.06
es/hygiene/typescript 195481189 ns/iter (± 2946311) 181278146 ns/iter (± 1391232) 1.08
es/resolver_with_hygiene/typescript 345864513 ns/iter (± 5306118) 328369692 ns/iter (± 2196592) 1.05
es/visitor/base-perf/module_clone 78635 ns/iter (± 915) 79258 ns/iter (± 1278) 0.99
es/visitor/base-perf/fold_empty 90714 ns/iter (± 1159) 89808 ns/iter (± 1313) 1.01
es/visitor/base-perf/fold_noop_impl_all 89942 ns/iter (± 1678) 91084 ns/iter (± 1275) 0.99
es/visitor/base-perf/fold_noop_impl_vec 91633 ns/iter (± 1323) 91568 ns/iter (± 783) 1.00
es/visitor/base-perf/boxing_boxed_clone 56 ns/iter (± 0) 56 ns/iter (± 0) 1
es/visitor/base-perf/boxing_unboxed_clone 54 ns/iter (± 0) 54 ns/iter (± 0) 1
es/visitor/base-perf/boxing_boxed 103 ns/iter (± 0) 104 ns/iter (± 0) 0.99
es/visitor/base-perf/boxing_unboxed 98 ns/iter (± 0) 98 ns/iter (± 0) 1
es/visitor/base-perf/visit_contains_this 3481 ns/iter (± 83) 3495 ns/iter (± 56) 1.00
es/base/parallel/resolver/typescript 5739869327 ns/iter (± 486937726) 5484842320 ns/iter (± 473209810) 1.05
es/base/parallel/hygiene/typescript 2209141166 ns/iter (± 28059995) 2152710308 ns/iter (± 22805801) 1.03
misc/visitors/time-complexity/time 5 101 ns/iter (± 0) 101 ns/iter (± 0) 1
misc/visitors/time-complexity/time 10 357 ns/iter (± 6) 352 ns/iter (± 0) 1.01
misc/visitors/time-complexity/time 15 705 ns/iter (± 2) 700 ns/iter (± 3) 1.01
misc/visitors/time-complexity/time 20 1315 ns/iter (± 0) 1335 ns/iter (± 8) 0.99
misc/visitors/time-complexity/time 40 6900 ns/iter (± 41) 6865 ns/iter (± 23) 1.01
misc/visitors/time-complexity/time 60 17465 ns/iter (± 48) 17392 ns/iter (± 24) 1.00
es/full-target/es2016 250498 ns/iter (± 310) 250003 ns/iter (± 628) 1.00
es/full-target/es2017 243163 ns/iter (± 295) 240888 ns/iter (± 439) 1.01
es/full-target/es2018 232275 ns/iter (± 442) 230369 ns/iter (± 858) 1.01
es2020_nullish_coalescing 91515 ns/iter (± 208) 90777 ns/iter (± 561) 1.01
es2020_optional_chaining 124310 ns/iter (± 747) 122089 ns/iter (± 789) 1.02
es2022_class_properties 147456 ns/iter (± 359) 145375 ns/iter (± 655) 1.01
es2018_object_rest_spread 95136 ns/iter (± 198) 93408 ns/iter (± 495) 1.02
es2019_optional_catch_binding 84427 ns/iter (± 198) 82784 ns/iter (± 454) 1.02
es2017_async_to_generator 85625 ns/iter (± 179) 83718 ns/iter (± 543) 1.02
es2016_exponentiation 89241 ns/iter (± 213) 87999 ns/iter (± 305) 1.01
es2015_arrow 94009 ns/iter (± 176) 92721 ns/iter (± 583) 1.01
es2015_block_scoped_fn 91527 ns/iter (± 278) 89597 ns/iter (± 584) 1.02
es2015_block_scoping 169949 ns/iter (± 624) 167169 ns/iter (± 1079) 1.02

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.