perf(common): Add more methods to Spanned (#4749)

- Lots of code only needs `lo` or `hi`, but they call `span()`, which is inefficient in some cases.
 - This PR only adds a trivial amount of optimization. I may add full optimization in future.
 - This PR improves codegen performance of `ExprOrSpread` and `Option<ExprOrSpread>`.
This commit is contained in:
Donny/강동윤 2022-05-23 18:18:40 +09:00 committed by GitHub
parent 6236e46574
commit 98df64517e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 142 additions and 36 deletions

View File

@ -12,16 +12,36 @@ pub use crate::syntax_pos::{
pub trait Spanned {
/// Get span of `self`.
fn span(&self) -> Span;
#[inline]
fn span_lo(&self) -> BytePos {
self.span().lo
}
#[inline]
fn span_hi(&self) -> BytePos {
self.span().hi
}
}
impl<'a, T> Spanned for Cow<'a, T>
where
T: Spanned + Clone,
{
#[inline(always)]
#[inline]
fn span(&self) -> Span {
(**self).span()
}
#[inline]
fn span_lo(&self) -> BytePos {
(**self).span_lo()
}
#[inline]
fn span_hi(&self) -> BytePos {
(**self).span_hi()
}
}
impl Spanned for Span {
@ -43,12 +63,29 @@ impl<S> Spanned for Option<S>
where
S: Spanned,
{
#[inline]
fn span(&self) -> Span {
match *self {
Some(ref s) => s.span(),
None => DUMMY_SP,
}
}
#[inline]
fn span_lo(&self) -> BytePos {
match *self {
Some(ref s) => s.span_lo(),
None => BytePos::DUMMY,
}
}
#[inline]
fn span_hi(&self) -> BytePos {
match *self {
Some(ref s) => s.span_hi(),
None => BytePos::DUMMY,
}
}
}
impl<S> Spanned for Rc<S>
@ -58,6 +95,16 @@ where
fn span(&self) -> Span {
<S as Spanned>::span(&*self)
}
#[inline]
fn span_lo(&self) -> BytePos {
<S as Spanned>::span_lo(&*self)
}
#[inline]
fn span_hi(&self) -> BytePos {
<S as Spanned>::span_hi(&*self)
}
}
impl<S> Spanned for Arc<S>
@ -67,6 +114,16 @@ where
fn span(&self) -> Span {
<S as Spanned>::span(&*self)
}
#[inline]
fn span_lo(&self) -> BytePos {
<S as Spanned>::span_lo(&*self)
}
#[inline]
fn span_hi(&self) -> BytePos {
<S as Spanned>::span_hi(&*self)
}
}
impl<S> Spanned for Box<S>
@ -76,6 +133,16 @@ where
fn span(&self) -> Span {
<S as Spanned>::span(&*self)
}
#[inline]
fn span_lo(&self) -> BytePos {
<S as Spanned>::span_lo(&*self)
}
#[inline]
fn span_hi(&self) -> BytePos {
<S as Spanned>::span_hi(&*self)
}
}
impl<'a, S> Spanned for &'a S
@ -83,7 +150,17 @@ where
S: ?Sized + Spanned,
{
fn span(&self) -> Span {
<S as Spanned>::span(*self)
<S as Spanned>::span(self)
}
#[inline]
fn span_lo(&self) -> BytePos {
<S as Spanned>::span_lo(self)
}
#[inline]
fn span_hi(&self) -> BytePos {
<S as Spanned>::span_hi(self)
}
}
@ -98,4 +175,18 @@ where
::either::Either::Right(ref n) => n.span(),
}
}
fn span_lo(&self) -> BytePos {
match *self {
::either::Either::Left(ref n) => n.span_lo(),
::either::Either::Right(ref n) => n.span_lo(),
}
}
fn span_hi(&self) -> BytePos {
match *self {
::either::Either::Left(ref n) => n.span_hi(),
::either::Either::Right(ref n) => n.span_hi(),
}
}
}

View File

@ -3,7 +3,7 @@ use is_macro::Is;
use serde::{self, Deserialize, Serialize};
use string_enum::StringEnum;
use swc_atoms::JsWord;
use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span, Spanned, DUMMY_SP};
use swc_common::{ast_node, util::take::Take, BytePos, EqIgnoreSpan, Span, Spanned, DUMMY_SP};
use crate::{
class::Class,
@ -905,6 +905,7 @@ pub struct ExprOrSpread {
}
impl Spanned for ExprOrSpread {
#[inline]
fn span(&self) -> Span {
let expr = self.expr.span();
match self.spread {
@ -912,6 +913,19 @@ impl Spanned for ExprOrSpread {
None => expr,
}
}
#[inline]
fn span_lo(&self) -> BytePos {
match self.spread {
Some(s) => s.lo,
None => self.expr.span_lo(),
}
}
#[inline]
fn span_hi(&self) -> BytePos {
self.expr.span_hi()
}
}
impl From<Expr> for ExprOrSpread {

View File

@ -67,6 +67,10 @@ where
}
pub(super) fn emit_leading_comments(&mut self, mut pos: BytePos, is_hi: bool) -> Result {
if pos.is_dummy() {
return Ok(());
}
let comments = match self.comments {
Some(ref comments) => comments,
None => return Ok(()),
@ -79,11 +83,8 @@ where
write_comments!(self, false, comments.take_leading(pos))
}
#[inline(always)]
pub(super) fn emit_leading_comments_of_span(&mut self, span: Span, is_hi: bool) -> Result {
if span.is_dummy_ignoring_cmt() {
return Ok(());
}
let pos = if is_hi { span.hi } else { span.lo };
self.emit_leading_comments(pos, is_hi)
}

View File

@ -2172,7 +2172,7 @@ where
&& previous_sibling.hi != parent_node.hi()
&& self.comments.is_some()
{
self.emit_leading_comments(previous_sibling.span().hi(), true)?;
self.emit_leading_comments(previous_sibling.hi(), true)?;
}
self.write_delim(format)?;
@ -2270,11 +2270,11 @@ where
if let Some(previous_sibling) = previous_sibling {
if format.contains(ListFormat::DelimitersMask)
&& previous_sibling.span().hi() != parent_node.hi()
&& previous_sibling.hi() != parent_node.hi()
&& emit_trailing_comments
&& self.comments.is_some()
{
self.emit_leading_comments(previous_sibling.span().hi(), true)?;
self.emit_leading_comments(previous_sibling.hi(), true)?;
}
}
}
@ -3574,7 +3574,7 @@ fn is_space_require_before_rhs(rhs: &Expr) -> bool {
}
fn is_empty_comments(span: &Span, comments: &Option<&dyn Comments>) -> bool {
span.is_dummy() || comments.map_or(true, |c| !c.has_leading(span.hi() - BytePos(1)))
span.is_dummy() || comments.map_or(true, |c| !c.has_leading(span.span_hi() - BytePos(1)))
}
fn minify_number(num: f64) -> String {

View File

@ -105,13 +105,13 @@ macro_rules! semi {
/// - `srcmap!(false)` for end (span.hi)
macro_rules! srcmap {
($emitter:expr, $n:expr, true) => {{
let bp = $n.span().lo;
if !bp.is_dummy() {
$emitter.wr.add_srcmap(bp)?;
let lo = $n.span_lo();
if !lo.is_dummy() {
$emitter.wr.add_srcmap(lo)?;
}
}};
($emitter:expr, $n:expr, false) => {
let hi = $n.span().hi;
let hi = $n.span_hi();
if !hi.is_dummy() {
$emitter.wr.add_srcmap(hi)?;
}

View File

@ -320,7 +320,7 @@ impl<I: Tokens> Parser<I> {
let args = self.parse_args(false)?;
Ok(Box::new(Expr::Call(CallExpr {
span: span!(self, expr.span().lo()),
span: span!(self, expr.span_lo()),
callee: Callee::Expr(expr),
args,
type_args: None,

View File

@ -19,7 +19,7 @@ impl<I: Tokens> Parser<I> {
let _tracing = debug_tracing!(self, "parse_expr");
let expr = self.parse_assignment_expr()?;
let start = expr.span().lo();
let start = expr.span_lo();
if is!(self, ',') {
let mut exprs = vec![expr];
@ -217,7 +217,7 @@ impl<I: Tokens> Parser<I> {
..self.ctx()
};
let alt = self.with_ctx(ctx).parse_assignment_expr()?;
let span = Span::new(start, alt.span().hi(), Default::default());
let span = Span::new(start, alt.span_hi(), Default::default());
Ok(Box::new(Expr::Cond(CondExpr {
span,
test,
@ -915,8 +915,8 @@ impl<I: Tokens> Parser<I> {
// span of sequence expression should not include '(', ')'
let seq_expr = Box::new(Expr::Seq(SeqExpr {
span: Span::new(
exprs.first().unwrap().span().lo(),
exprs.last().unwrap().span().hi(),
exprs.first().unwrap().span_lo(),
exprs.last().unwrap().span_hi(),
Default::default(),
),
exprs,
@ -957,7 +957,7 @@ impl<I: Tokens> Parser<I> {
tag: Box<Expr>,
type_params: Option<TsTypeParamInstantiation>,
) -> PResult<TaggedTpl> {
let tagged_tpl_start = tag.span().lo();
let tagged_tpl_start = tag.span_lo();
trace_cur!(self, parse_tagged_tpl);
let tpl = self.parse_tpl(true)?;
@ -1168,8 +1168,8 @@ impl<I: Tokens> Parser<I> {
let bracket_lo = self.input.prev_span().lo;
let prop = self.include_in_expr(true).parse_expr()?;
expect!(self, ']');
let span = Span::new(obj.span().lo(), self.input.last_pos(), Default::default());
debug_assert_eq!(obj.span().lo(), span.lo());
let span = Span::new(obj.span_lo(), self.input.last_pos(), Default::default());
debug_assert_eq!(obj.span_lo(), span.lo());
let prop = ComputedPropName {
span: Span::new(bracket_lo, self.input.last_pos(), Default::default()),
expr: prop,
@ -1290,9 +1290,9 @@ impl<I: Tokens> Parser<I> {
Either::Left(p) => MemberProp::PrivateName(p),
Either::Right(i) => MemberProp::Ident(i),
})?;
let span = span!(self, obj.span().lo());
debug_assert_eq!(obj.span().lo(), span.lo());
debug_assert_eq!(prop.span().hi(), span.hi());
let span = span!(self, obj.span_lo());
debug_assert_eq!(obj.span_lo(), span.lo());
debug_assert_eq!(prop.span_hi(), span.hi());
let type_args = if self.syntax().typescript() && is!(self, '<') {
self.try_parse_ts_type_args()
@ -1631,7 +1631,7 @@ impl<I: Tokens> Parser<I> {
arg = ExprOrSpread {
spread: None,
expr: Box::new(Expr::Cond(CondExpr {
span: Span::new(start, alt.span().hi(), Default::default()),
span: Span::new(start, alt.span_hi(), Default::default()),
test,
cons,
@ -1838,7 +1838,7 @@ impl<I: Tokens> Parser<I> {
fn at_possible_async(&mut self, expr: &Expr) -> PResult<bool> {
// TODO(kdy1): !this.state.containsEsc &&
Ok(self.state.potential_arrow_start == Some(expr.span().lo())
Ok(self.state.potential_arrow_start == Some(expr.span_lo())
&& matches!(
*expr,
Expr::Ident(Ident {

View File

@ -93,7 +93,7 @@ impl<I: Tokens> Parser<I> {
&& !self.input.had_line_break_before_cur()
&& is!(self, "as")
{
let start = left.span().lo();
let start = left.span_lo();
let expr = left;
let node = if peeked_is!(self, "const") {
bump!(self); // as
@ -212,7 +212,7 @@ impl<I: Tokens> Parser<I> {
}
let node = Box::new(Expr::Bin(BinExpr {
span: Span::new(left.span().lo(), right.span().hi(), Default::default()),
span: Span::new(left.span_lo(), right.span_hi(), Default::default()),
op,
left,
right,
@ -253,7 +253,7 @@ impl<I: Tokens> Parser<I> {
};
let arg = self.parse_unary_expr()?;
let span = Span::new(start, arg.span().hi(), Default::default());
let span = Span::new(start, arg.span_hi(), Default::default());
self.check_assign_target(&arg, false);
return Ok(Box::new(Expr::Update(UpdateExpr {
@ -311,7 +311,7 @@ impl<I: Tokens> Parser<I> {
}
return Ok(Box::new(Expr::Unary(UnaryExpr {
span: Span::new(start, arg.span().hi(), Default::default()),
span: Span::new(start, arg.span_hi(), Default::default()),
op,
arg,
})));
@ -344,7 +344,7 @@ impl<I: Tokens> Parser<I> {
};
return Ok(Box::new(Expr::Update(UpdateExpr {
span: span!(self, expr.span().lo()),
span: span!(self, expr.span_lo()),
prefix: false,
op,
arg: expr,

View File

@ -2149,14 +2149,14 @@ impl<I: Tokens> Parser<I> {
while !self.input.had_line_break_before_cur() && eat!(self, '[') {
if eat!(self, ']') {
ty = Box::new(TsType::TsArrayType(TsArrayType {
span: span!(self, ty.span().lo()),
span: span!(self, ty.span_lo()),
elem_type: ty,
}));
} else {
let index_type = self.parse_ts_type()?;
expect!(self, ']');
ty = Box::new(TsType::TsIndexedAccessType(TsIndexedAccessType {
span: span!(self, ty.span().lo()),
span: span!(self, ty.span_lo()),
readonly,
obj_type: ty,
index_type,
@ -2259,7 +2259,7 @@ impl<I: Tokens> Parser<I> {
return Ok(Default::default());
}
let start = expr.span().lo();
let start = expr.span_lo();
match &*expr.sym {
"declare" => {