Skip to content

Replace NodeFinder with direct recursion in shouldInvalidateExpression()#6041

Merged
staabm merged 1 commit into
phpstan:2.2.xfrom
staabm:less-nodef
Jul 12, 2026
Merged

Replace NodeFinder with direct recursion in shouldInvalidateExpression()#6041
staabm merged 1 commit into
phpstan:2.2.xfrom
staabm:less-nodef

Conversation

@staabm

@staabm staabm commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

The findFirst() call allocated a NodeTraverser + FirstFindingVisitor and paid the full visitor protocol (~4 calls per visited node) for every (stored expression, invalidated expression) pair that passes the substring pre-filter - about 2M visited nodes per analysed slice. A hand-rolled pre-order search with identical match semantics does one method call per node.

taken from 517cde7

before this PR:

➜  phpstan-src git:(2.2.x) ✗ php bin/phpstan clear-result-cache -q && time php -d memory_limit=450M bin/phpstan analyze src/Analyser -q
21.57s user 1.66s system 314% cpu 7.379 total
➜  phpstan-src git:(2.2.x) php bin/phpstan clear-result-cache -q && time php -d memory_limit=450M bin/phpstan analyze src/Analyser -q
21.34s user 1.61s system 320% cpu 7.150 total
➜  phpstan-src git:(2.2.x) php bin/phpstan clear-result-cache -q && time php -d memory_limit=450M bin/phpstan analyze src/Analyser -q
21.51s user 1.50s system 318% cpu 7.233 total

after this PR:

➜  phpstan-src git:(2.2.x) php bin/phpstan clear-result-cache -q && time php -d memory_limit=450M bin/phpstan analyze src/Analyser -q
20.45s user 1.57s system 327% cpu 6.714 total
➜  phpstan-src git:(2.2.x) php bin/phpstan clear-result-cache -q && time php -d memory_limit=450M bin/phpstan analyze src/Analyser -q
20.46s user 1.58s system 327% cpu 6.722 total
➜  phpstan-src git:(2.2.x) php bin/phpstan clear-result-cache -q && time php -d memory_limit=450M bin/phpstan analyze src/Analyser -q
20.52s user 1.54s system 324% cpu 6.797 total

The findFirst() call allocated a NodeTraverser + FirstFindingVisitor
and paid the full visitor protocol (~4 calls per visited node) for
every (stored expression, invalidated expression) pair that passes the
substring pre-filter - about 2M visited nodes per analysed slice. A
hand-rolled pre-order search with identical match semantics does one
method call per node.
@staabm staabm marked this pull request as ready for review July 12, 2026 07:26
@phpstan-bot

Copy link
Copy Markdown
Collaborator

This pull request has been marked as ready for review.

staabm referenced this pull request Jul 12, 2026
The findFirst() call allocated a NodeTraverser + FirstFindingVisitor
and paid the full visitor protocol (~4 calls per visited node) for
every (stored expression, invalidated expression) pair that passes the
substring pre-filter - about 2M visited nodes per analysed slice. A
hand-rolled pre-order search with identical match semantics does one
method call per node.
@staabm staabm merged commit d941625 into phpstan:2.2.x Jul 12, 2026
673 of 675 checks passed
@staabm staabm deleted the less-nodef branch July 12, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants