-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Emit trait method bodies in statics #5177
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
56fe5cd
to
77dfcfe
Compare
Module bootstrap progressing well: https://scala-ci.typesafe.com/job/scala-2.12.x-integrate-bootstrap/424/console => I need to update some tests now.
|
c50b219
to
0daf45d
Compare
Another swing at the bootstrap: https://scala-ci.typesafe.com/job/scala-2.12.x-integrate-bootstrap/426/ |
@lrytz I'm a bit stuck trying to teach the inliner about the new setup. I'm working on I found the
|
i'll take a look today |
@retronym i think your approach works fine, here's a WIP that identifies trait forwarders invoking static impl meethods well enough (i'd say): lrytz@9f50d64 (needs cleaning up) |
lrytz@9f50d64 is the latest WIP |
892f325
to
3577041
Compare
@lrytz thanks for that. I've cleaned it up by:
I'll continue now with the job of adapting the JUnit tests for the optimizer, and then seeing how partest goes. |
@@ -123,6 +123,8 @@ object BytecodeUtils { | |||
|
|||
def isReference(t: Type) = t.getSort == Type.OBJECT || t.getSort == Type.ARRAY | |||
|
|||
def isScala(classNode: ClassNode) = classNode.attrs != null && classNode.attrs.asScala.exists(a => a.`type` == BTypes.ScalaAttributeName || a.`type` == BTypes.ScalaSigAttributeName) |
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 just was a bit confused why this works, because the scala pickle is stored in the ScalaSignature
annotation nowadays (no longer in the ScalaSig
attribute), but it turns out we still put the attribute. do you know if we have a test for that?
scala/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
Lines 1119 to 1121 in 2e40aa5
val ssa = getAnnotPickle(bType.internalName, moduleClass.companionSymbol) | |
mirrorClass.visitAttribute(if (ssa.isDefined) pickleMarkerLocal else pickleMarkerForeign) | |
emitAnnotations(mirrorClass, moduleClass.annotations ++ ssa) |
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.
The switch to annotation was made in ef1577a. I don't know whether leaving the attribute was intentional or an oversight.
87400b7
to
8aec58e
Compare
@lrytz I found a different approach to fixing trait inlining that seems to work better, I changed the backend to use the inline metadata of the forward method for the static method, too. This has got all the JUnit tests working again. I'm running a bootstrap build again to run the partest suite, too: https://scala-ci.typesafe.com/view/scala-2.12.x/job/scala-2.12.x-integrate-bootstrap/433/console |
I found a problem:
|
@retronym for your fix to the inliner metadata, I think it's a bit of a hack; we should start by adding an entry for the newly-generated static method to the |
to expand: what happens in your fix is that the static method is inlined into the forwarder. the only reason this didn't happen before is because the We did rely on the same mechanics before, when we still had trait impl classes. |
@retronym I implemented the change to represent the static methods in the ScalaInlineInfo: retronym/scala@topic/trait-statics...lrytz:pr5177 There's first commit is necessary to fix a cross-talk between tests, the test introduced in the last commit would cause some other tests to fail otherwise. The second commit is a similar fix, but not related to this PR. |
@retronym the implementation of The problem is that when building the |
@lrytz I'm going to try to move things back to |
Oh. That would be a pity for Scala.js. the JS backend is very happy with the current trees. It doesn't need those static methods. |
12ab0f0
to
ec6af82
Compare
@retronym how about just adding |
Great! Let's get that STARR published (I agree maven is the best location). (EDIT: I also experimented with publishing internally, but we'll go the same route as last time -- via maven) |
I tried to see how the community build performs here, but couldn't get it running. The problem is that we fix scala-xml and scala-partest to 2.12.0-M4, which is not binary compatible. The result is crashes when using scaladoc:
I tried a few hacks, including
Note that #4851 would fix the problem for scaladoc and parser-combinators, but we might still have it for projects using xml or parser-combinators in other ways. |
213c6d3
to
4e8f2f9
Compare
Following the "bootstrap plan" we used in #5003
|
This corrects an error in the change to the trait encoding in scala#5003: getters in traits should have empty bodies and be emitted as abstract. ``` % ~/scala/2.12.0-M4/bin/scalac sandbox/test.scala && javap -c T Compiled from "test.scala" public interface T { public abstract void T$_setter_$x_$eq(int); public int x(); Code: 0: aload_0 1: invokeinterface #15, 1 // InterfaceMethod x:()I 6: ireturn public int y(); Code: 0: aload_0 1: invokeinterface #20, 1 // InterfaceMethod y:()I 6: ireturn public void y_$eq(int); Code: 0: aload_0 1: iload_1 2: invokeinterface #24, 2 // InterfaceMethod y_$eq:(I)V 7: return public void $init$(); Code: 0: aload_0 1: bipush 42 3: invokeinterface #29, 2 // InterfaceMethod T$_setter_$x_$eq:(I)V 8: aload_0 9: bipush 24 11: invokeinterface #24, 2 // InterfaceMethod y_$eq:(I)V 16: return } % qscalac sandbox/test.scala && javap -c T Compiled from "test.scala" public interface T { public abstract void T$_setter_$x_$eq(int); public abstract int x(); public abstract int y(); public abstract void y_$eq(int); public static void $init$(T); Code: 0: aload_0 1: bipush 42 3: invokeinterface #21, 2 // InterfaceMethod T$_setter_$x_$eq:(I)V 8: aload_0 9: bipush 24 11: invokeinterface #23, 2 // InterfaceMethod y_$eq:(I)V 16: return public void $init$(); Code: 0: aload_0 1: invokestatic #27 // Method $init$:(LT;)V 4: return } ```
This partially reverts the fix for SI-5278 made in 7a99c03. The original motivation for this case to avoid bytecode that stretched platform limitations in Android. For super calls to Scala defined trait methods, we won't use `invokespecial`, but rather use `invokestatic` to a static trait implementation method. As such, we can continue to prune redundant Scala interfaces. It might be worth considering removing the pruning of redundant parents altoghether, though: - We no longer include `ScalaObject` as a parent of every class, which was mentioned as a problem in SI-5728. - Scala 2.12 has left Android behind for the time being due to use of Java 8 facilities. - javac doesn't do this, so why should we?
4e8f2f9
to
6f7f32d
Compare
bootstrap build on latest rev https://scala-ci.typesafe.com/view/scala-2.12.x/job/scala-2.12.x-integrate-bootstrap/467/console |
And use this as the target of the default methods or statically resolved super or $init calls. The call-site change is predicated on `-Yuse-trait-statics` as a stepping stone for experimentation / bootstrapping. I have performed this transformation in the backend, rather than trying to reflect this in the view from Scala symbols + ASTs. We also need to add an restriction related to invokespecial to Java parents: to support a super call to one of these to implement a super accessor, the interface must be listed as a direct parent of the class. The static method names has a trailing $ added to avoid duplicate name and signature errors in classfiles.
6f7f32d
to
4d20b81
Compare
Community build using those bootstrapped modules, and fully bootstrapped scala by dbuild (can't skip locker due to binary incompat): https://scala-ci.typesafe.com/view/scala-2.12.x/job/scala-2.12.x-integrate-community-build/432/console |
bd66724
to
cb57729
Compare
The process of restarring will be a tiny bit easier than last time after #5229 is merged. |
cb57729
to
4d20b81
Compare
Moving to the rebased PR |
Emit trait method bodies in statics [rebase of #5177]
In 2.12.0-M4 / #5003, we changed the trait encoding to do away with trait implementation classes, in favour of leaving trait methods in place as interface default methods.
However, we've since discovered that we can no longer precisely target a particular statically resolved method with
invokespecial
due to impedance mismatch between JVM and Scala semantics.This pull request emits a pair of methods for each concrete trait method. The default method remains, with the same signature as before. However, it now forwards to a same-named static method (with an explicit self param) that contains the method code.
This encoding allows us to precisely target a particular method with
invokestatic
.This is binary incompatible, and will require bootstrapping of the modules.
(More details to follow)