Skip to content
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

SAM Functions from scala-java8-compat [ci: last-only] #4594

Closed
wants to merge 12 commits into from

Conversation

lrytz
Copy link
Member

@lrytz lrytz commented Jun 30, 2015

No description provided.

@scala-jenkins scala-jenkins added this to the 2.12.0-M3 milestone Jun 30, 2015
@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

locally i get this alarming outcome:

quick.bin:
    [mkdir] Created dir: /Users/luc/scala/scala/build/quick/bin

BUILD FAILED
/Users/luc/scala/scala/build.xml:69: The following error occurred while executing this line:
/Users/luc/scala/scala/build-ant-macros.xml:8: The following error occurred while executing this line:
/Users/luc/scala/scala/build.xml:1126: The following error occurred while executing this line:
/Users/luc/scala/scala/build-ant-macros.xml:331: The following error occurred while executing this line:
/Users/luc/scala/scala/build-ant-macros.xml:350: Could not create type mk-bin due to java.lang.BootstrapMethodError: call site initialization exception
    at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
    at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
    at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
    at scala.sys.BooleanProp$.keyExists(BooleanProp.scala:72)
    at scala.sys.SystemProperties$.bool(SystemProperties.scala:78)
    at scala.sys.SystemProperties$.noTraceSupression$lzycompute(SystemProperties.scala:89)
    at scala.sys.SystemProperties$.noTraceSupression(SystemProperties.scala:89)
    at scala.util.control.NoStackTrace$.<init>(NoStackTrace.scala:31)
    at scala.util.control.NoStackTrace$.<clinit>(NoStackTrace.scala)
    at scala.util.control.NoStackTrace$class.fillInStackTrace(NoStackTrace.scala:22)
    at scala.util.control.BreakControl.fillInStackTrace(Breaks.scala:94)
    at java.lang.Throwable.<init>(Throwable.java:250)
    at scala.util.control.BreakControl.<init>(Breaks.scala:94)
    at scala.util.control.Breaks.<init>(Breaks.scala:29)
    at scala.collection.Traversable$.<init>(Traversable.scala:95)
    at scala.collection.Traversable$.<clinit>(Traversable.scala)
    at scala.package$.<init>(package.scala:40)
    at scala.package$.<clinit>(package.scala)
    at scala.Predef$.<init>(Predef.scala:89)
    at scala.Predef$.<clinit>(Predef.scala)
    at scala.tools.ant.ScalaTool.<init>(ScalaTool.scala:58)
[...]
Caused by: java.lang.invoke.LambdaConversionException: Incorrect number of parameters for static method invokeStatic scala.sys.BooleanProp$.scala$sys$BooleanProp$$$anonfun$2$adapted:(String)Object; 0 captured parameters, 0 functional interface method parameters, 1 implementation parameters
    at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:193)
    at java.lang.invoke.LambdaMetafactory.altMetafactory(LambdaMetafactory.java:473)
    at java.lang.invoke.CallSite.makeSite(CallSite.java:325)

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

source code:

s => s == "" || s.equalsIgnoreCase("true")

bytecode:

    INVOKEDYNAMIC $init$()Lscala/compat/java8/JFunction1; [
      // handle kind 0x6 : INVOKESTATIC
      java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
      // arguments:
      ()V, 
      // handle kind 0x6 : INVOKESTATIC
      scala/sys/BooleanProp$.scala$sys$BooleanProp$$$anonfun$2$adapted(Ljava/lang/String;)Ljava/lang/Object;, 
      (Ljava/lang/String;)Ljava/lang/Object;, 
      3, 
      1, 
      Lscala/Serializable;.class, 
      0
    ]
    CHECKCAST scala/Function1

The mistake seems to be that the Scala compiler incorrectly selects $init$ (which is a default method) as the abstract method of JFunction1, whereas it should be apply (inherited from Function1).

Since we're doing mixed compilation, this is almost certainly a problem of the Java parser. I'll take a look.

@retronym
Copy link
Member

I think this is my bug in the backend. Try this:

diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 40ba0c0..06a7027 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -1299,7 +1299,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
       val invokedType = asm.Type.getMethodDescriptor(asmType(functionalInterface), (receiver ::: capturedParams).map(sym => toTypeKind(sym.info).toASMType): _*)

       val constrainedType = new MethodBType(lambdaParams.map(p => toTypeKind(p.tpe)), toTypeKind(lambdaTarget.tpe.resultType)).toASMType
-      val sam = functionalInterface.info.decls.find(_.isDeferred).getOrElse(functionalInterface.info.member(nme.apply))
+      val sam = functionalInterface.info.decls.find(_.isDeferredNotDefault).getOrElse(functionalInterface.info.member(nme.apply))
       val samName = sam.name.toString
       val samMethodType = asmMethodType(sam).toASMType

@retronym
Copy link
Member

Thanks for submitting this PR, BTW. I tried something similar but wasn't able to convince <scalacfork> to accept Java sources. I thought this was due to a limitation of our Ant tasks:

https://github.com/scala/scala/blob/v2.11.7/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala#L82-L116

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

ok, trying now. still, it's probably a bug in JavaParser: the symbol flags should be the same when reading from source or from classfile. $init$ should not have the DEFERRED flag

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

thanks for the ScalacFork link, i have to check what it chooses to recompile if a subset of the sources is modified.

@retronym
Copy link
Member

My theory was that the order of the decls was different in joint vs separate compilation, and that the decls.find was only working by accident.

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

The java parser sets DEFERRED even if there's a default method. Checking the access flags of a javac-produced classfile, the flag should not be there:

  // access flags 0x1
  public default $init$()V
   L0
    RETURN

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

pushed a fix to the java parser - note that the commits show in the wrong order on GitHub, the correct order is

* bdbc66c - (HEAD -> jfun, origin/jfun) Copy LambdaDeserializer from scala-java8-compat to scala.runtime (3 minutes ago) <Jason Zaugg>
* 2c0a5e1 - Copy SAM functions from java8-compat to src/library (3 minutes ago) <Lukas Rytz>
* 153beab - Fix Java parser for default methods (3 minutes ago) <Lukas Rytz>
* c8cf9f6 - Allow mixed builds in ant (2 hours ago) <Lukas Rytz>
* 18aa8af - Revert "Add scala-java8-compat to scala-library.jar" (5 hours ago) <Lukas Rytz>
* 80ee730 - (upstream/2.12.x, upstream-writable/2.12.x, scala/2.12.x, 2.12.x) Update README with required ant version on Java 8 (15 hours ago) <Adriaan Moors>

@retronym
Copy link
Member

I have a slight preference to hide JFunctionN under scala.runtime.java8, rather than scala.compat.java8. Maybe this isn't too important as they should only be a temporary addition to the library.

@retronym
Copy link
Member

osgi.core:
    [mkdir] Created dir: /home/jenkins/workspace/scala-2.12.x-validate-test@2/build/osgi
     [copy] Copying 1 file to /home/jenkins/workspace/scala-2.12.x-validate-test@2/build/osgi
      [bnd] # addAll '/home/jenkins/workspace/scala-2.12.x-validate-test@2/build/pack/lib/scala-library.jar' with :,
      [bnd] # addAll '/home/jenkins/workspace/scala-2.12.x-validate-test@2/build/osgi/scala-library.bnd' with ,
      [bnd] Updating classpath after classpathref setting
      [bnd] java.lang.ArrayIndexOutOfBoundsException: 15
      [bnd]     at aQute.lib.osgi.Clazz.parseClassFile(Clazz.java:448)
      [bnd]     at aQute.lib.osgi.Clazz.parseClassFile(Clazz.java:369)
      [bnd]     at aQute.lib.osgi.Clazz.parseClassFileWithCollector(Clazz.java:359)
      [bnd]     at aQute.lib.osgi.Clazz.parseClassFile(Clazz.java:349)
      [bnd]     at aQute.lib.osgi.Analyzer.analyzeJar(Analyzer.java:1725)
      [bnd]     at aQute.lib.osgi.Analyzer.analyzeBundleClasspath(Analyzer.java:1595)
      [bnd]     at aQute.lib.osgi.Analyzer.analyze(Analyzer.java:124)
      [bnd]     at aQute.lib.osgi.Builder.analyze(Builder.java:306)
      [bnd]     at aQute.lib.osgi.Analyzer.calcManifest(Analyzer.java:301)
      [bnd]     at aQute.lib.osgi.Builder.build(Builder.java:73)
      [bnd]     at aQute.lib.osgi.Builder.builds(Builder.java:970)
      [bnd]     at aQute.bnd.ant.BndTask.executeBackwardCompatible(BndTask.java:180)
      [bnd]     at aQute.bnd.ant.BndTask.execute(BndTask.java:87)

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

yes, i'm looking into this - any intuitive ideas?

@retronym
Copy link
Member

bndtools/bnd#603

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

@retronym
Copy link
Member

The latest is 2.4.1. We're using 1.50.0.

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

yeah, the issue you link mentions we need 2.4, i'll give it a try.

@retronym
Copy link
Member

This PR tentatively LGTM. I won't be around much to continue review for the next few days, but I think if you get through the Ant/SBT pain this ought to go in.

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

      [bnd] # addAll '/Users/luc/scala/scala/build/pack/lib/scala-library.jar' with :,
      [bnd] # addAll '/Users/luc/scala/scala/build/osgi/scala-library.bnd' with ,
      [bnd] 1 ERRORS
      [bnd]  The default package '.' is not permitted by the Import-Package syntax. 
      [bnd]  This can be caused by compile errors in Eclipse because Eclipse creates 
      [bnd] valid class files regardless of compile errors.
      [bnd] The following package(s) import from the default package [scala.collection.generic, scala.sys.process, scala.collection.parallel.mutable, scala.util, scala.collection.parallel.immutable, scala.reflect, scala.concurrent.impl, scala.util.hashing, scala.collection.parallel, scala.collection.convert, scala.io, scala, scala.collection.concurrent, scala.util.control, scala.beans, scala.concurrent.duration, scala.collection, scala.runtime, scala.math, scala.collection.mutable, scala.concurrent, scala.sys, scala.collection.immutable, scala.ref, scala.util.matching]
      [bnd] /Users/luc/scala/scala/build/osgi/scala-library.bnd: bnd failed

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

ok, thanks for your help!

@lrytz
Copy link
Member Author

lrytz commented Jun 30, 2015

i'm running out of ideas for the bnd issue (see above), maybe @adriaanm knows more? scala-library.jar doesn't have any classfiles in the empty package. can it be due to other files, e.g., versions.properties? or due to a dependency of scala-library? what would that be?

@lrytz lrytz force-pushed the jfun branch 2 times, most recently from 530d65e to a01ea0c Compare June 30, 2015 14:29
@lrytz lrytz closed this Jun 30, 2015
@lrytz lrytz changed the title SAM Functions from scala-java8-compat SAM Functions from scala-java8-compat [ci: last-only] Jun 30, 2015
@lrytz lrytz reopened this Jun 30, 2015
@adriaanm
Copy link
Contributor

From a clean (non-optimized) build, osgi.core succeeds for me. I did ant pack.done && ant osgi.done

osgi.core:
    [mkdir] Created dir: /Users/adriaan/git/scala/build/osgi
     [copy] Copying 1 file to /Users/adriaan/git/scala/build/osgi
      [bnd] # addAll '/Users/adriaan/git/scala/build/pack/lib/scala-library.jar' with :,
      [bnd] # addAll '/Users/adriaan/git/scala/build/osgi/scala-library.bnd' with ,
      [bnd] # org.scala-lang.scala-library (org.scala-lang.scala-library.jar) 4082 
      [jar] Building jar: /Users/adriaan/git/scala/build/osgi/scala-library-src.jar
     [copy] Copying 1 file to /Users/adriaan/git/scala/build/osgi
      [bnd] # addAll '/Users/adriaan/git/scala/build/pack/lib/scala-reflect.jar' with :,
      [bnd] # addAll '/Users/adriaan/git/scala/build/osgi/scala-reflect.bnd' with ,
      [bnd] # org.scala-lang.scala-reflect (org.scala-lang.scala-reflect.jar) 3049 
      [jar] Building jar: /Users/adriaan/git/scala/build/osgi/scala-reflect-src.jar
     [copy] Copying 1 file to /Users/adriaan/git/scala/build/osgi
      [bnd] # addAll '/Users/adriaan/git/scala/build/pack/lib/scala-compiler.jar' with :,
      [bnd] # addAll '/Users/adriaan/git/scala/build/osgi/scala-compiler.bnd' with ,
      [bnd] # org.scala-lang.scala-compiler (org.scala-lang.scala-compiler.jar) 10360 
      [jar] Building jar: /Users/adriaan/git/scala/build/osgi/scala-compiler-src.jar
[stopwatch] [osgi.core.timer: 16.066 sec]

@adriaanm
Copy link
Contributor

osgi.done fails, though, since 2.0.0-M2 is not a valid osgi version (scala-swing). Urgh!
It needs to be 2.0.0.M2.

Hacky fix:

diff --git i/build-ant-macros.xml w/build-ant-macros.xml
index 795779193a..b090682fcc 100644
--- i/build-ant-macros.xml
+++ w/build-ant-macros.xml
@@ -488,7 +488,7 @@
           <filter token="SCALA_COMPILER_INTERACTIVE_VERSION" value="${scala-compiler-interactive.version.number}"/>
           <filter token="XML_VERSION"                value="${scala-xml.version.number}" />
           <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" />
-          <filter token="SCALA_SWING_VERSION"        value="${scala-swing.version.number}" />
+          <filter token="SCALA_SWING_VERSION"        value="${scala-swing.version.osgi}" />
         </filterset>
       </copy>
       <bnd classpath="${@{project}.jar}" eclipse="false" failok="false" exceptions="true" files="${build-osgi.dir}/${@{project}.name}.bnd" output="${build-osgi.dir}"/>
diff --git i/versions.properties w/versions.properties
index 5fd2ac4b71..ad3d659aee 100644
--- i/versions.properties
+++ w/versions.properties
@@ -25,6 +25,7 @@ scala.binary.version=2.12.0-M1
 scala-xml.version.number=1.0.4
 scala-parser-combinators.version.number=1.0.4
 scala-swing.version.number=2.0.0-M2
+scala-swing.version.osgi=2.0.0.M2
 jline.version=2.12.1
 scala-asm.version=5.0.4-scala-2

lrytz and others added 12 commits July 1, 2015 17:36
The JFunction classes depend on the FunctionN traits, so the java
compiler needs the Scala library on the classpath.

At the same time, while compiling the Scala library, the symbols for
JFunction classes need to be available to emit indy-lambda closures.
Therefore we pass the JFunctions as Java sources while compiling the
Scala library.
Default methods (and also static methods) in interfaces should not
get the `DEFERRED` flag (they don't have it in bytecode).

Also tightens the Java parser for abstract methods to disallow a
method body.
Used revision: scala/scala-java8-compat@9253ed9

moved files to package scala.runtime.java8
The original file is here:
https://github.com/scala/scala-java8-compat/blob/master/src/main/java/scala/compat/java8/runtime/LambdaDeserializer.scala

The only difference is the package name (changed to scala.runtime).

This commit is a cherry-pick of retronym's c0732e6
Bnd 1.50 doesn't work with Java 8 classfiles, so upgrade to 2.4.1.
Also upgrade all other tools to make tests pass.

It seems that the new version of bnd only copies classfiles from the
original into the resulting jar, while the old version also copied
all other files. This is fixed by adding
  Include-Resource: @@SOURCE_JARNAME@

This makes bnd copy all resources from the source jar. I ran the
following on the osgi artifacts of this branch, and on 2.11.x:

for f in `find build/osgi -name '*.jar' -a -not -name '*src.jar'`; do unzip -l $f | grep -v '\.class' ; done

Comparing the two file lists, things look OK:
https://gist.github.com/lrytz/be08db051a53eded192d

For `org.eclipse.osgi` we moved to the group ID `org.eclipse.tycho`,
where there's a newer version available. The osgi tests would fail
with the most recent version available in the `org.eclipse.osgi` group
ID.

Sets the required java version in bnd files (JavaSE-1.8).

Introduces scala-swing.version.osgi - the version.number is not a
valid osgi version.
It tests the serialVersionUID field on closure classes. The field
doesn't exist for indyLambda closures.

See https://issues.scala-lang.org/browse/SI-9373
They fail at runtime in GenBCode since scala is built with indyLambda
enabled:

java.lang.AssertionError: assertion failed: Bad superClass for trait JFunction1: class Any
  at scala.tools.nsc.Global.assert(Global.scala:261)
  at scala.tools.nsc.backend.jvm.BTypesFromSymbols.setClassInfo(BTypesFromSymbols.scala:228)

Noted in https://issues.scala-lang.org/browse/SI-9374
The old inliner fails more often when the library is built with
indylambda.

Noted in https://issues.scala-lang.org/browse/SI-9374.

Example: List.foreach

➜  sandbox git:(jfun) ✗ qs -Ybackend:GenASM -optimize -Yinline-warnings
Welcome to Scala version 2.12.0-20150630-220939-1cb032d806 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45).
Type in expressions to have them evaluated.
Type :help for more information.

scala> List(1,2,3).foreach(x => x + 1)
<console>:11: warning: Could not inline required method foreach because bytecode unavailable.
       List(1,2,3).foreach(x => x + 1)
                          ^
<console>:11: warning: At the end of the day, could not inline @inline-marked method foreach
       List(1,2,3).foreach(x => x + 1)
                          ^
The delambdafyLambdaClassNames tests was removed, there's nothing to
tests with indyLambda.
@lrytz
Copy link
Member Author

lrytz commented Jul 1, 2015

it builds green. cleaned up the commits, so running the test again.

i think we should keep this in [ci: last-only], because for the build to be green we'd have to squash everything, which would be a huge commit of many things.

review by @adriaanm.

@lrytz
Copy link
Member Author

lrytz commented Jul 1, 2015

btw i marked these two as blockers for M2, but we can change this:

@adriaanm
Copy link
Contributor

adriaanm commented Jul 1, 2015

Sounds good to me. Let's give ourselves the rest of the week to polish M2. Does that sound like enough time? Stage on Monday/Tuesday?

@lrytz
Copy link
Member Author

lrytz commented Jul 1, 2015

macro to retrieve cross versioned artifact names

yes, but what i found gives you the full path to the jar, while we really need the filename only.

document what swing's osgi version is for

yes!

@adriaanm
Copy link
Contributor

adriaanm commented Jul 1, 2015

I think we should squash this into, say, four commits:

  • one commit per bug fix (parser, deserializer) -- should be all green
  • incorporating java sources + required build updates (mixed mode, osgi) -- can be red, to show failing tests
  • move failing tests to pending (green)

@adriaanm
Copy link
Contributor

adriaanm commented Jul 1, 2015

Happy to do the rebasing this morning.

@adriaanm adriaanm mentioned this pull request Jul 1, 2015
@adriaanm adriaanm modified the milestones: 2.12.0-M3, 2.12.0-M2 Jul 1, 2015
@lrytz
Copy link
Member Author

lrytz commented Jul 1, 2015

#4597

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants