perf(es/parser): Remove needless strcmp ops (#8223)

**Description:**


## The current `main`

```
es/parser/angular       time:   [7.9848 ms 8.0003 ms 8.0243 ms]
```

## This PR

```
es/parser/angular       time:   [7.3380 ms 7.3498 ms 7.3663 ms]
```
This commit is contained in:
Donny/강동윤 2023-11-06 13:16:35 +09:00 committed by GitHub
parent 968345b7f6
commit 3833cf4e55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 194 additions and 171 deletions

64
Cargo.lock generated
View File

@ -2598,18 +2598,38 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
"phf_macros",
"phf_shared",
"phf_macros 0.10.0",
"phf_shared 0.10.0",
"proc-macro-hack",
]
[[package]]
name = "phf"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2",
]
[[package]]
name = "phf_generator"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
"phf_shared",
"phf_shared 0.10.0",
"rand",
]
[[package]]
name = "phf_generator"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [
"phf_shared 0.11.2",
"rand",
]
@ -2619,14 +2639,27 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
dependencies = [
"phf_generator",
"phf_shared",
"phf_generator 0.10.0",
"phf_shared 0.10.0",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "phf_shared"
version = "0.10.0"
@ -2636,6 +2669,15 @@ dependencies = [
"siphasher",
]
[[package]]
name = "phf_shared"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
"siphasher",
]
[[package]]
name = "pin-project"
version = "1.0.12"
@ -3598,7 +3640,7 @@ dependencies = [
"new_debug_unreachable",
"once_cell",
"parking_lot",
"phf_shared",
"phf_shared 0.10.0",
"precomputed-hash",
"serde",
]
@ -3609,8 +3651,8 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
dependencies = [
"phf_generator",
"phf_shared",
"phf_generator 0.10.0",
"phf_shared 0.10.0",
"proc-macro2",
"quote",
]
@ -4139,6 +4181,7 @@ dependencies = [
"bytecheck",
"is-macro",
"num-bigint",
"phf 0.11.2",
"rkyv",
"scoped-tls",
"serde",
@ -4389,7 +4432,7 @@ dependencies = [
name = "swc_ecma_ext_transforms"
version = "0.110.14"
dependencies = [
"phf",
"phf 0.10.1",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
@ -4489,6 +4532,7 @@ dependencies = [
"either",
"num-bigint",
"num-traits",
"phf 0.11.2",
"pretty_assertions",
"serde",
"serde_json",
@ -4606,7 +4650,7 @@ dependencies = [
"criterion",
"indexmap 1.9.3",
"once_cell",
"phf",
"phf 0.10.1",
"rayon",
"rustc-hash",
"serde",

View File

@ -46,6 +46,7 @@ unicode-id = "0.3"
string_enum = { version = "0.4.1", path = "../string_enum" }
swc_atoms = { version = "0.6.0", path = "../swc_atoms" }
swc_common = { version = "0.33.3", path = "../swc_common" }
phf = { version = "0.11.2", features = ["macros"] }
[dev-dependencies]
serde_json = "1"

View File

@ -1,5 +1,6 @@
use std::fmt::Display;
use phf::phf_set;
use scoped_tls::scoped_thread_local;
use swc_atoms::{js_word, Atom};
use swc_common::{
@ -317,66 +318,87 @@ impl Ident {
}
}
static RESERVED: phf::Set<&str> = phf_set!(
"break",
"case",
"catch",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"enum",
"export",
"extends",
"false",
"finally",
"for",
"function",
"if",
"import",
"in",
"instanceof",
"new",
"null",
"package",
"return",
"super",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with",
);
static RESSERVED_IN_STRICT_MODE: phf::Set<&str> = phf_set!(
"implements",
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"yield",
);
static RESERVED_IN_ES3: phf::Set<&str> = phf_set!(
"abstract",
"boolean",
"byte",
"char",
"double",
"final",
"float",
"goto",
"int",
"long",
"native",
"short",
"synchronized",
"throws",
"transient",
"volatile",
);
pub trait IdentExt: AsRef<str> {
fn is_reserved(&self) -> bool {
[
"break",
"case",
"catch",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"enum",
"export",
"extends",
"false",
"finally",
"for",
"function",
"if",
"import",
"in",
"instanceof",
"new",
"null",
"package",
"return",
"super",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with",
]
.contains(&self.as_ref())
RESERVED.contains(self.as_ref())
}
fn is_reserved_in_strict_mode(&self, is_module: bool) -> bool {
if is_module && self.as_ref() == "await" {
return true;
}
[
"implements",
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"yield",
]
.contains(&self.as_ref())
RESSERVED_IN_STRICT_MODE.contains(self.as_ref())
}
fn is_reserved_in_strict_bind(&self) -> bool {
@ -384,25 +406,7 @@ pub trait IdentExt: AsRef<str> {
}
fn is_reserved_in_es3(&self) -> bool {
[
"abstract",
"boolean",
"byte",
"char",
"double",
"final",
"float",
"goto",
"int",
"long",
"native",
"short",
"synchronized",
"throws",
"transient",
"volatile",
]
.contains(&self.as_ref())
RESERVED_IN_ES3.contains(self.as_ref())
}
}

View File

@ -37,6 +37,7 @@ swc_atoms = { version = "0.6.0", path = "../swc_atoms" }
swc_common = { version = "0.33.3", path = "../swc_common" }
swc_ecma_ast = { version = "0.110.3", path = "../swc_ecma_ast" }
swc_ecma_visit = { version = "0.96.3", path = "../swc_ecma_visit", optional = true }
phf = { version = "0.11.2", features = ["macros"] }
[target.'cfg(not(any(target_arch = "wasm32", target_arch = "arm")))'.dependencies]
stacker = { version = "0.1.15", optional = true }

View File

@ -21,7 +21,7 @@ pub use self::{
};
use crate::{
error::{Error, SyntaxError},
token::{BinOpToken, Token, Word},
token::{BinOpToken, Keyword, Token, Word},
Context, Syntax,
};
@ -761,86 +761,54 @@ impl<'a> Lexer<'a> {
/// See https://tc39.github.io/ecma262/#sec-names-and-keywords
fn read_ident_or_keyword(&mut self) -> LexResult<Token> {
static KNOWN_WORDS: phf::Map<&str, Word> = phf::phf_map! {
"await" => Word::Keyword(Keyword::Await),
"break" => Word::Keyword(Keyword::Break),
"case" => Word::Keyword(Keyword::Case),
"catch" => Word::Keyword(Keyword::Catch),
"class" => Word::Keyword(Keyword::Class),
"const" => Word::Keyword(Keyword::Const),
"continue" => Word::Keyword(Keyword::Continue),
"debugger" => Word::Keyword(Keyword::Debugger),
"default" => Word::Keyword(Keyword::Default_),
"delete" => Word::Keyword(Keyword::Delete),
"do" => Word::Keyword(Keyword::Do),
"else" => Word::Keyword(Keyword::Else),
"export" => Word::Keyword(Keyword::Export),
"extends" => Word::Keyword(Keyword::Extends),
"false" => Word::False,
"finally" => Word::Keyword(Keyword::Finally),
"for" => Word::Keyword(Keyword::For),
"function" => Word::Keyword(Keyword::Function),
"if" => Word::Keyword(Keyword::If),
"import" => Word::Keyword(Keyword::Import),
"in" => Word::Keyword(Keyword::In),
"instanceof" => Word::Keyword(Keyword::InstanceOf),
"let" => Word::Keyword(Keyword::Let),
"new" => Word::Keyword(Keyword::New),
"null" => Word::Null,
"return" => Word::Keyword(Keyword::Return),
"super" => Word::Keyword(Keyword::Super),
"switch" => Word::Keyword(Keyword::Switch),
"this" => Word::Keyword(Keyword::This),
"throw" => Word::Keyword(Keyword::Throw),
"true" => Word::True,
"try" => Word::Keyword(Keyword::Try),
"typeof" => Word::Keyword(Keyword::TypeOf),
"var" => Word::Keyword(Keyword::Var),
"void" => Word::Keyword(Keyword::Void),
"while" => Word::Keyword(Keyword::While),
"with" => Word::Keyword(Keyword::With),
"yield" => Word::Keyword(Keyword::Yield),
};
debug_assert!(self.cur().is_some());
let start = self.cur_pos();
let (word, has_escape) = self.read_word_as_str_with(|s| {
use crate::token::Keyword::*;
if s.len() == 1 || s.len() > 10 {
{}
} else {
match s.as_bytes()[0] {
b'a' if s == "await" => return Await.into(),
b'b' if s == "break" => return Break.into(),
b'c' => match s {
"case" => return Case.into(),
"const" => return Const.into(),
"class" => return Class.into(),
"catch" => return Catch.into(),
"continue" => return Continue.into(),
_ => {}
},
b'd' => match s {
"do" => return Do.into(),
"default" => return Default_.into(),
"delete" => return Delete.into(),
"debugger" => return Debugger.into(),
_ => {}
},
b'e' => match s {
"else" => return Else.into(),
"export" => return Export.into(),
"extends" => return Extends.into(),
_ => {}
},
b'f' => match s {
"for" => return For.into(),
"false" => return Word::False,
"finally" => return Finally.into(),
"function" => return Function.into(),
_ => {}
},
b'i' => match s {
"if" => return If.into(),
"import" => return Import.into(),
"in" => return In.into(),
"instanceof" => return InstanceOf.into(),
_ => {}
},
b'l' if s == "let" => return Let.into(),
b'n' => match s {
"new" => return New.into(),
"null" => return Word::Null,
_ => {}
},
b'r' if s == "return" => return Return.into(),
b's' => match s {
"super" => return Super.into(),
"switch" => return Switch.into(),
_ => {}
},
b't' => match s {
"this" => return This.into(),
"true" => return Word::True,
"try" => return Try.into(),
"throw" => return Throw.into(),
"typeof" => return TypeOf.into(),
_ => {}
},
b'v' => match s {
"var" => return Var.into(),
"void" => return Void.into(),
_ => {}
},
b'w' => match s {
"while" => return While.into(),
"with" => return With.into(),
_ => {}
},
b'y' if s == "yield" => return Yield.into(),
_ => {}
}
if let Some(word) = KNOWN_WORDS.get(s) {
return word.clone();
}
Word::Ident(s.into())

View File

@ -60,8 +60,8 @@ impl Context {
}
}
pub fn is_reserved_word(self, word: &str) -> bool {
match word {
pub fn is_reserved_word(self, word: &Atom) -> bool {
match &**word {
"let" => self.strict,
// SyntaxError in the module only, not in the strict.
// ```JavaScript

View File

@ -58,18 +58,14 @@ macro_rules! define_known_ident {
)*
}
impl std::str::FromStr for KnownIdent {
type Err = ();
static STR_TO_KNOWN_IDENT: phf::Map<&'static str, KnownIdent> = phf::phf_map! {
$(
$value => KnownIdent::$name,
)*
};
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
$(
$value => Ok(Self::$name),
)*
_ => Err(()),
}
}
}
impl From<KnownIdent> for Atom {
@ -140,6 +136,14 @@ define_known_ident!(
Public => "public",
);
impl std::str::FromStr for KnownIdent {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
STR_TO_KNOWN_IDENT.get(s).cloned().ok_or(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum WordKind {
Keyword(Keyword),
@ -576,6 +580,7 @@ impl From<&'_ str> for Word {
}
impl From<&'_ str> for IdentLike {
#[inline]
fn from(s: &str) -> Self {
s.parse::<KnownIdent>()
.map(Self::Known)