Commit 6cc200f
authored
Optimize _node_contains_jsx
The optimized code achieves a **684% speedup** (from 1.03ms to 131μs) by replacing recursive calls with an iterative stack-based approach and using a frozenset for type checking.
## Key Optimizations
**1. Eliminated Recursive Overhead**
The original code uses recursion with multiple call sites, creating significant overhead from:
- Function call stack frames for each node traversal
- Generator expression overhead in `any(_node_contains_jsx(child) for child in node.children)`
- Repeated function entry/exit costs
The optimized version uses an explicit stack with a while loop, eliminating all recursion overhead. This is particularly impactful for tree traversal where every node would trigger a new function call in the original version.
**2. Frozenset Lookup for Type Checking**
Moving JSX type checks into a `frozenset` (`_JSX_TYPES`) provides O(1) average-case lookup instead of tuple membership testing, which is O(n) linear scan. While the performance difference is small for 5 types, frozensets are optimized for membership testing and signal intent clearly.
**3. Simplified Control Flow**
The original code had special-case handling for `return_statement` nodes before the generic child traversal. The optimized version treats all nodes uniformly—checking the type first, then processing children—reducing branching and making the code path more predictable.
## Performance Impact by Test Case
The optimization excels on **breadth-heavy trees**:
- `test_large_breadth_many_children_with_one_jsx_at_end`: **7541% faster** (324μs → 4.25μs)
- `test_large_breadth_many_children_no_jsx`: **292% faster** (338μs → 86.5μs)
For these cases, the original recursive approach with generator expressions incurs massive overhead when traversing 1000 siblings, while the iterative approach efficiently processes them with minimal per-node cost.
For simple cases with few nodes, the speedup is more modest (47-99% faster) due to lower recursion depth, though there is a slight regression (~1-25% slower) for the absolute simplest cases with a single node, likely due to the stack initialization overhead. This is an acceptable trade-off given the dramatic improvements on realistic tree structures.
The optimization preserves all behavior including the `TypeError` when `children` is `None`, ensuring backward compatibility.1 parent 5c3a8dc commit 6cc200f
1 file changed
Lines changed: 15 additions & 16 deletions
Lines changed: 15 additions & 16 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
22 | 30 | | |
23 | 31 | | |
24 | 32 | | |
| |||
177 | 185 | | |
178 | 186 | | |
179 | 187 | | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | | - | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
196 | 195 | | |
197 | 196 | | |
198 | 197 | | |
| |||
0 commit comments