-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
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
-
Repeated full scans over
Module.bodyin the main transform pipelinevisit_mut_modulecalls: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_itemsthen does bothretainandretain_mutpasses again ([transform.rs:158-166]).visit_mut_stmtre-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.
-
Extra pass on statement vectors in
visit_mut_stmtsvisit_mut_stmtsdoes aretain_muttransform pass, then a secondretainpass for dummy empties ([transform.rs:294-315]).
This can be collapsed into one pass by dropping dummy empties directly in the first traversal.
-
Per-member AST clone in enum semantic analysis
visit_ts_enum_declclones each enum member before computing value ([semantic.rs:545-552], especiallymember.clone()).transform_ts_enum_memberonly needs the initializer, so cloning the fullTsEnumMemberis avoidable.
On large enums with complex initializers, this creates unnecessary clone churn.
-
Eager fallback cloning in enum evaluator (
EnumValueComputer)compute_binclones the wholeBinExprup front ([ts_enum.rs:189]).compute_memberclones the wholeMemberExprup front ([ts_enum.rs:265]).compute_tplclones the wholeTplup front ([ts_enum.rs:294]).
These clones are paid even when evaluation succeeds and no opaque fallback is needed.
-
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.
- Members are filtered once when building
-
Repeated JSX pragma parsing per module
TypeScriptReact::visit_mut_moduleparses 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.
-
Repeated temporary
Vec<Id>allocations fromfind_pat_ids- Occurs in
collect_declandvisit_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.
- Occurs in
Suggested optimization order (highest expected impact first)
- Fuse/trim module-body passes in
transform.rs(finding ecmascript parser #1). - Remove per-member clone in enum semantic analysis (finding EcmaScript lexer is inefficient #3).
- Make enum opaque fallback construction lazy (finding Transformers for ecmascript #4).
- Remove redundant enum filter pass (finding Handle early errors in ecmascript parser #5).
- Merge statement cleanup passes (finding Clean up #2).
- Cache default JSX pragma parsing (finding Internal documentations #6).
- Replace
find_pat_idstemp 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.