Skip to content

Commit af85ec4

Browse files
committed
Load compilation units from tasty
1 parent 4ecb1f7 commit af85ec4

File tree

6 files changed

+98
-7
lines changed

6 files changed

+98
-7
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class Compiler {
4747
List(new PostTyper), // Additional checks and cleanups after type checking
4848
List(new sbt.ExtractAPI), // Sends a representation of the API of classes to sbt via callbacks
4949
List(new Pickler), // Generate TASTY info
50+
List(new LinkAll), // Link all
5051
List(new FirstTransform, // Some transformations to put trees into a canonical form
5152
new CheckReentrant, // Internal use only: Check that compiled program has no data races involving global vars
5253
new ElimJavaPackages), // Eliminate syntactic references to Java packages

compiler/src/dotty/tools/dotc/FromTasty.scala

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,8 @@ object FromTasty extends Driver {
8585
case info: ClassfileLoader =>
8686
info.load(clsd)
8787
val unpickled = clsd.symbol.asClass.tree
88-
if (unpickled != null) {
89-
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
90-
unit1.tpdTree = unpickled
91-
force.traverse(unit1.tpdTree)
92-
unit1
93-
} else
94-
cannotUnpickle(s"its class file ${info.classfile} does not have a TASTY attribute")
88+
if (unpickled != null) mkUnit(clsd, unpickled)
89+
else cannotUnpickle(s"its class file ${info.classfile} does not have a TASTY attribute")
9590
case info =>
9691
cannotUnpickle(s"its info of type ${info.getClass} is not a ClassfileLoader")
9792
}
@@ -101,4 +96,20 @@ object FromTasty extends Driver {
10196
}
10297
}
10398
}
99+
100+
def loadCompilationUnit(clsd: ClassDenotation)(implicit ctx: Context): Option[CompilationUnit] = {
101+
assert(ctx.settings.XlinkOptimise.value)
102+
clsd.dottyUnpickler.flatMap { unpickler =>
103+
ctx.log("Loading compilation unit for: " + clsd)
104+
val body = unpickler.body(ctx.addMode(Mode.ReadPositions))
105+
body.headOption.map(unpickled => mkUnit(clsd, unpickled))
106+
}
107+
}
108+
109+
private def mkUnit(clsd: ClassDenotation, unpickled: Tree)(implicit ctx: Context): CompilationUnit = {
110+
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
111+
unit1.tpdTree = unpickled
112+
force.traverse(unit1.tpdTree)
113+
unit1
114+
}
104115
}

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class ScalaSettings extends Settings.SettingGroup {
113113
val YoptPhases = PhasesSetting("-Yopt-phases", "Restrict the optimisation phases to execute under -optimise.")
114114
val YoptFuel = IntSetting("-Yopt-fuel", "Maximum number of optimisations performed under -optimise.", -1)
115115
val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying local optimisations to the .program") withAbbreviation "-optimize"
116+
val XlinkOptimise = BooleanSetting("-Xlink-optimise", "Link class files.").withAbbreviation("-Xlink-optimize")
116117

117118
/** Dottydoc specific settings */
118119
val siteRoot = StringSetting(

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import java.util.WeakHashMap
1919
import config.Config
2020
import config.Printers.{completions, incremental, noPrinter}
2121

22+
import dotty.tools.dotc.core.tasty.DottyUnpickler
23+
2224
trait SymDenotations { this: Context =>
2325
import SymDenotations._
2426

@@ -139,6 +141,8 @@ object SymDenotations {
139141
private[this] var myPrivateWithin: Symbol = initPrivateWithin
140142
private[this] var myAnnotations: List[Annotation] = Nil
141143

144+
private[dotc] var dottyUnpickler: Option[DottyUnpickler] = None
145+
142146
/** The owner of the symbol; overridden in NoDenotation */
143147
def owner: Symbol = ownerIfExists
144148

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import scala.annotation.switch
1515
import typer.Checking.checkNonCyclic
1616
import io.AbstractFile
1717
import scala.util.control.NonFatal
18+
import tasty.DottyUnpickler
1819

1920
object ClassfileParser {
2021
/** Marker trait for unpicklers that can be embedded in classfiles. */
@@ -162,6 +163,16 @@ class ClassfileParser(
162163
}
163164
}
164165

166+
if (ctx.settings.XlinkOptimise.value) {
167+
// Save references to DottyUnpickler to be able to load compilation units from tasty
168+
result match {
169+
case result@Some(_: DottyUnpickler) =>
170+
classRoot.dottyUnpickler = result.asInstanceOf[Option[DottyUnpickler]]
171+
moduleRoot.dottyUnpickler = result.asInstanceOf[Option[DottyUnpickler]]
172+
case _ =>
173+
}
174+
}
175+
165176
// eager load java enum definitions for exhaustivity check of pattern match
166177
if (isEnum) {
167178
instanceScope.toList.map(_.ensureCompleted())
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package dotty.tools.dotc.transform
2+
3+
import dotty.tools.dotc.{CompilationUnit, FromTasty}
4+
import dotty.tools.dotc.ast.Trees._
5+
import dotty.tools.dotc.ast.tpd
6+
import dotty.tools.dotc.core.Contexts._
7+
import dotty.tools.dotc.core.SymDenotations.ClassDenotation
8+
import dotty.tools.dotc.core.Symbols._
9+
import dotty.tools.dotc.core.Flags._
10+
import dotty.tools.dotc.transform.TreeTransforms._
11+
12+
/** Loads all potentially reachable trees from tasty. ▲
13+
* Only performed on whole world optimization mode. ▲ ▲
14+
*
15+
* TODO: Next step is to only load compilation units reachable in the call graph
16+
*/
17+
class LinkAll extends MiniPhaseTransform {
18+
import tpd._
19+
20+
override def phaseName = "linkAll"
21+
22+
override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = NoTransform
23+
24+
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] =
25+
if (ctx.settings.XlinkOptimise.value) super.runOn(allUnits(Set.empty, units.toSet, Set.empty))
26+
else super.runOn(units)
27+
28+
/** Loads and processes new compilation units, possibly loading more units. */
29+
private def allUnits(processed: Set[CompilationUnit], unprocessed: Set[CompilationUnit], loadedClasses: Set[ClassDenotation])(implicit ctx: Context): List[CompilationUnit] = {
30+
if (unprocessed.isEmpty) processed.toList
31+
else {
32+
val accum = new ClassesToLoadAccumulator
33+
val classesToLoad = unprocessed.foldLeft(Set.empty[ClassDenotation])((acc, unit) => accum.apply(acc, unit.tpdTree)) -- loadedClasses
34+
val loadedUnits = classesToLoad.flatMap(cls => FromTasty.loadCompilationUnit(cls))
35+
allUnits(processed ++ unprocessed, loadedUnits, loadedClasses ++ classesToLoad)
36+
}
37+
}
38+
39+
/** Collects all class denotations that may need to be loaded. */
40+
private class ClassesToLoadAccumulator extends TreeAccumulator[Set[ClassDenotation]] {
41+
private var inParents = false
42+
override def apply(acc: Set[ClassDenotation], tree: tpd.Tree)(implicit ctx: Context): Set[ClassDenotation] = tree match {
43+
case New(tpt) => accum(acc, tpt.tpe.classSymbol)
44+
case AppliedTypeTree(tpt, _) if inParents => accum(acc, tpt.symbol)
45+
case tree: RefTree if inParents || tree.symbol.is(Module) =>
46+
foldOver(accum(acc, tree.symbol), tree)
47+
case tree @ Template(constr, parents, self, _) =>
48+
val acc1 = this(acc, constr)
49+
inParents = true
50+
val acc2 = this(acc1, parents)
51+
inParents = false
52+
this(this(acc2, self), tree.body)
53+
case _ => foldOver(acc, tree)
54+
}
55+
56+
/** Accumulate class denotation for `sym` if needed */
57+
private def accum(acc: Set[ClassDenotation], sym: Symbol)(implicit ctx: Context): Set[ClassDenotation] = {
58+
val topClass = sym.topLevelClass.denot.asClass
59+
if (topClass.is(JavaDefined) || topClass.is(Scala2x) || topClass.symbol == defn.ObjectClass) acc
60+
else acc + topClass
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)