Skip to content

Commit

Permalink
Emit trait method bodies in statics
Browse files Browse the repository at this point in the history
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.

Once we commit to this change, we can remove the
`lateInterfaces` bookkeeping from the backend, as we no
long will need to add ancestor interfaces as direct
parents to allow use of invokespecial for super calls.

```
> ;scalac sandbox/test.scala ; scala Test

[info] Running scala.tools.nsc.MainGenericRunner -usejavacp Test
T
C
[success] Total time: 2 s, completed 04/05/2016 11:07:13 AM
> eval "javap -classpath . -c -private C".!!
[info] ans: String = Compiled from "test.scala"
[info] public class C implements T {
[info]   public C();
[info]     Code:
[info]        0: aload_0
[info]        1: invokespecial #14                 // Method java/lang/Object."<init>":()V
[info]        4: aload_0
[info]        5: invokespecial #17                 // Method T.$init$:()V
[info]        8: getstatic     #23                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
[info]       11: ldc           #24                 // String C
[info]       13: invokevirtual #28                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
[info]       16: aload_0
[info]       17: invokespecial #32                 // Method T.foo:()I
[info]       20: pop
[info]       21: return
[info] }
> ;scalac -Yuse-trait-statics sandbox/test.scala ; scala Test

[info] Running scala.tools.nsc.MainGenericRunner -usejavacp Test
T
C
[success] Total time: 2 s, completed 04/05/2016 11:07:39 AM
> eval "javap -classpath . -c -private C".!!
[info] ans: String = Compiled from "test.scala"
[info] public class C implements T {
[info]   public C();
[info]     Code:
[info]        0: aload_0
[info]        1: invokespecial #14                 // Method java/lang/Object."<init>":()V
[info]        4: aload_0
[info]        5: invokestatic  #18                 // Method T.$init$:(LT;)V
[info]        8: getstatic     #24                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
[info]       11: ldc           #25                 // String C
[info]       13: invokevirtual #29                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
[info]       16: aload_0
[info]       17: invokestatic  #33                 // Method T.foo:(LT;)I
[info]       20: pop
[info]       21: return
[info] }
> eval "javap -classpath . -c -private T".!!
[info] ans: String = Compiled from "test.scala"
[info] public interface T {
[info]   public static int foo(T);
[info]     Code:
[info]        0: iconst_0
[info]        1: ireturn
[info]
[info]   public int foo();
[info]     Code:
[info]        0: aload_0
[info]        1: invokestatic  #15                 // Method foo:(LT;)I
[info]        4: ireturn
[info]
[info]   public static void $init$(T);
[info]     Code:
[info]        0: getstatic     #24                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
[info]        3: ldc           #25                 // String T
[info]        5: invokevirtual #29                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
[info]        8: return
[info]
[info]   public void $init$();
[info]     Code:
[info]        0: aload_0
[info]        1: invokestatic  #32                 // Method $init$:(LT;)V
[info]        4: return
[info] }
```
  • Loading branch information
retronym committed May 25, 2016
1 parent 7bc46b8 commit 6ddb9ed
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 4 deletions.
2 changes: 1 addition & 1 deletion project/ScalaOptionParser.scala
Expand Up @@ -90,7 +90,7 @@ object ScalaOptionParser {
"-Ypresentation-strict", "-Ypresentation-verbose", "-Yquasiquote-debug", "-Yrangepos", "-Yreify-copypaste", "-Yreify-debug", "-Yrepl-class-based",
"-Yrepl-sync", "-Yshow-member-pos", "-Yshow-symkinds", "-Yshow-symowners", "-Yshow-syms", "-Yshow-trees", "-Yshow-trees-compact", "-Yshow-trees-stringified", "-Ytyper-debug",
"-Ywarn-adapted-args", "-Ywarn-dead-code", "-Ywarn-inaccessible", "-Ywarn-infer-any", "-Ywarn-nullary-override", "-Ywarn-nullary-unit", "-Ywarn-numeric-widen", "-Ywarn-unused", "-Ywarn-unused-import", "-Ywarn-value-discard",
"-deprecation", "-explaintypes", "-feature", "-help", "-no-specialization", "-nobootcp", "-nowarn", "-optimise", "-print", "-unchecked", "-uniqid", "-usejavacp", "-usemanifestcp", "-verbose", "-version")
"-deprecation", "-explaintypes", "-feature", "-help", "-no-specialization", "-nobootcp", "-nowarn", "-optimise", "-print", "-unchecked", "-uniqid", "-usejavacp", "-usemanifestcp", "-verbose", "-version", "-Yuse-trait-statics")
private def stringSettingNames = List("-Xgenerate-phase-graph", "-Xmain-class", "-Xpluginsdir", "-Xshow-class", "-Xshow-object", "-Xsource-reader", "-Ydump-classes", "-Ygen-asmp",
"-Ypresentation-log", "-Ypresentation-replay", "-Yrepl-outdir", "-d", "-dependencyfile", "-encoding", "-Xscript")
private def pathSettingNames = List("-bootclasspath", "-classpath", "-extdirs", "-javabootclasspath", "-javaextdirs", "-sourcepath", "-toolcp")
Expand Down
Expand Up @@ -1061,7 +1061,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val receiverName = internalName(receiverClass)

// super calls are only allowed to direct parents
if (style.isSuper && receiverClass.isTraitOrInterface && !cnode.interfaces.contains(receiverName)) {
if (!settings.YuseTraitStatics.value && style.isSuper && receiverClass.isTraitOrInterface && !cnode.interfaces.contains(receiverName)) {
thisBType.info.get.inlineInfo.lateInterfaces += receiverName
cnode.interfaces.add(receiverName)
}
Expand All @@ -1082,7 +1082,11 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case Virtual =>
if (needsInterfaceCall(receiverClass)) bc.invokeinterface(receiverName, jname, mdescr, pos)
else bc.invokevirtual (receiverName, jname, mdescr, pos)
case Super => bc.invokespecial (receiverName, jname, mdescr, pos)
case Super =>
if (receiverClass.isTraitOrInterface && settings.YuseTraitStatics.value) {
val staticDesc = MethodBType(typeToBType(method.owner.info) :: method.info.paramTypes.map(typeToBType), typeToBType(method.info.resultType)).descriptor
bc.invokestatic(receiverName, jname, staticDesc, pos)
} else bc.invokespecial (receiverName, jname, mdescr, pos)
}

bmType.returnType
Expand Down
13 changes: 12 additions & 1 deletion src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
Expand Up @@ -488,7 +488,18 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {

case ValDef(mods, name, tpt, rhs) => () // fields are added in `genPlainClass()`, via `addClassFields()`

case dd : DefDef => genDefDef(dd)
case dd : DefDef =>
if (dd.symbol.owner.isTrait && dd.rhs != EmptyTree && !dd.symbol.isPrivate && !dd.symbol.hasFlag(Flags.STATIC)) {
// Split concrete methods in traits (including mixin constructors) into a static method
// with an explicit this parameter, and a non-static forwarder method.
val staticDefDef = global.gen.mkStatic(dd, _.cloneSymbol)
val forwarderDefDef = {
val forwarderBody = Apply(global.gen.mkAttributedRef(staticDefDef.symbol), This(dd.symbol.owner).setType(dd.symbol.owner.info) :: dd.vparamss.head.map(p => global.gen.mkAttributedIdent(p.symbol))).setType(dd.symbol.info.resultType)
deriveDefDef(dd)(_ => global.atPos(dd.pos)(forwarderBody))
}
genDefDef(staticDefDef)
genDefDef(forwarderDefDef)
} else genDefDef(dd)

case Template(_, _, body) => body foreach gen

Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Expand Up @@ -201,6 +201,7 @@ trait ScalaSettings extends AbsScalaSettings
val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
val YuseTraitStatics = BooleanSetting ("-Yuse-trait-statics", "Emit super calls to trait methods with invokestatic")

val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method")
Expand Down

0 comments on commit 6ddb9ed

Please sign in to comment.