Skip to content

perf(swc_ecma_transforms_typescript): reduce repeated AST passes and enum clone churn #11653

@kdy1

Description

@kdy1

Summary

I did a full static pass over crates/swc_ecma_transforms_typescript and found several likely performance hotspots. These are all static-analysis findings (no runtime profile attached yet), but they are concentrated in hot traversal paths and enum processing.

Findings

  1. Repeated full scans over Module.body in the main transform pipeline

    • visit_mut_module calls:
      • strip_module_items_with_semantic ([transform.rs:127-130, 666-766])
      • visit_mut_for_ts_import_export ([transform.rs:132, 1464-1667])
      • then node.visit_mut_children_with(self) ([transform.rs:134])
    • visit_mut_module_items then does both retain and retain_mut passes again ([transform.rs:158-166]).
    • visit_mut_stmt re-checks retention (should_retain_stmt) for statements ([transform.rs:336-342]).

    This creates multiple O(N) passes over top-level items and repeats hashing/lookups for large modules.

  2. Extra pass on statement vectors in visit_mut_stmts

    • visit_mut_stmts does a retain_mut transform pass, then a second retain pass for dummy empties ([transform.rs:294-315]).

    This can be collapsed into one pass by dropping dummy empties directly in the first traversal.

  3. Per-member AST clone in enum semantic analysis

    • visit_ts_enum_decl clones each enum member before computing value ([semantic.rs:545-552], especially member.clone()).
    • transform_ts_enum_member only needs the initializer, so cloning the full TsEnumMember is avoidable.

    On large enums with complex initializers, this creates unnecessary clone churn.

  4. Eager fallback cloning in enum evaluator (EnumValueComputer)

    • compute_bin clones the whole BinExpr up front ([ts_enum.rs:189]).
    • compute_member clones the whole MemberExpr up front ([ts_enum.rs:265]).
    • compute_tpl clones the whole Tpl up front ([ts_enum.rs:294]).

    These clones are paid even when evaluation succeeds and no opaque fallback is needed.

  5. Duplicate filtering in transform_ts_enum

    • Members are filtered once when building member_list ([transform.rs:951])
    • then filtered again with the same predicate before build_assign ([transform.rs:964]).

    The second filter appears redundant and adds another pass.

  6. Repeated JSX pragma parsing per module

    • TypeScriptReact::visit_mut_module parses default pragma strings (React.createElement, React.Fragment) each module visit ([typescript.rs:182-200]).

    This can likely be cached per pass instance (or as already-parsed IDs) when config/comments do not override it.

  7. Repeated temporary Vec<Id> allocations from find_pat_ids

    • Occurs in collect_decl and visit_export_decl ([semantic.rs:210-216, 392-396]).

    For modules with many declarations, this repeatedly allocates intermediate vectors instead of streaming directly into target sets/maps.

Suggested optimization order (highest expected impact first)

  1. Fuse/trim module-body passes in transform.rs (finding ecmascript parser #1).
  2. Remove per-member clone in enum semantic analysis (finding EcmaScript lexer is inefficient #3).
  3. Make enum opaque fallback construction lazy (finding Transformers for ecmascript #4).
  4. Remove redundant enum filter pass (finding Handle early errors in ecmascript parser #5).
  5. Merge statement cleanup passes (finding Clean up #2).
  6. Cache default JSX pragma parsing (finding Internal documentations #6).
  7. Replace find_pat_ids temp vectors with iterator/callback-based insertion where possible (finding Travis and codecov #7).

Notes

  • These are static findings; exact impact should be confirmed with benchmark fixtures (e.g. large namespace/enum-heavy TS inputs).
  • If helpful, I can send a follow-up PR sequence in the same order above, with per-change benchmark deltas.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions