-
Notifications
You must be signed in to change notification settings - Fork 395
IntroduceLinktimeProperty
and get rid of JSLinkingInfo
#5025
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
Conversation
linker/shared/src/main/scala/org/scalajs/linker/standard/LinkTimeProperties.scala
Outdated
Show resolved
Hide resolved
1b2c4ab
to
e518c18
Compare
linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala
Show resolved
Hide resolved
38c150d
to
03e6b54
Compare
linker/shared/src/main/scala/org/scalajs/linker/analyzer/Infos.scala
Outdated
Show resolved
Hide resolved
|
There are two things we do to test deserialization hacks. First, as part of The second and most important thing is we do two-commit PRs for these changes. In the first commit, we do all the changes except changes to the compiler and libraries. This way, we force the deserialization hacks to be necessary during that commit for all the tests to pass. The second commit then changes the compiler and libraries. You can see an example of this system in the current PR for |
linker/shared/src/main/scala/org/scalajs/linker/standard/LinkTimeProperties.scala
Outdated
Show resolved
Hide resolved
linker/shared/src/main/scala/org/scalajs/linker/standard/LinkTimeProperties.scala
Outdated
Show resolved
Hide resolved
e5c7f0a
to
292e9ca
Compare
LinktimeProperty
and get rid of JSLinkingInfo
LinktimeProperty
and get rid of JSLinkingInfo
Is there any reason that the third commit (validation) is not squashed into the first commit (introduction of the IR node)? |
I made it a separate commit since it includes some messy changes (passing |
Yes, it should at least be tested before the commit that changes the compiler, since we need the deserialization hack to produce valid code. I think we should squash it even if it is messy. I don't think we have precedent for delayed validation for that reason. An alternative is to first introduce non-functional refactorings (in this case passing new things around), then have the functional commit that uses those refactorings. |
292e9ca
to
aab4f4a
Compare
Squashed 👍 |
linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala
Show resolved
Hide resolved
e8c58cd
to
4f21e7f
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.
Looks good overall. Here is a detailed review to iron out the details.
We also need new tests for user-defined globals with the name "this"
. Both through a dynamic-style access and an @JSGlobal("this")
access. We also need to test direct js.typeOf(...)
versions, since the latter produces special IR when the argument is a JSGlobalRef
(it produces a JSTypeOfGlobalRef
).
linker/shared/src/main/scala/org/scalajs/linker/standard/LinkTimeProperties.scala
Outdated
Show resolved
Hide resolved
linker/shared/src/test/scala/org/scalajs/linker/AnalyzerTest.scala
Outdated
Show resolved
Hide resolved
test-suite/js/src/test/scala/org/scalajs/testsuite/library/LinkTimePropertyTest.scala
Outdated
Show resolved
Hide resolved
@@ -51,13 +51,4 @@ class LinkingInfoTest { | |||
assertEquals(11, ESVersion.ES2020) | |||
assertEquals(12, ESVersion.ES2021) | |||
} | |||
|
|||
@Test def isolatedJSLinkingInfo(): Unit = { |
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.
We should keep this test in the second commit, since the method still exists (as deprecated).
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.
Drive-by comment 🚗
linker/shared/src/main/scala/org/scalajs/linker/standard/LinkTimeProperties.scala
Outdated
Show resolved
Hide resolved
afa8ce1
to
3c0c519
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.
You'll need to include a commit that changes the version numbers as first commit. For example
24d417a
@@ -342,7 +342,7 @@ class JSGlobalScopeTest extends DirectTest with TestHelpers { | |||
"extends", "false", "finally", "for", "function", "if", "implements", | |||
"import", "in", "instanceof", "interface", "let", "new", "null", | |||
"package", "private", "protected", "public", "return", "static", | |||
"super", "switch", /*"this",*/ "throw", "true", "try", "typeof", "var", | |||
"super", "switch", "throw", "true", "try", "typeof", "var", |
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 change should be integrated in the first commit.
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.
Or rather: the first commit should not touch this. It's the second commit that allows this
in global selections in the compiler; not the first one.
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.
Right, the first commit shouldn't touch the test 😵💫 thanks!
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.
Ah, no this change (remove "this"
from the rejectAllReservedIdentifiers
) have to be in the first commit.
Indeed we allow this
in global selections in the compiler on second commit, but we change the requirements of the IR in the first commit (isValidJSGlobalRefName
which is referred from the requirements of JSGlobalRef
)
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.
Ah but then I think we should add an explicit rejection of "this"
in the compiler
in the first commit (and then remove it in the second commit).
This way we know that the first commit does not change anything user-visible. Only the second commit introduces user-level changes.
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.
force pushed the commits to mix this change into the first commit 🙇
d5c2f7f
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.
Oops, I commented at a same timing
Ah but then I think we should add an explicit rejection of "this" in the compiler in the first commit (and then remove it in the second commit).
This way we know that the first commit does not change anything user-visible. Only the second commit introduces user-level changes.
👍
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.
So we're going to have the following changes in the first commit
diff --git a/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala b/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala
index ef5d20f12..c3dff7493 100644
--- a/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala
+++ b/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala
@@ -6758,7 +6758,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
implicit pos: Position): js.JSGlobalRef = {
propName match {
case js.StringLiteral(value) =>
- if (js.JSGlobalRef.isValidJSGlobalRefName(value)) {
+ if (js.JSGlobalRef.isValidJSGlobalRefName(value) && value != js.JSGlobalRef.FileLevelThis) {
if (value == "await") {
global.runReporting.warning(pos,
s"$actionFull of the global scope with the name '$value' is deprecated.\n" +
and remove the change + "this"
from JSGlobalScopeTest
in the second commit
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.
done, sorry for making a mess
linker/shared/src/main/scala/org/scalajs/linker/analyzer/Analyzer.scala
Outdated
Show resolved
Hide resolved
compiler/src/test/scala/org/scalajs/nscplugin/test/OptimizationTest.scala
Show resolved
Hide resolved
test-suite/js/src/test/scala/org/scalajs/testsuite/library/LinkTimePropertyTest.scala
Outdated
Show resolved
Hide resolved
3c0c519
to
30105d0
Compare
30105d0
to
f3b38df
Compare
Thank you for the thorough review! I think addressed all the feedbacks, and now waiting for the CI |
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.
Cool, looks great!
I noticed a few tiny details, but otherwise LGTM.
@gzm0 Any last-minute concerns? I believe the public API on this is very limited at this point.
linker/shared/src/main/scala/org/scalajs/linker/standard/CoreSpec.scala
Outdated
Show resolved
Hide resolved
linker/shared/src/main/scala/org/scalajs/linker/standard/LinkTimeProperties.scala
Outdated
Show resolved
Hide resolved
test-suite/js/src/test/scala/org/scalajs/testsuite/jsinterop/MiscInteropTest.scala
Show resolved
Hide resolved
a73512f
to
e26f056
Compare
87b9b43
to
d5c2f7f
Compare
No, API is limited so looks good. Is it deliberate that we do the compiler changes later? |
Yes, it is for testing deserialization hack 👍 |
That's what we always do for these pairs of commits with deserialization hacks, isn't it? Or are you talking about something else? |
ref: scala-js#5000 Previously, accessing link-time information via `scala.scalajs.runtime.linkingInfo` required interacting with a JavaScript object. That introduced JS interop in the Wasm backend causing a slowdown, and could hinder the optimization pipeline (In fact, we folded the access to `JSLinkingInfo` into `Literal`s in `OptimizerCore`). `LinkTimeProperty` is a new IR node that is guaranteed to be transformed into a `Literal` at the optimizer or backend stage. We plan to introduce a new primitive, such as `linkTimePropertyXXX`, which will be transformed into a `LinkTimeProperty` in a later commit. Additionally, we will update `scala.scalajs.LinkingInfo` to use `linkTimePropertyXXX` instead of `runtime.linkingInfo`, allowing us to eliminate the JS object when accessing link-time information. This commit also deprecates the `JSLinkingInfo` IR node. For backward compatibility, we introduced a deserialization hack that transforms `JSSelect(JSLinkingInfo(), StringLiteral(...))` into the corresponding `LinkTimeProperty`. An isolated `JSLinkingInfo` will be deserialized into a `JSObjectConstr()` containing the corresponding `LinkTimeProperty` values. Also, this commit introduces validation for `LinkTimeProperty` during reachability analysis. The Analyzer now verifies that the `LinkTimeProperty` in the IR has a valid name and type pair, ensuring it can be resolved using the provided link-time information. If an invalid `LinkTimeProperty` is detected, an error will be recorded in the `Analysis`
b8d607e
to
7bf410d
Compare
TLDR: - Add `scala.scalajs.LinkingInfo.linkTimeProperty` APIs that emits `LinkTimeProperty` IRs. - Deprecate `scala.scalajs.runtime.linkingInfo` in favor of `scala.scalajs.LinkingInfo` and `scala.scalajs.js.special.fileLevelThis`. - Keeping `scala.scalajs.runtime.linkingInfo` because Scala3 compiler looks like depends on the symbol of `runtime.linkingInfo` https://github.com/scala/scala3/blob/67cd3ebe3f70bb9045cc966af5b96a623a7da973/compiler/src/dotty/tools/backend/sjs/JSDefinitions.scala#L182-L183 This commit introduces new APIs under `scala.scalajs.LinkingInfo`: `linkTimeProperty(Int|String|Boolean)`. These APIs allow us to define link-time properties in a more optimized and JS-independent way, replacing the previous `scala.scalajs.runtime.linkingInfo`. For instance, `linkTimePropertyInt("core/esVersion")` emits the IR `LinkTimeProperty("core/esVersion")(IntType)`, which will later be transformed into an `IntLiteral` by the optimizer or linker backend. `scala.scalajs.runtime.linkingInfo` is now deprecated in favor of `scala.scalajs.LinkingInfo`. For cases where `scala.scalajs.runtime.linkingInfo.fileLevelThis` was used, users should migrate to `scala.scalajs.js.special.fileLevelThis`.
ref: #5000
Previously, accessing link-time information via
scala.scalajs.runtime.linkingInfo
required interacting with a JavaScript object. That introduced JS interop in the Wasm backend causing a slowdown, and could hinder the optimization pipeline (In fact, we folded the access toJSLinkingInfo
intoLiteral
s inOptimizerCore
).This PR introduces
LinkTimeProperty
that is a new IR node that is guaranteed to be transformed into aLiteral
at the optimizer or backend stage.scala.scalajs.LinkingInfo.linkTimeProperty(Int|Boolean|String)
APIs that emitsLinkTimeProperty
IRs.scala.scalajs.runtime.linkingInfo
in favor ofscala.scalajs.LinkingInfo
andscala.scalajs.js.special.fileLevelThis
.For instance,
linkTimePropertyInt("core/esVersion")
emits the IRLinkTimeProperty("core/esVersion")(IntType)
, which will later be transformed into anIntLiteral
by the optimizer or linker backend. (I didn't make it generic because generics makes it compilation a bit complicated for keeping it's type after erasure / the only types we want here are Literal types required byLinkingInfo
).For backward compatibility, we introduced a deserialization hacks:
JSSelect(JSLinkingInfo(), StringLiteral(...))
into the correspondingLinkTimeProperty
.JSLinkingInfo
will be deserialized into aJSObjectConstr()
containing the correspondingLinkTimeProperty
values.