Skip to content

Commit 0246f72

Browse files
authored
Merge pull request #9619 from dotty-staging/parallel-position-pickler
Parallelize position pickling
2 parents 02e60f8 + 18a13c6 commit 0246f72

File tree

9 files changed

+40
-48
lines changed

9 files changed

+40
-48
lines changed

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,15 @@ class GenBCodePipeline(val int: DottyBackendInterface)(using Context) extends BC
235235
if (!ctx.settings.YemitTastyInClass.value) {
236236
val outTastyFile = getFileForClassfile(outF, store.name, ".tasty")
237237
val outstream = new DataOutputStream(outTastyFile.bufferedOutput)
238-
try outstream.write(binary)
238+
try outstream.write(binary())
239239
catch case ex: ClosedByInterruptException =>
240240
try
241241
outTastyFile.delete() // don't leave an empty or half-written tastyfile around after an interrupt
242242
catch case _: Throwable =>
243243
throw ex
244244
finally outstream.close()
245245

246-
val uuid = new TastyHeaderUnpickler(binary).readHeader()
246+
val uuid = new TastyHeaderUnpickler(binary()).readHeader()
247247
val lo = uuid.getMostSignificantBits
248248
val hi = uuid.getLeastSignificantBits
249249

@@ -257,7 +257,7 @@ class GenBCodePipeline(val int: DottyBackendInterface)(using Context) extends BC
257257
// Create an empty file to signal that a tasty section exist in the corresponding .class
258258
// This is much cheaper and simpler to check than doing classfile parsing
259259
getFileForClassfile(outF, store.name, ".hasTasty")
260-
binary
260+
binary()
261261
}
262262
val dataAttr = createJAttribute(nme.TASTYATTR.mangledString, tasty, 0, tasty.length)
263263
store.visitAttribute(dataAttr)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class CompilationUnit protected (val source: SourceFile) {
3030
var sourceVersion: Option[SourceVersion] = None
3131

3232
/** Pickled TASTY binaries, indexed by class. */
33-
var pickled: Map[ClassSymbol, Array[Byte]] = Map()
33+
var pickled: Map[ClassSymbol, () => Array[Byte]] = Map()
3434

3535
/** The fresh name creator for the current unit.
3636
* FIXME(#7661): This is not fine-grained enough to enable reproducible builds,

compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala

-2
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,6 @@ object PickledQuotes {
168168
val treePkl = pickler.treePkl
169169
treePkl.pickle(tree :: Nil)
170170
treePkl.compactify()
171-
pickler.addrOfTree = treePkl.buf.addrOfTree
172-
pickler.addrOfSym = treePkl.addrOfSym
173171
if (tree.span.exists)
174172
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil)
175173

compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala

-13
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,5 @@ class TastyPickler(val rootCls: ClassSymbol) {
6565
all.bytes
6666
}
6767

68-
/** The address in the TASTY file of a given tree, or None if unknown.
69-
* Note that trees are looked up by reference equality,
70-
* so one can reliably use this function only directly after `pickler`.
71-
*/
72-
var addrOfTree: tpd.Tree => Addr = (_ => NoAddr)
73-
74-
/**
75-
* Addresses in TASTY file of symbols, stored by pickling.
76-
* Note that trees are checked for reference equality,
77-
* so one can reliably use this function only dirrectly after `pickler`
78-
*/
79-
var addrOfSym: Symbol => Option[Addr] = (_ => None)
80-
8168
val treePkl: TreePickler = new TreePickler(this)
8269
}

compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ class TreeBuffer extends TastyBuffer(50000) {
2121
private var delta: Array[Int] = _
2222
private var numOffsets = 0
2323

24-
/** A map from tree unique ids to the address index at which a tree is pickled. */
24+
/** A map from tree unique ids to the address index at which a tree is pickled.
25+
* Note that trees are looked up by reference equality,
26+
* so one can reliably use this function only directly after `pickler`.
27+
*/
2528
private val addrOfTree = SparseIntArray()
2629

2730
def registerTreeAddr(tree: Tree): Addr =

compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class DecompilationPrinter extends Phase {
3939
private def printToOutput(out: PrintStream)(using Context): Unit = {
4040
val unit = ctx.compilationUnit
4141
if (ctx.settings.printTasty.value)
42-
println(new TastyPrinter(unit.pickled.head._2).printContents())
42+
println(new TastyPrinter(unit.pickled.head._2()).printContents())
4343
else {
4444
val unitFile = unit.source.toString.replace("\\", "/").replace(".class", ".tasty")
4545
out.println(s"/** Decompiled from $unitFile */")

compiler/src/dotty/tools/dotc/decompiler/IDEDecompilerDriver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class IDEDecompilerDriver(val settings: List[String]) extends dotc.Driver {
3535
val unit = ctx.run.units.head
3636

3737
val decompiled = ReflectionImpl.showTree(unit.tpdTree)
38-
val tree = new TastyHTMLPrinter(unit.pickled.head._2).printContents()
38+
val tree = new TastyHTMLPrinter(unit.pickled.head._2()).printContents()
3939

4040
reporter.removeBufferedMessages.foreach(message => System.err.println(message))
4141
(tree, decompiled)

compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class ReadTasty extends Phase {
4040
if (cls.rootTree.isEmpty) None
4141
else {
4242
val unit = CompilationUnit(cls, cls.rootTree, forceTrees = true)
43-
unit.pickled += (cls -> unpickler.unpickler.bytes)
43+
unit.pickled += (cls -> (() => unpickler.unpickler.bytes))
4444
Some(unit)
4545
}
4646
case tree: Tree[?] =>

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

+29-25
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import Symbols._
1313
import Flags.Module
1414
import reporting.ThrowingReporter
1515
import collection.mutable
16+
import scala.concurrent.{Future, Await, ExecutionContext}
17+
import scala.concurrent.duration.Duration
1618

1719
object Pickler {
1820
val name: String = "pickler"
@@ -55,35 +57,37 @@ class Pickler extends Phase {
5557
}
5658
{
5759
val pickler = new TastyPickler(cls)
58-
if (ctx.settings.YtestPickler.value) {
60+
if ctx.settings.YtestPickler.value then
5961
beforePickling(cls) = tree.show
6062
picklers(cls) = pickler
61-
}
6263
val treePkl = pickler.treePkl
6364
treePkl.pickle(tree :: Nil)
64-
treePkl.compactify()
65-
pickler.addrOfTree = treePkl.buf.addrOfTree
66-
pickler.addrOfSym = treePkl.addrOfSym
67-
if (tree.span.exists)
68-
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil)
69-
70-
if (!ctx.settings.YdropComments.value)
71-
new CommentPickler(pickler, treePkl.buf.addrOfTree).pickleComment(tree)
72-
73-
// other pickle sections go here.
74-
val pickled = pickler.assembleParts()
75-
unit.pickled += (cls -> pickled)
76-
77-
def rawBytes = // not needed right now, but useful to print raw format.
78-
pickled.iterator.grouped(10).toList.zipWithIndex.map {
79-
case (row, i) => s"${i}0: ${row.mkString(" ")}"
80-
}
81-
82-
// println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
83-
if (pickling ne noPrinter) {
84-
println(i"**** pickled info of $cls")
85-
println(new TastyPrinter(pickled).printContents())
86-
}
65+
val pickledF = Future {
66+
treePkl.compactify()
67+
if tree.span.exists then
68+
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil)
69+
70+
if !ctx.settings.YdropComments.value then
71+
new CommentPickler(pickler, treePkl.buf.addrOfTree).pickleComment(tree)
72+
73+
val pickled = pickler.assembleParts()
74+
75+
def rawBytes = // not needed right now, but useful to print raw format.
76+
pickled.iterator.grouped(10).toList.zipWithIndex.map {
77+
case (row, i) => s"${i}0: ${row.mkString(" ")}"
78+
}
79+
80+
// println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
81+
if pickling ne noPrinter then
82+
pickling.synchronized {
83+
println(i"**** pickled info of $cls")
84+
println(new TastyPrinter(pickled).printContents())
85+
}
86+
pickled
87+
}(using ExecutionContext.global)
88+
def force(): Array[Byte] = Await.result(pickledF, Duration.Inf)
89+
if ctx.settings.YtestPickler.value then force()
90+
unit.pickled += (cls -> force)
8791
}
8892
}
8993

0 commit comments

Comments
 (0)