Skip to content

Commit a3a41bb

Browse files
committed
Improve compression of TastyString
Improves #3877 `'{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }` was reduced from 206 bytes to 172 bytes `'{ ~x * ~powerCode(n - 1, x) }` was reduced from 143 bytes to 128 bytes
1 parent f758994 commit a3a41bb

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

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

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,34 @@ package dotty.tools.dotc.core.tasty
22

33
import scala.runtime.quoted.Unpickler.Pickled
44

5+
import java.io._
6+
import java.util.Base64
7+
import java.nio.charset.StandardCharsets.UTF_8
8+
59
/** Utils for String representation of TASTY */
610
object TastyString {
711

8-
// Conservative encoding, each byte is encoded in a char
9-
// TODO improve encoding compression
10-
private final val maxStringSize = 65535 / 2
12+
// Max size of a string literal in the bytecode
13+
private final val maxStringSize = 65535
1114

1215
/** Encode TASTY bytes into an Seq of String */
13-
def pickle(bytes: Array[Byte]): Pickled =
14-
bytes.sliding(maxStringSize, maxStringSize).map(bytesToString).toList
15-
16-
/** Decode the TASTY String into TASTY bytes */
17-
def unpickle(strings: Pickled): Array[Byte] = {
18-
val bytes = new Array[Byte](strings.map(_.length).sum)
19-
var i = 0
20-
for (str <- strings; j <- str.indices) {
21-
bytes(i) = str.charAt(j).toByte
22-
i += 1
16+
def pickle(bytes: Array[Byte]): Pickled = {
17+
val str = new String(Base64.getEncoder().encode(bytes), UTF_8)
18+
def split(sliceEnd: Int, acc: List[String]): List[String] = {
19+
if (sliceEnd == 0) acc
20+
else {
21+
val sliceStart = (sliceEnd - maxStringSize) max 0
22+
split(sliceStart, str.substring(sliceStart, sliceEnd) :: acc)
23+
}
2324
}
24-
bytes
25+
split(str.length, Nil)
2526
}
2627

27-
/** Encode bytes into a String */
28-
private def bytesToString(bytes: Array[Byte]): String = {
29-
assert(bytes.length <= maxStringSize)
30-
val chars = new Array[Char](bytes.length)
31-
for (i <- bytes.indices) chars(i) = (bytes(i) & 0xff).toChar
32-
new String(chars)
28+
/** Decode the TASTY String into TASTY bytes */
29+
def unpickle(strings: Pickled): Array[Byte] = {
30+
val string = new StringBuilder
31+
strings.foreach(string.append)
32+
Base64.getDecoder().decode(string.result().getBytes(UTF_8))
3333
}
3434

3535
}

0 commit comments

Comments
 (0)