Skip to content

Commit 2cab739

Browse files
committed
Produce one TASTY pickling per top-level class.
If a unit has several top-level classes or object (which are not linked classes of each other) each gets its own pickle information, which contains any enclosing package clauses and imports and then just the top-level class/object and its companion object.
1 parent 6927c1a commit 2cab739

File tree

4 files changed

+73
-32
lines changed

4 files changed

+73
-32
lines changed

src/dotty/tools/backend/jvm/GenBCode.scala

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,12 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
175175
val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName) else null;
176176
val plainC = pcb.cnode
177177

178-
if ((!claszSymbol.companionClass.exists) || !claszSymbol.is(Flags.Module)) {
179-
// generate TASTY on class if it is there, or on module if it has no companion class
180-
181-
val binary = ctx.compilationUnit.pickler.assembleParts()
182-
val dataAttr = new CustomAttr(nme.DottyTASTYATTR.toString, binary)
183-
plainC.visitAttribute(dataAttr)
184-
}
185-
178+
if (claszSymbol.isClass) // @DarkDimius is this test needed here?
179+
for (pickler <- ctx.compilationUnit.picklers.get(claszSymbol.asClass)) {
180+
val binary = pickler.assembleParts()
181+
val dataAttr = new CustomAttr(nme.DottyTASTYATTR.toString, binary)
182+
plainC.visitAttribute(dataAttr)
183+
}
186184

187185
// -------------- bean info class, if needed --------------
188186
val beanC =

src/dotty/tools/dotc/CompilationUnit.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ class CompilationUnit(val source: SourceFile) {
1919
def isJava = source.file.name.endsWith(".java")
2020

2121
/**
22-
* Pickler used to create TASTY sections.
22+
* Picklers used to create TASTY sections, indexed by toplevel class to which they belong.
2323
* Sections: Header, ASTs and Positions are populated by `pickler` phase.
2424
* Subsequent phases can add new sections.
2525
*/
26-
lazy val pickler: TastyPickler = new TastyPickler()
26+
var picklers: Map[ClassSymbol, TastyPickler] = Map()
2727

2828
/**
2929
* Addresses in TASTY file of trees, stored by pickling.

src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,34 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
461461
accum(Nil, root)
462462
}
463463

464+
465+
/** The top level classes in this tree, including only those module classes that
466+
* are not a linked class of some other class in the result.
467+
*/
468+
def topLevelClasses(tree: Tree)(implicit ctx: Context): List[ClassSymbol] = tree match {
469+
case PackageDef(_, stats) => stats.flatMap(topLevelClasses)
470+
case tdef: TypeDef if tdef.symbol.isClass => tdef.symbol.asClass :: Nil
471+
case _ => Nil
472+
}
473+
474+
/** The tree containing only the top-level classes and objects matching either `cls` or its companion object */
475+
def sliceTopLevel(tree: Tree, cls: ClassSymbol)(implicit ctx: Context): List[Tree] = tree match {
476+
case PackageDef(pid, stats) =>
477+
cpy.PackageDef(tree)(pid, stats.flatMap(sliceTopLevel(_, cls))) :: Nil
478+
case tdef: TypeDef =>
479+
val sym = tdef.symbol
480+
assert(sym.isClass)
481+
if (cls == sym || cls == sym.linkedClass) tdef :: Nil
482+
else Nil
483+
case vdef: ValDef =>
484+
val sym = vdef.symbol
485+
assert(sym is Module)
486+
if (cls == sym.companionClass || cls == sym.moduleClass) vdef :: Nil
487+
else Nil
488+
case tree =>
489+
tree :: Nil
490+
}
491+
464492
/** The statement sequence that contains a definition of `sym`, or Nil
465493
* if none was found.
466494
* For a tree to be found, The symbol must have a position and its definition

src/dotty/tools/dotc/transform/Pickler.scala

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import config.Printers.{noPrinter, pickling}
99
import java.io.PrintStream
1010
import Periods._
1111
import Phases._
12+
import Symbols._
13+
import Flags.Module
1214
import collection.mutable
1315

1416
/** This phase pickles trees */
@@ -23,28 +25,41 @@ class Pickler extends Phase {
2325
s.close
2426
}
2527

26-
private val beforePickling = new mutable.HashMap[CompilationUnit, String]
28+
private val beforePickling = new mutable.HashMap[ClassSymbol, String]
29+
30+
/** Drop any elements of this list that are linked module classes of other elements in the list */
31+
private def dropCompanionModuleClasses(clss: List[ClassSymbol])(implicit ctx: Context): List[ClassSymbol] = {
32+
val companionModuleClasses =
33+
clss.filterNot(_ is Module).map(_.linkedClass).filterNot(_.isAbsent)
34+
clss.filterNot(companionModuleClasses.contains)
35+
}
2736

2837
override def run(implicit ctx: Context): Unit = {
2938
val unit = ctx.compilationUnit
30-
val tree = unit.tpdTree
3139
pickling.println(i"unpickling in run ${ctx.runId}")
32-
if (ctx.settings.YtestPickler.value) beforePickling(unit) = tree.show
3340

34-
val pickler = unit.pickler
35-
val treePkl = new TreePickler(pickler)
36-
treePkl.pickle(tree :: Nil)
37-
unit.addrOfTree = treePkl.buf.addrOfTree
38-
unit.addrOfSym = treePkl.addrOfSym
39-
if (tree.pos.exists)
40-
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)
41+
for { cls <- dropCompanionModuleClasses(topLevelClasses(unit.tpdTree))
42+
tree <- sliceTopLevel(unit.tpdTree, cls) } {
43+
if (ctx.settings.YtestPickler.value) beforePickling(cls) = tree.show
44+
val pickler = new TastyPickler()
45+
unit.picklers += (cls -> pickler)
46+
val treePkl = new TreePickler(pickler)
47+
treePkl.pickle(tree :: Nil)
48+
unit.addrOfTree = treePkl.buf.addrOfTree
49+
unit.addrOfSym = treePkl.addrOfSym
50+
if (tree.pos.exists)
51+
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)
4152

42-
def rawBytes = // not needed right now, but useful to print raw format.
43-
unit.pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
44-
case (row, i) => s"${i}0: ${row.mkString(" ")}"
53+
def rawBytes = // not needed right now, but useful to print raw format.
54+
pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
55+
case (row, i) => s"${i}0: ${row.mkString(" ")}"
56+
}
57+
// println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
58+
if (pickling ne noPrinter) {
59+
println(i"**** pickled info of $cls")
60+
new TastyPrinter(pickler.assembleParts()).printContents()
4561
}
46-
// println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
47-
if (pickling ne noPrinter) new TastyPrinter(pickler.assembleParts()).printContents()
62+
}
4863
}
4964

5065
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
@@ -58,23 +73,23 @@ class Pickler extends Phase {
5873
pickling.println(i"testing unpickler at run ${ctx.runId}")
5974
ctx.definitions.init
6075
val unpicklers =
61-
for (unit <- units) yield {
62-
val unpickler = new DottyUnpickler(unit.pickler.assembleParts())
76+
for (unit <- units; (cls, pickler) <- unit.picklers) yield {
77+
val unpickler = new DottyUnpickler(pickler.assembleParts())
6378
unpickler.enter(roots = Set())
64-
unpickler
79+
cls -> unpickler
6580
}
6681
pickling.println("************* entered toplevel ***********")
67-
for ((unpickler, unit) <- unpicklers zip units) {
82+
for ((cls, unpickler) <- unpicklers) {
6883
val unpickled = unpickler.body(readPositions = false)
69-
testSame(i"$unpickled%\n%", beforePickling(unit), unit)
84+
testSame(i"$unpickled%\n%", beforePickling(cls), cls)
7085
}
7186
}
7287

73-
private def testSame(unpickled: String, previous: String, unit: CompilationUnit)(implicit ctx: Context) =
88+
private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(implicit ctx: Context) =
7489
if (previous != unpickled) {
7590
output("before-pickling.txt", previous)
7691
output("after-pickling.txt", unpickled)
77-
ctx.error(s"""pickling difference for $unit, for details:
92+
ctx.error(s"""pickling difference for ${cls.fullName}, for details:
7893
|
7994
| diff before-pickling.txt after-pickling.txt""".stripMargin)
8095
}

0 commit comments

Comments
 (0)