Skip to content

Commit

Permalink
GenBCode: fix incrementatal compilation by mimicing GenASM
Browse files Browse the repository at this point in the history
The incremental compiler in SBT uses an implementation detail
of the compiler backend to enumerate the classes that are actually
written to disk.

This commit mimics this in GenBCode by populating `Run#icode` with
an `IClass` for each `ClassDef` processed.

We should revisit this by creating a dedicated API for this purpose
and migrating SBT to use that. We should also revisit this code
as we implement closure elimination in the GenBCode; this commit
assumes that all `ClassDef`s that enter the backend will generate
classfile products.

The enclosed test is extracted from the incrementatl compiler.

I've also manually integration tested this with SBT:

  https://gist.github.com/retronym/fabf6f92787ea9c1ce67
  • Loading branch information
retronym committed Jun 28, 2015
1 parent 950bb26 commit b17a291
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ abstract class GenBCode extends BCodeSyncAndTry {
)
}

// shim for SBT, see https://github.com/sbt/sbt/issues/2076
// TODO put this closer to classfile writing once we have closure elimination
// TODO create a nicer public API to find out the correspondence between sourcefile and ultimate classfiles
currentUnit.icode += new icodes.IClass(cd.symbol)

// -------------- mirror class, if needed --------------
val mirrorC =
if (isTopLevelModuleClass(claszSymbol)) {
Expand Down
42 changes: 42 additions & 0 deletions test/files/run/sbt-icode-interface.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import scala.tools.partest._
import scala.tools.nsc._

object Test extends DirectTest {

def code = """
class C { class D }
object O
""".trim

def show() {
for (b <- List("GenASM", "GenBCode")) {
val global = newCompiler("-usejavacp", s"-Ybackend:$b")
import global._
val r = new Run
r.compileSources(newSourceFile(code) :: Nil)

val results = collection.mutable.Buffer[(Boolean, String)]()

// Nailing down defacto compiler API from SBT's usage
// https://github.com/sbt/sbt/blob/adb41611cf73260938274915d8462d924df200c8/compile/interface/src/main/scala/xsbt/Analyzer.scala#L29-L41
def isTopLevelModule(sym: Symbol) = sym.isTopLevel && sym.isModule
for (unit <- currentRun.units if !unit.isJava) {
val sourceFile = unit.source.file.file
for (iclass <- unit.icode) {
val sym = iclass.symbol
def addGenerated(separatorRequired: Boolean) {
results += (separatorRequired -> sym.fullName)
}
if (sym.isModuleClass && !sym.isImplClass) {
if (isTopLevelModule(sym) && sym.companionClass == NoSymbol)
addGenerated(false)
addGenerated(true)
} else
addGenerated(false)
}
}
val expected = List((false, "C"), (true, "O"), (false, "C$D"))
assert(results.toList == expected, b + ": " + results.toList)
}
}
}

0 comments on commit b17a291

Please sign in to comment.