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

Sharing GenBcode backend between scalac and dotty #4136

Closed
wants to merge 46 commits into from

Conversation

DarkDimius
Copy link
Member

This PR abstracts GenBcode implementation classes from existence of global using forwarders, which would have a different implementation in dotty.

The main class here is BackendInterface that defines everything that backend uses.
While it would be good to have backend use less that 150 methods on Symbol this commit doesn't address this issue: it tries to not introduce any changes in behavior.

In order to not loose perfromance and not allocate options during pattern matching this implemtation relies on name-based pattern matching with preallocated objects, this makes BackendInterface non-thread safe, but as of now it is used only in single thread. If several threads will ever be used to transfrom AST to asm bytecode than each of threads will need to own its own instance of BackendInterface.

@lrytz please have a look.

@scala-jenkins scala-jenkins added this to the 2.11.5 milestone Nov 18, 2014
@DarkDimius
Copy link
Member Author

I cannot reproduce error with which jenkins failed: https://scala-webapps.epfl.ch/jenkins/job/pr-scala-publish-core/4763/console
scala.reflect.internal.FatalError: object ScalaRunTime does not have a member hash
It does and on my local setup it can find it.
I'm not aware of internal specifics of how symbol loading in scalac is organized. @lrytz could you please have a look?

@gkossakowski
Copy link
Member

Did you try ant all.clean && ant?

@DarkDimius
Copy link
Member Author

I've tried making a clean clone and building it.
Now I've checked with ant all.clean still works(ie can't reproduce error).

@retronym
Copy link
Member

I reproduced it with:

% cat build.properties
#locker.skip=1
starr.use.released=1

% ant all.clean build-opt

init:
     [copy] Copying 2 files to /Users/jason/code/scala2/build/deps/junit
     [copy] Copying 6 files to /Users/jason/code/scala2/build/deps/partest
     [copy] Copying 1 file to /Users/jason/code/scala2/build/deps/repl
     [copy] Copying 5 files to /Users/jason/code/scala2/build/deps/scaladoc
     [echo] Using Scala 2.11.2 for STARR.
     [copy] Copying 5 files to /Users/jason/code/scala2/build/deps/starr
     [echo]        build time: 19 November 2014, 08:39:01
     [echo]      java version: Java HotSpot(TM) 64-Bit Server VM 1.8.0_25 (1.8)
     [echo]         java args: -Xmx3g -Xms3g -XX:+TieredCompilation -XX:ReservedCodeCacheSize=256m -XX:MaxPermSize=384m -XX:+UseNUMA -XX:+UseParallelGC
     [echo]        javac args:
     [echo]       scalac args: -feature  -optimise
     [echo] scalac quick args: -feature  -optimise
     [echo]          git date: 20141118-214623
     [echo]          git hash: 4c66397573
     [echo]     maven version: 2.11.5-SNAPSHOT
     [echo]      OSGi version: 2.11.5.v20141118-214623-4c66397573
     [echo] canonical version: 2.11.5-20141118-214623-4c66397573

asm.done:
    [mkdir] Created dir: /Users/jason/code/scala2/build/asm/classes
    [javac] Compiling 82 source files to /Users/jason/code/scala2/build/asm/classes
    [javac] warning: [options] bootstrap class path not set in conjunction with -source 1.5
    [javac] warning: [options] source value 1.5 is obsolete and will be removed in a future release
    [javac] warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
    [javac] Note: Some input files use unchecked or unsafe operations.
    [javac] Note: Recompile with -Xlint:unchecked for details.
    [javac] 3 warnings
[stopwatch] [asm.timer: 1.549 sec]
    [mkdir] Created dir: /Users/jason/code/scala2/build/libs

forkjoin.done:
    [mkdir] Created dir: /Users/jason/code/scala2/build/libs/classes/forkjoin
    [javac] Compiling 10 source files to /Users/jason/code/scala2/build/libs/classes/forkjoin
    [javac] warning: [options] bootstrap class path not set in conjunction with -source 1.5
    [javac] warning: [options] source value 1.5 is obsolete and will be removed in a future release
    [javac] warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
    [javac] 3 warnings
    [javac] Creating empty /Users/jason/code/scala2/build/libs/classes/forkjoin/scala/concurrent/forkjoin/package-info.class
      [jar] Building jar: /Users/jason/code/scala2/build/libs/forkjoin.jar
[stopwatch] [forkjoin.timer: 0.273 sec]

locker.start:

locker.lib:
    [mkdir] Created dir: /Users/jason/code/scala2/build/locker/classes/library
    [javac] Compiling 32 source files to /Users/jason/code/scala2/build/locker/classes/library
    [javac] warning: [options] bootstrap class path not set in conjunction with -source 1.5
    [javac] warning: [options] source value 1.5 is obsolete and will be removed in a future release
    [javac] warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
    [javac] 3 warnings
[locker.library] Compiling 579 files to /Users/jason/code/scala2/build/locker/classes/library
[locker.library] Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0
[locker.library] /Users/jason/code/scala2/src/library/scala/SerialVersionUID.scala:15: warning: Implementation restriction: subclassing Classfile does not
[locker.library] make your annotation visible at runtime.  If that is what
[locker.library] you want, you must write the annotation class in Java.
[locker.library] class SerialVersionUID(value: Long) extends scala.annotation.ClassfileAnnotation
[locker.library]       ^
[locker.library] warning: there were 120 deprecation warnings; re-run with -deprecation for details
[locker.library] warning: there was one unchecked warning; re-run with -unchecked for details
[locker.library] warning: there were 348 inliner warnings; re-run with -Yinline-warnings for details
[locker.library] four warnings found
[propertyfile] Creating new property file: /Users/jason/code/scala2/build/locker/classes/library/library.properties
[stopwatch] [locker.library.timer: 46.579 sec]

locker.reflect:
    [mkdir] Created dir: /Users/jason/code/scala2/build/locker/classes/reflect
[locker.reflect] Compiling 157 files to /Users/jason/code/scala2/build/locker/classes/reflect
[locker.reflect] Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0
[locker.reflect] warning: there were 60 deprecation warnings; re-run with -deprecation for details
[locker.reflect] warning: there were two unchecked warnings; re-run with -unchecked for details
[locker.reflect] warning: there were 74 inliner warnings; re-run with -Yinline-warnings for details
[locker.reflect] three warnings found
[propertyfile] Creating new property file: /Users/jason/code/scala2/build/locker/classes/reflect/reflect.properties
[stopwatch] [locker.reflect.timer: 46.396 sec]

locker.comp:
    [mkdir] Created dir: /Users/jason/code/scala2/build/locker/classes/compiler
[locker.compiler] Compiling 303 files to /Users/jason/code/scala2/build/locker/classes/compiler
[locker.compiler] Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0
[locker.compiler] /Users/jason/code/scala2/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala:444: warning: could not emit switch for @switch annotated match
[locker.compiler]       (const.tag: @switch) match {
[locker.compiler]                    ^
[locker.compiler] warning: there were 169 deprecation warnings; re-run with -deprecation for details
[locker.compiler] warning: there were 17 unchecked warnings; re-run with -unchecked for details
[locker.compiler] warning: there were 262 inliner warnings; re-run with -Yinline-warnings for details
[locker.compiler] four warnings found
[propertyfile] Creating new property file: /Users/jason/code/scala2/build/locker/classes/compiler/compiler.properties
     [copy] Copying 5 files to /Users/jason/code/scala2/build/locker/classes/compiler
[stopwatch] [locker.compiler.timer: 1:22.784 sec]

locker.done:

quick.start:

quick.lib:
    [mkdir] Created dir: /Users/jason/code/scala2/build/quick/classes/library
    [javac] Compiling 32 source files to /Users/jason/code/scala2/build/quick/classes/library
    [javac] warning: [options] bootstrap class path not set in conjunction with -source 1.5
    [javac] warning: [options] source value 1.5 is obsolete and will be removed in a future release
    [javac] warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
    [javac] 3 warnings
[quick.library] Compiling 579 files to /Users/jason/code/scala2/build/quick/classes/library
[quick.library] Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0
[quick.library] error: scala.reflect.internal.FatalError: object ScalaRunTime does not have a member hash
[quick.library]     at scala.reflect.internal.Definitions$DefinitionsClass.scala$reflect$internal$Definitions$DefinitionsClass$$fatalMissingSymbol(Definitions.scala:1181)
[quick.library]     at scala.reflect.internal.Definitions$DefinitionsClass.getMember(Definitions.scala:1198)
[quick.library]     at scala.tools.nsc.backend.jvm.ScalacBackendInterface.<init>(ScalacBackendInterface.scala:111)
[quick.library]     at scala.tools.nsc.backend.icode.GenICode.<init>(GenICode.scala:34)
[quick.library]     at scala.tools.nsc.Global$genicode$.<init>(Global.scala:585)
[quick.library]     at scala.tools.nsc.Global.genicode$lzycompute(Global.scala:581)
[quick.library]     at scala.tools.nsc.Global.genicode(Global.scala:581)
[quick.library]     at scala.tools.nsc.Global.computeInternalPhases(Global.scala:703)
[quick.library]     at scala.tools.nsc.Global.computePhaseDescriptors(Global.scala:735)
[quick.library]     at scala.tools.nsc.Global.phaseDescriptors$lzycompute(Global.scala:742)

@retronym
Copy link
Member

Here's a fix:

retronym@ac75d10

You must not call into Definitions before Definitions#init() has been called.

@DarkDimius
Copy link
Member Author

@retronym thanks for help!

I tried to run all testsuite with modified genbcode. I have failures for tests such as pos/t5545, but it seems that I'm bug compatible with https://issues.scala-lang.org/browse/SI-8431
@lrytz Are you up to review? Should I squash commits or would it be easier for you review them separately?

@DarkDimius
Copy link
Member Author

The left failures are one neg and one run. I can reproduce neither of those. I can compile failed tests by hand with self-bootstrapped compiler, while it seems that in Jenkins they fail with NPE. I don't have a stacktrace to see where this NPE was issued, so I'm not sure how to fix it.

@retronym
Copy link
Member

The test failure was just a friendly reminder you either to regenerate the source of JavaUniverseForce or to restore the previous order of the members of Definition. It didn't mean that semantics of the compiler were affected by that ordering.

@retronym
Copy link
Member

@DarkDimius I am also unable to locally reproduce the test failures in

neg/case-collision2.scala
test/files/run/t8925.scala

After building a merge of d37ad and origin/2.11.x.

Let's see if it is deterministic:

PLS REBUILD/pr-scala@d37adac374f4127f66ff74e8cac756f6e0f74665

@scala-jenkins
Copy link

(kitty-note-to-self: ignore 63910525)
🐱 Roger! Rebuilding pr-scala for d37adac. 🚨

@sjrd
Copy link
Member

sjrd commented Nov 21, 2014

OMG this is definitely going to endanger the cross-compilation of the Scala.js backend against all versions of Scala ...
I will try to compile Scala.js against this branch, and see how much breaks, and whether I can come up with more implicit magic to survive this.

Note that I'm not even speaking about actually using that abstraction. At first glance, at least the changes in ScalaPrimitives are not source compatible.


if(!int.shouldEmitJumpAfterLabels) genNormalBlock
else {
val (prefixLabels: List[LabelDef], stats1) = stats.span {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[locker.compiler] /Users/luc/scala/scala2/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala:857: warning: abstract type LabelDef in type pattern List[BCodeBodyBuilder.this.int.LabelDef] (the underlying of List[BCodeBodyBuilder.this.int.LabelDef]) is unchecked since it is eliminated by erasure
[locker.compiler]         val (prefixLabels: List[LabelDef], stats1) = stats.span {
[locker.compiler]                            ^

val LongTag: ConstantTag
val StringTag: ConstantTag
val ClazzTag: ConstantTag
val EnumTag: ConstantTag
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This abstraction breaks the @switch in genConstant:

[quick.compiler] /Users/luc/scala/scala2/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala:459: warning: could not emit switch for @switch annotated match
[quick.compiler]       (const.tag: @switch) match {
[quick.compiler]                    ^

Not specific to this change: We need to do at least some performance testing to get a feeling for the performance penalty before adding the new abstraction layer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this particular abstraction, actual ConstantTag==Long values are same in dotty and scalac, so if this particular place introduces a slowdown it could be solved.
The way how I observe how fast is the compiler is time that is taken to compile standard library. Before 2d22839 it was 10% slower. After I didn't check.

Handling Ident's in dotty requires analysing its type,
Instead of exporting a lot of abstractions around types
I'd better go with a single method that hides this.
*/
for (i <- args.length until dims) elemKind = ArrayBType(elemKind)
}
(argsSize : @switch) match {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you remove the @swtich here? it triggers a warning:

[quick.compiler] /Users/luc/scala/scala2/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala:606: warning: matches with two cases or fewer are emitted using if-then-else instead of switch
[quick.compiler]       (argsSize : @switch) match {
[quick.compiler]                    ^

retronym and others added 2 commits December 5, 2014 18:28
This is a re-run of SI-5158 in two different contexts.

As reported, the result of `unapply[Seq]` under name based pattern
matching might not guarantee stability of results of calls to
`_1`, `apply(i)`, etc, so we call these eagerly, and call them
once only.

I also found a case in regular pattern matching that we hadn't
accounted for: extracting elements of sequences (either from
a case class or from an `unapplySeq`) may also be unstable.

This commit changes `ExtractorTreeMaker` to force storage
of such binders, even under `-optimize`. This parallels the change
to `ProductExtractorTreeMaker` in 8ebe8e3.

I have added a special case for traditional `unapply` methods
returning `Option`. This avoids a change for:

```
% cat test/files/run/t9003b.scala
object Single {
  def unapply(a: Any) = Some("")
}

object Test {
  def main(args: Array[String]): Unit = {
    "" match {
      case Single(x) =>
        (x, x)
    }
  }
}
% qscalac -optimize -Xprint:patmat test/files/run/t9003b.scala 2>&1 | grep --context=5 get
      case <synthetic> val x1: Any = "";
      case5(){
        <synthetic> val o7: Some[String] = Single.unapply(x1);
        if (o7.isEmpty.unary_!)
          matchEnd4({
            scala.Tuple2.apply[String, String](o7.get, o7.get);
            ()
          })
        else
          case6()
      };
% scalac-hash v2.11.4 -optimize -Xprint:patmat test/files/run/t9003b.scala 2>&1 | grep --context=5 get
      case <synthetic> val x1: Any = "";
      case5(){
        <synthetic> val o7: Some[String] = Single.unapply(x1);
        if (o7.isEmpty.unary_!)
          matchEnd4({
            scala.Tuple2.apply[String, String](o7.get, o7.get);
            ()
          })
        else
          case6()
      };
```
needed to handle array_clone in dotty. Which doesn't have a symbol but isn't byte code primitive operation
@@ -637,7 +644,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self =>
def descriptor(k: TypeKind): String = { javaType(k).getDescriptor }
def descriptor(s: Symbol): String = { javaType(s).getDescriptor }

def javaType(tk: TypeKind): asm.Type = {
def javaType(tk: TypeKinds#TypeKind): asm.Type = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these projections in GenASM still necessary?

@adriaanm adriaanm modified the milestones: 2.11.5, 2.11.6 Dec 11, 2014
DarkDimius added a commit to dotty-staging/dotty that referenced this pull request Dec 12, 2014
DarkDimius added a commit to dotty-staging/dotty that referenced this pull request Dec 15, 2014
DarkDimius added a commit to dotty-staging/dotty that referenced this pull request Dec 16, 2014
@lrytz
Copy link
Member

lrytz commented Dec 18, 2014

Let's close this one for now, as it requires a chunk of work.

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