- Notifications
You must be signed in to change notification settings - Fork396
Add a desugaring pass between the base linker and the optimizer.#5101
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
ae9fdc5
toa738094
CompareThis is now in a reviewable shape, I think. The second commit might be over-engineered, though. 😅 |
I've had a look at this and the PRs on top of this. I think it fits the overall linker design reasonably nicely. Some higher level comments:
I'll likely proceed with a more detailed review when I have time, unless you feel comparing this to#5096 needs more higher level discussion. |
sjrd commentedJan 17, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I can try something like that.
I don't think we can. The problem is that wedon't see the shape
They don't. Those two PRs are unrelated. (I was prompted to look into that because I expected to have to write one more cache with clear after run for the desugaring phase. But it turned out it was so fast that a cache makes it worse, and so there is no relationship with the cache PRs.)
So basically making it a bare enum-like thing with an ordering, and have the checkers know the acceptable ranges? That's what I started with, but found it unwieldy. I can revert to that state to give a comparison.
No I think it's fine. It seems that this variant wins over#5096 overall. |
Maybe consider giving the enum ordering to make the range checks easier to grok. Or even expand the features on top of the checker ( IMHO the important part is that the logic of what is allowed where is in the checkers and not the phase enum. |
a738094
to808638e
Comparesjrd commentedJan 18, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I pushed a different version of the This should make things clearer while leaving the responsibility to the checkers, as you mentioned (although factored out in |
I pushed a commit thast switches to that scheme. I'm not sure I like it better, though. It bothers me that we have fields in |
Yes, I agree, this is not nice in our design. However, I don't think this is anything new: Arguably, this is something we should fix. Ironically, one of the easiest way I know is using structural subtyping like in go (producer exposes concrete type, consumer defines an interface of what it needs). Unfortunately, that's not really available to us in Scala. Other than that, I find the alternative much cleaner :-/ Do you think it makes sense to figure out how to better decouple the fields we have for individual phases? |
Good point. The new desugaring info does not make the situation qualitatively worse. This is probably fine as is, then. We can try to improve that afterwards. |
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.
More in-depth review of check refactoring.
How big is the effort to split this into a separate PR to ease review?
linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
hasRuntimeTypeInfo, | ||
fieldsRead, | ||
staticFieldsRead, | ||
staticDependencies, |
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.
Note to self: This will not be correct anymore when we add theNewLambda
desguaring: there will be a dependency on the class.
linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
linker/shared/src/main/scala/org/scalajs/linker/checker/CheckingPhase.scala OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
linker/shared/src/main/scala/org/scalajs/linker/checker/FeatureSet.scala OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
linker/shared/src/main/scala/org/scalajs/linker/checker/FeatureSet.scala OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
linker/shared/src/main/scala/org/scalajs/linker/checker/FeatureSet.scala OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
linker/shared/src/main/scala/org/scalajs/linker/checker/FeatureSet.scala OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
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.
Review of the new phase (as far as possible given the current commit situation).
@@ -105,6 +107,13 @@ final class BaseLinker(config: CommonPhaseConfig, checkIR: Boolean) { | |||
private[frontend] object BaseLinker { | |||
/** Takes a ClassDef and DCE infos to construct a stripped down LinkedClass. | |||
*/ | |||
private[frontend] def refineClassDef(classDef: ClassDef, version: Version, |
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.
Do we still need this extra method?
newJSPropertyDef.copy()(jsPropertyDef.version)(newJSPropertyDef.pos) | ||
} | ||
override def transformTopLevelExportDef(exportDef: TopLevelExportDef): TopLevelExportDef = { |
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.
IIUC this override is (now) unnecessary?
I can do that, but probably not before Wednesday. |
No worries. I will not have time before that for sure. |
a98d50a
tob21e091
CompareRebased on top of#5120. |
b21e091
toa977798
Comparea977798
to2820d22
CompareRebased. This is now back to being standalone and re-reviewable. |
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.
Just one comment regarding the name of desugaringInfo.
@@ -89,3 +92,19 @@ final class LinkedClass( | |||
def fullName: String = className.nameString | |||
} | |||
object LinkedClass { | |||
final class DesugaringInfo( |
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.
This needs somewhere a comment at the very least what the infois. (the fact that desugaring is required).
Otherwise this IMO reads more like "information needed/useful for desugaring".
Ideally this of course goes into the names, but I realize thatmethodsNeedingDesugaring
is probably a bit too long :-/
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.
If only we had Latin's gérondif 😁 We could call itAbSaccharoTemperandum
😅
PerhapsDesugaringRequirements
?
linker/shared/src/test/scala/org/scalajs/linker/IRCheckerTest.scala OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
2820d22
to4f75c5a
CompareI went for Also I changed how we construct instances of |
Previously, the emitters and the optimizer all had to perform thesame desugaring for `LinkTimeProperty` nodes. Instead, we nowperform the desugaring in a dedicated phase, after the baselinker.The reachability analysis records whether each method needsdesugaring or not. We mark those that do so that the desugaringpass knows what to process. Methods that do not requiredesugaring are not processed, and so incur no additional cost.No caching is performed in `Desugarer`. It processes so fewmethods that caching makes it (slightly) *slower*.The machinery is heavy. It definitely outweighs the benefits interms of duplication for `LinkTimeProperty` alone. However, thesame machinery will be used to desugar `NewLambda` nodes. Thiscommit serves as a stepping stone in that direction.
4f75c5a
to1987d87
Compareprivate def desugarClass(linkedClass: LinkedClass): LinkedClass = { | ||
import linkedClass._ | ||
if (desugaringRequirements.isEmpty) { |
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.
Nice!
76f7be7
intoscala-js:mainUh oh!
There was an error while loading.Please reload this page.
Previously, the emitters and the optimizer all had to perform the same desugaring for
LinkTimeProperty
nodes. Instead, we now perform the desugaring in a dedicated phase, after the base linker.The reachability analysis records whether each method needs desugaring or not. We mark those that do so that the desugaring pass knows what to process. Methods that do not require desugaring are not processed, and so incur no additional cost.
No caching is perfored in
Desugarer
. It processes so few methods that caching makes it (slightly)slower.The machinery is heavy. It definitely outweighs the benefits in terms of duplication for
LinkTimeProperty
alone. However, the same machinery will be used to desugarNewLambda
nodes. This commit serves as a stepping stone in that direction.Alternative to#5096.