Skip to content

Commit ba98f3d

Browse files
committed
Pickling reorganizations
- Don't create additional threads if ParallelPickling = false - Reorganize pickling to use common scratch data between different pickles to conserve space
1 parent 0f8d801 commit ba98f3d

File tree

8 files changed

+230
-168
lines changed

8 files changed

+230
-168
lines changed

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

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,43 @@ import dotty.tools.tasty.TastyFormat.CommentsSection
99

1010
import java.nio.charset.StandardCharsets
1111

12-
class CommentPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Addr, docString: untpd.MemberDef => Option[Comment]):
13-
private val buf = new TastyBuffer(5000)
14-
pickler.newSection(CommentsSection, buf)
15-
16-
def pickleComment(root: tpd.Tree): Unit = traverse(root)
17-
18-
private def pickleComment(addr: Addr, comment: Comment): Unit =
19-
if addr != NoAddr then
20-
val bytes = comment.raw.getBytes(StandardCharsets.UTF_8).nn
21-
val length = bytes.length
22-
buf.writeAddr(addr)
23-
buf.writeNat(length)
24-
buf.writeBytes(bytes, length)
25-
buf.writeLongInt(comment.span.coords)
26-
27-
private def traverse(x: Any): Unit = x match
28-
case x: untpd.Tree @unchecked =>
29-
x match
30-
case x: tpd.MemberDef @unchecked => // at this point all MembderDefs are t(y)p(e)d.
31-
for comment <- docString(x) do pickleComment(addrOfTree(x), comment)
32-
case _ =>
33-
val limit = x.productArity
34-
var n = 0
35-
while n < limit do
36-
traverse(x.productElement(n))
37-
n += 1
38-
case y :: ys =>
39-
traverse(y)
40-
traverse(ys)
41-
case _ =>
42-
12+
object CommentPickler:
13+
14+
def pickleComment(
15+
pickler: TastyPickler,
16+
addrOfTree: PositionPickler.TreeToAddr,
17+
docString: untpd.MemberDef => Option[Comment],
18+
root: tpd.Tree,
19+
buf: TastyBuffer = new TastyBuffer(5000)): Unit =
20+
21+
pickler.newSection(CommentsSection, buf)
22+
23+
def pickleComment(addr: Addr, comment: Comment): Unit =
24+
if addr != NoAddr then
25+
val bytes = comment.raw.getBytes(StandardCharsets.UTF_8).nn
26+
val length = bytes.length
27+
buf.writeAddr(addr)
28+
buf.writeNat(length)
29+
buf.writeBytes(bytes, length)
30+
buf.writeLongInt(comment.span.coords)
31+
32+
def traverse(x: Any): Unit = x match
33+
case x: untpd.Tree @unchecked =>
34+
x match
35+
case x: tpd.MemberDef @unchecked => // at this point all MembderDefs are t(y)p(e)d.
36+
for comment <- docString(x) do pickleComment(addrOfTree(x), comment)
37+
case _ =>
38+
val limit = x.productArity
39+
var n = 0
40+
while n < limit do
41+
traverse(x.productElement(n))
42+
n += 1
43+
case y :: ys =>
44+
traverse(y)
45+
traverse(ys)
46+
case _ =>
47+
48+
traverse(root)
49+
end pickleComment
4350
end CommentPickler
4451

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

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,32 @@ import collection.mutable
1616
import util.Spans._
1717
import reporting.Message
1818

19-
class PositionPickler(
20-
pickler: TastyPickler,
21-
addrOfTree: PositionPickler.TreeToAddr,
22-
treeAnnots: untpd.MemberDef => List[tpd.Tree],
23-
relativePathReference: String){
24-
19+
object PositionPickler:
2520
import ast.tpd._
2621

27-
val buf: TastyBuffer = new TastyBuffer(5000)
28-
pickler.newSection(PositionsSection, buf)
29-
30-
private val pickledIndices = new mutable.BitSet
22+
// Note: This could be just TreeToAddr => Addr if functions are specialized to value classes.
23+
// We use a SAM type to avoid boxing of Addr
24+
@FunctionalInterface
25+
trait TreeToAddr:
26+
def apply(x: untpd.Tree): Addr
3127

32-
def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean, hasPoint: Boolean): Int = {
28+
def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean, hasPoint: Boolean): Int =
3329
def toInt(b: Boolean) = if (b) 1 else 0
3430
(addrDelta << 3) | (toInt(hasStartDelta) << 2) | (toInt(hasEndDelta) << 1) | toInt(hasPoint)
35-
}
3631

37-
def picklePositions(source: SourceFile, roots: List[Tree], warnings: mutable.ListBuffer[Message]): Unit = {
32+
def picklePositions(
33+
pickler: TastyPickler,
34+
addrOfTree: TreeToAddr,
35+
treeAnnots: untpd.MemberDef => List[tpd.Tree],
36+
relativePathReference: String,
37+
source: SourceFile,
38+
roots: List[Tree],
39+
warnings: mutable.ListBuffer[Message],
40+
buf: TastyBuffer = new TastyBuffer(5000),
41+
pickledIndices: mutable.BitSet = new mutable.BitSet) =
42+
43+
pickler.newSection(PositionsSection, buf)
44+
3845
/** Pickle the number of lines followed by the length of each line */
3946
def pickleLineOffsets(): Unit = {
4047
val content = source.content()
@@ -129,10 +136,6 @@ class PositionPickler(
129136
}
130137
for (root <- roots)
131138
traverse(root, NoSource)
132-
}
133-
}
134-
object PositionPickler:
135-
// Note: This could be just TreeToAddr => Addr if functions are specialized to value classes.
136-
// We use a SAM type to avoid boxing of Addr
137-
@FunctionalInterface trait TreeToAddr:
138-
def apply(x: untpd.Tree): Addr
139+
end picklePositions
140+
end PositionPickler
141+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package dotty.tools.dotc.core.tasty
2+
import dotty.tools.tasty.TastyBuffer
3+
import collection.mutable
4+
5+
class ScratchData:
6+
var delta, delta1 = new Array[Int](50000)
7+
8+
val positionBuffer = new TastyBuffer(5000)
9+
val pickledIndices = new mutable.BitSet
10+
11+
val commentBuffer = new TastyBuffer(5000)
12+
13+
def reset() =
14+
positionBuffer.reset()
15+
pickledIndices.clear()
16+
commentBuffer.reset()
17+

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

Lines changed: 94 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ class TreeBuffer extends TastyBuffer(50000) {
1717
private val initialOffsetSize = bytes.length / (AddrWidth * ItemsOverOffsets)
1818
private var offsets = new Array[Int](initialOffsetSize)
1919
private var isRelative = new Array[Boolean](initialOffsetSize)
20-
private var delta: Array[Int] = _
2120
private var numOffsets = 0
2221

2322
/** A map from trees to the address at which a tree is pickled. */
@@ -68,109 +67,113 @@ class TreeBuffer extends TastyBuffer(50000) {
6867
}
6968

7069
/** The amount by which the bytes at the given address are shifted under compression */
71-
def deltaAt(at: Addr): Int = {
70+
def deltaAt(at: Addr, scratch: ScratchData): Int = {
7271
val idx = bestFit(offsets, numOffsets, at.index - 1)
73-
if (idx < 0) 0 else delta(idx)
72+
if (idx < 0) 0 else scratch.delta(idx)
7473
}
7574

7675
/** The address to which `x` is translated under compression */
77-
def adjusted(x: Addr): Addr = x - deltaAt(x)
76+
def adjusted(x: Addr, scratch: ScratchData): Addr = x - deltaAt(x, scratch)
77+
78+
/** Final assembly, involving the following steps:
79+
* - compute deltas
80+
* - adjust deltas until additional savings are < 1% of total
81+
* - adjust offsets according to the adjusted deltas
82+
* - shrink buffer, skipping zeroes.
83+
*/
84+
def compactify(scratch: ScratchData): Unit =
7885

7986
/** Compute all shift-deltas */
80-
private def computeDeltas() = {
81-
delta = new Array[Int](numOffsets)
82-
var lastDelta = 0
83-
var i = 0
84-
while (i < numOffsets) {
85-
val off = offset(i)
86-
val skippedOff = skipZeroes(off)
87-
val skippedCount = skippedOff.index - off.index
88-
assert(skippedCount < AddrWidth, s"unset field at position $off")
89-
lastDelta += skippedCount
90-
delta(i) = lastDelta
91-
i += 1
87+
def computeDeltas() = {
88+
if scratch.delta.length < numOffsets then
89+
scratch.delta = new Array[Int](numOffsets)
90+
scratch.delta1 = new Array[Int](numOffsets)
91+
var lastDelta = 0
92+
var i = 0
93+
while (i < numOffsets) {
94+
val off = offset(i)
95+
val skippedOff = skipZeroes(off)
96+
val skippedCount = skippedOff.index - off.index
97+
assert(skippedCount < AddrWidth, s"unset field at position $off")
98+
lastDelta += skippedCount
99+
scratch.delta(i) = lastDelta
100+
i += 1
101+
}
92102
}
93-
}
94103

95-
/** The absolute or relative adjusted address at index `i` of `offsets` array*/
96-
private def adjustedOffset(i: Int): Addr = {
97-
val at = offset(i)
98-
val original = getAddr(at)
99-
if (isRelative(i)) {
100-
val start = skipNat(at)
101-
val len1 = original + delta(i) - deltaAt(original + start.index)
102-
val len2 = adjusted(original + start.index) - adjusted(start).index
103-
assert(len1 == len2,
104-
s"adjusting offset #$i: $at, original = $original, len1 = $len1, len2 = $len2")
105-
len1
104+
/** The absolute or relative adjusted address at index `i` of `offsets` array*/
105+
def adjustedOffset(i: Int): Addr = {
106+
val at = offset(i)
107+
val original = getAddr(at)
108+
if (isRelative(i)) {
109+
val start = skipNat(at)
110+
val len1 = original + scratch.delta(i) - deltaAt(original + start.index, scratch)
111+
val len2 = adjusted(original + start.index, scratch) - adjusted(start, scratch).index
112+
assert(len1 == len2,
113+
s"adjusting offset #$i: $at, original = $original, len1 = $len1, len2 = $len2")
114+
len1
115+
}
116+
else adjusted(original, scratch)
106117
}
107-
else adjusted(original)
108-
}
109118

110-
/** Adjust all offsets according to previously computed deltas */
111-
private def adjustOffsets(): Unit =
112-
var i = 0
113-
while i < numOffsets do
114-
val corrected = adjustedOffset(i)
115-
fillAddr(offset(i), corrected)
116-
i += 1
117-
118-
/** Adjust deltas to also take account references that will shrink (and thereby
119-
* generate additional zeroes that can be skipped) due to previously
120-
* computed adjustments.
121-
*/
122-
private def adjustDeltas(): Int = {
123-
val delta1 = new Array[Int](delta.length)
124-
var lastDelta = 0
125-
var i = 0
126-
while i < numOffsets do
127-
val corrected = adjustedOffset(i)
128-
lastDelta += AddrWidth - TastyBuffer.natSize(corrected.index)
129-
delta1(i) = lastDelta
130-
i += 1
131-
val saved =
132-
if (numOffsets == 0) 0
133-
else delta1(numOffsets - 1) - delta(numOffsets - 1)
134-
delta = delta1
135-
saved
136-
}
119+
/** Adjust all offsets according to previously computed deltas */
120+
def adjustOffsets(): Unit =
121+
var i = 0
122+
while i < numOffsets do
123+
val corrected = adjustedOffset(i)
124+
fillAddr(offset(i), corrected)
125+
i += 1
126+
127+
/** Adjust deltas to also take account references that will shrink (and thereby
128+
* generate additional zeroes that can be skipped) due to previously
129+
* computed adjustments.
130+
*/
131+
def adjustDeltas(): Int = {
132+
var lastDelta = 0
133+
var i = 0
134+
while i < numOffsets do
135+
val corrected = adjustedOffset(i)
136+
lastDelta += AddrWidth - TastyBuffer.natSize(corrected.index)
137+
scratch.delta1(i) = lastDelta
138+
i += 1
139+
val saved =
140+
if (numOffsets == 0) 0
141+
else scratch.delta1(numOffsets - 1) - scratch.delta(numOffsets - 1)
142+
val tmp = scratch.delta
143+
scratch.delta = scratch.delta1
144+
scratch.delta1 = tmp
145+
saved
146+
}
137147

138-
/** Compress pickle buffer, shifting bytes to close all skipped zeroes. */
139-
private def compress(): Int = {
140-
var lastDelta = 0
141-
var start = 0
142-
var i = 0
143-
var wasted = 0
144-
def shift(end: Int) =
145-
System.arraycopy(bytes, start, bytes, start - lastDelta, end - start)
146-
while (i < numOffsets) {
147-
val next = offsets(i)
148-
shift(next)
149-
start = next + delta(i) - lastDelta
150-
val pastZeroes = skipZeroes(Addr(next)).index
151-
assert(pastZeroes >= start, s"something's wrong: eliminated non-zero")
152-
wasted += (pastZeroes - start)
153-
lastDelta = delta(i)
154-
i += 1
148+
/** Compress pickle buffer, shifting bytes to close all skipped zeroes. */
149+
def compress(): Int = {
150+
var lastDelta = 0
151+
var start = 0
152+
var i = 0
153+
var wasted = 0
154+
def shift(end: Int) =
155+
System.arraycopy(bytes, start, bytes, start - lastDelta, end - start)
156+
while (i < numOffsets) {
157+
val next = offsets(i)
158+
shift(next)
159+
start = next + scratch.delta(i) - lastDelta
160+
val pastZeroes = skipZeroes(Addr(next)).index
161+
assert(pastZeroes >= start, s"something's wrong: eliminated non-zero")
162+
wasted += (pastZeroes - start)
163+
lastDelta = scratch.delta(i)
164+
i += 1
165+
}
166+
shift(length)
167+
length -= lastDelta
168+
wasted
155169
}
156-
shift(length)
157-
length -= lastDelta
158-
wasted
159-
}
160170

161-
def adjustTreeAddrs(): Unit =
162-
var i = 0
163-
while i < treeAddrs.size do
164-
treeAddrs.setValue(i, adjusted(Addr(treeAddrs.value(i))).index)
165-
i += 1
171+
def adjustTreeAddrs(): Unit =
172+
var i = 0
173+
while i < treeAddrs.size do
174+
treeAddrs.setValue(i, adjusted(Addr(treeAddrs.value(i)), scratch).index)
175+
i += 1
166176

167-
/** Final assembly, involving the following steps:
168-
* - compute deltas
169-
* - adjust deltas until additional savings are < 1% of total
170-
* - adjust offsets according to the adjusted deltas
171-
* - shrink buffer, skipping zeroes.
172-
*/
173-
def compactify(): Unit = {
174177
val origLength = length
175178
computeDeltas()
176179
//println(s"offsets: ${offsets.take(numOffsets).deep}")
@@ -185,5 +188,5 @@ class TreeBuffer extends TastyBuffer(50000) {
185188
adjustTreeAddrs()
186189
val wasted = compress()
187190
pickling.println(s"original length: $origLength, compressed to: $length, wasted: $wasted") // DEBUG, for now.
188-
}
191+
end compactify
189192
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -812,8 +812,8 @@ class TreePickler(pickler: TastyPickler) {
812812
assert(forwardSymRefs.isEmpty, i"unresolved symbols: $missing%, % when pickling ${ctx.source}")
813813
}
814814

815-
def compactify(): Unit = {
816-
buf.compactify()
815+
def compactify(scratch: ScratchData = new ScratchData): Unit = {
816+
buf.compactify(scratch)
817817

818818
def updateMapWithDeltas(mp: MutableSymbolMap[Addr]) =
819819
val keys = new Array[Symbol](mp.size)
@@ -826,7 +826,7 @@ class TreePickler(pickler: TastyPickler) {
826826
i = 0
827827
while i < keys.length do
828828
val key = keys(i)
829-
mp(key) = adjusted(mp(key))
829+
mp(key) = adjusted(mp(key), scratch)
830830
i += 1
831831

832832
updateMapWithDeltas(symRefs)

0 commit comments

Comments
 (0)