-
-
Notifications
You must be signed in to change notification settings - Fork 484
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AST visitor with bottom-up reading WIP #3152
Conversation
CodSpeed Performance ReportMerging #3152 will degrade performances by 3.5%Comparing Summary
Benchmarks breakdown
|
b5ee93c
to
ce282cc
Compare
ce282cc
to
d8eba8e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was following this PR while it was in progress so here are my initial thoughts on it.
I'm good with this one if we look at it as a stepping-stone toward the GCell version, Otherwise, I think the top-down is better than this Since while top-down approach is much more limited than having a 2-way traversal - either mutable or immutable - It is much cleaner.
About the performance drop, I'm sure we can make it better(not sure by how much). Still, one of the reasons we pursued this bottom-up approach was to lower the mispredicted branches and increase performance along with the API ergonomics. We have to stay focused on the initial goals(although we might want to compromise some of those goals just to push something out).
PS: I suggest that if we can extend our time window for this feature, We should do it. We may never be able to get it perfect first try, But more time in the oven can reduce the friction of refactoring in the future.
PS2: I believe even with a -20% performance we are still doing better than swc
since we don't do multiple passes on the AST.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel comfortable to work on this.
Requesting a review from everyone who is going to work on the transformer in the near future. |
Thanks both for reviewing. Just to say, this is not ready to merge yet. I think it's sound - Miri gives it a pass on the few conformance tests that I've tried - but I would like to test it much more exhaustively to make sure. This kind of subverts Rust's usual borrowing rules. I think it's bending the rules rather than breaking them, but I'm not 100% sure, and it needs more testing to be confident. There is a chance it may turn out not to be viable. Also, some of the lifetimes I don't think are correct currently, which definitely needs addressing, or it could lead to illegal reference aliasing. But, since there's some positive interest, I'll continue cleaning it up and hardening it next week. @Boshen 3 questions:
|
Previously, VisitMut only added the Your change is correct, when I'm not sure here is necessary. Since the typescript plugin removes all ts-only code first, maybe no |
d8eba8e
to
8259173
Compare
I'm fine with it, we can move it to a Rust task later. We can bikeshed this later.
It was written by hand so had missing parts.
Nope, the transformer started out from not doing much work, I expect things to slow down a bit. |
a1e0966
to
05ca458
Compare
e5388c8
to
0dedfc3
Compare
Thanks for coming back @Dunqing. Ah ha that makes sense. I suppose it's possible for some future use cases you might want to keep TS syntax present in AST - it could be useful for optimizations in a minifier, for example. But for now, yes, there's no point. As you say, we could hash that out a bit later. |
0e24b24
to
773e927
Compare
OK, I think this is good to go now. However, I don't think this PR should be merged as is. I've submitted the first part as #3169 - just the I wanted to split it up and submit all the parts as a Graphite stack, but don't seem to be able to use Graphite now - it sends me to a "billing" page. @Boshen did they start charging open source? Changes since previous versionSoundnessThere were indeed some soundness issues, but have ironed them out. In truth, there may be more - there's some code I'm not completely sure of - but we'll find out once we are using it and have a wide range of usage to run Miri on. If it does turn out there is still some unsoundness, I don't think it's a show-stopper, as I'm pretty confident that I know how to fix it. DocsI've added lengthy doc comments explaining how the scheme works. The implementation is sprawling, but the core concept is quite simple, so it should be comprehensible. If it's not, then that's my fault for not writing clearly enough. Please let me know whether what I've written makes sense or not, and I'll try again if it doesn't. CratesIt's a lot of code, so I've moved it into it's own crate I've also made a separate crate |
By the way, I realized today that this scheme can be extended without too much effort to also allow mutating upwards (with restriction that you can't mutate parent, only siblings). But I'd like to mull that a bit more, and do it as a follow-up. |
First part of #3152. This adds a crate `oxc_traverse`, but doesn't connect it up to the transformer or anything else yet. I think we could merge this now - as it doesn't affect any code that's in use - and then iterate on it to add scopes before using it in transformer. Please see #3152 (comment) for the broader picture.
Sliced off from #3152. This switches the transformer over to use `Traverse` instead of `VisitMut`. This is incomplete - scopes are not implemented yet. At present, no transforms use scopes anyway, so all tests pass, but regardless I don't think should be merged until the implementation is complete.
AST traversal with ability to:
NB: Unlike the cell-based approach (#2987) this does NOT allow mutating parents/ancestors, only reading them.
Please see last commit for an implementation of
transform-react-display-name
which uses this ability, and passes the final failing test for that plugin.#2987 will work eventually, but it's proving a quagmire to implement for whole AST, so I thought I'd try this other approach to get something working faster. In any case, perhaps reading up is all we need, and #2987's ability to mutate parents is not actually required to implement transformers?
Notes
VisitMut
is replaced byTraverse
.visit_*
functions are replaced byenter_*
andexit_*
.walk_*
themselves.walk_*
drives the process, and callsenter_*
andexit_*
itself.Traverse
trait,Ancestor
andwalk_*
functions are generated by a codegen currently written in JS (for speed of implementation). We should rewrite it in Rust as a build script if we want to go forwards with this.#[visited_node]
attr acts as a marker for the codegen, telling it which types to generate visitors for. It can likely be removed by making the codegen smarter.Performance
Performance is not great. -4% on transformer benchmarks. However, please note that transformer benchmarks run the whole process including parsing, and parsing takes up ~80% of the bench run time. Therefore a -4% drop on the transformer benchmark means that the transformer itself has got about 20% slower.
But...
(4) is the big one. To explain:
I noticed that
VisitMut
doesn't actually fire visitors everywhere it should (I had to make changes to one of the TS transforms because previouslyVisitMut
wasn't callingtransform_identifier_reference
forIdentifierReference
s inTSInterfaceHeritage
orTSTypeReference
).In comparison,
Traverse
is codegen-ed, so it performs visitation in a completely exhaustive fashion. Nothing gets missed.So the majority of the perf hit may just be that it's visiting all the AST, where
VisitMut
was missing some - but that's a feature not a bug!Draft status
This PR is not entirely complete. Still some stuff to fix around lifetimes, and would like to test it more exhaustively with Miri. But I think it's in a fit state for comments at this point.