Skip to content

Output .tasty files in Pickler phase #4955

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -42,9 +42,9 @@ pipeline:
commands:
- cp -R . /tmp/4/ && cd /tmp/4/
- ./project/scripts/sbt sbt-dotty/scripted
when:
# sbt scripted tests are slow and only run on nightly or deployment
event: [ tag, deployment ]
# when:
# # sbt scripted tests are slow and only run on nightly or deployment
# event: [ tag, deployment ]

# DOCUMENTATION:
documentation:
46 changes: 23 additions & 23 deletions compiler/src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
@@ -213,36 +213,36 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName) else null;
val plainC = pcb.cnode

if (claszSymbol.isClass) // @DarkDimius is this test needed here?
for (binary <- ctx.compilationUnit.pickled.get(claszSymbol.asClass)) {
if (claszSymbol.isClass) { // @DarkDimius is this test needed here?
def storeTastyTagBytes(getBytes: String => Array[Byte]): Unit = {
val store = if (mirrorC ne null) mirrorC else plainC
val tasty =
if (!ctx.settings.YemitTastyInClass.value) {
val outTastyFile = getFileForClassfile(outF, store.name, ".tasty")
val outstream = new DataOutputStream(outTastyFile.bufferedOutput)
try outstream.write(binary)
finally outstream.close()

val uuid = new TastyHeaderUnpickler(binary).readHeader()
val lo = uuid.getMostSignificantBits
val hi = uuid.getLeastSignificantBits

val bytes = getBytes(store.name)
val dataAttr = new CustomAttr(nme.TASTYATTR.mangledString, bytes)
store.visitAttribute(dataAttr)
}
if (ctx.settings.YemitTastyInClass.value) {
for (binary <- ctx.compilationUnit.pickled.get(claszSymbol.asClass)) {
storeTastyTagBytes { name =>
// Create an empty file to signal that a tasty section exist in the corresponding .class
// This is much cheaper and simpler to check than doing classfile parsing
getFileForClassfile(outF, name, ".hasTasty")
binary
}
}
} else {
for (uuid <- ctx.compilationUnit.tastyUUID.get(claszSymbol.asClass)) {
assert(!ctx.settings.YemitTastyInClass.value)
storeTastyTagBytes { name =>
// TASTY attribute is created but only the UUID bytes are stored in it.
// A TASTY attribute has length 16 if and only if the .tasty file exists.
val buffer = new TastyBuffer(16)
buffer.writeUncompressedLong(lo)
buffer.writeUncompressedLong(hi)
buffer.writeUncompressedLong(uuid.getLeastSignificantBits)
buffer.writeUncompressedLong(uuid.getMostSignificantBits)
buffer.bytes
} else {
// Create an empty file to signal that a tasty section exist in the corresponding .class
// This is much cheaper and simpler to check than doing classfile parsing
getFileForClassfile(outF, store.name, ".hasTasty")
binary
}
val dataAttr = new CustomAttr(nme.TASTYATTR.mangledString, tasty)
store.visitAttribute(dataAttr)
}
}

}

// ----------- create files

7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
@@ -10,6 +10,8 @@ import dotty.tools.dotc.core.SymDenotations.ClassDenotation
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.transform.SymUtils._

import java.util.UUID

class CompilationUnit(val source: SourceFile) {

override def toString = source.toString
@@ -18,11 +20,14 @@ class CompilationUnit(val source: SourceFile) {

var tpdTree: tpd.Tree = tpd.EmptyTree

def isJava = source.file.name.endsWith(".java")
def isJava: Boolean = source.file.name.endsWith(".java")

/** Pickled TASTY binaries, indexed by class. */
var pickled: Map[ClassSymbol, Array[Byte]] = Map()

/** UUID of the pickled TASTY, indexed by class. */
var tastyUUID: Map[ClassSymbol, UUID] = Map()

/** Will be reset to `true` if `untpdTree` contains `Quote` trees. The information
* is used in phase ReifyQuotes in order to avoid traversing a quote-less tree.
*/
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ object PickledQuotes {
if (pickling ne noPrinter)
println(i"**** pickling quote of \n${tree.show}")

val pickled = pickler.assembleParts()
val pickled = pickler.assembleParts()._2

if (pickling ne noPrinter)
new TastyPrinter(pickled).printContents()
9 changes: 6 additions & 3 deletions compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
Original file line number Diff line number Diff line change
@@ -6,10 +6,12 @@ package tasty
import TastyFormat._
import collection.mutable
import TastyBuffer._
import core.Symbols.{Symbol, ClassSymbol}
import core.Symbols.{ClassSymbol, Symbol}
import ast.tpd
import Decorators._

import java.util.UUID

class TastyPickler(val rootCls: ClassSymbol) {

private val sections = new mutable.ArrayBuffer[(NameRef, TastyBuffer)]
@@ -19,7 +21,8 @@ class TastyPickler(val rootCls: ClassSymbol) {
def newSection(name: String, buf: TastyBuffer) =
sections += ((nameBuffer.nameIndex(name.toTermName), buf))

def assembleParts(): Array[Byte] = {
/** Returns the UUID and bytes of the tasty file */
def assembleParts(): (UUID, Array[Byte]) = {
def lengthWithLength(buf: TastyBuffer) =
buf.length + natSize(buf.length)

@@ -60,7 +63,7 @@ class TastyPickler(val rootCls: ClassSymbol) {
all.writeBytes(buf.bytes, buf.length)
}
assert(all.length == totalSize && all.bytes.length == totalSize, s"totalSize = $totalSize, all.length = ${all.length}, all.bytes.length = ${all.bytes.length}")
all.bytes
(new UUID(uuidHi, uuidLow), all.bytes)
}

/** The address in the TASTY file of a given tree, or None if unknown.
30 changes: 22 additions & 8 deletions compiler/src/dotty/tools/dotc/transform/Pickler.scala
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import Symbols._
import Flags.Module
import reporting.ThrowingReporter
import collection.mutable
import NameOps._

object Pickler {
val name = "pickler"
@@ -64,17 +65,29 @@ class Pickler extends Phase {
new CommentPickler(pickler, treePkl.buf.addrOfTree).pickleComment(tree)

// other pickle sections go here.
val pickled = pickler.assembleParts()
unit.pickled += (cls -> pickled)
val (uuid, pickled) = pickler.assembleParts()

def rawBytes = // not needed right now, but useful to print raw format.
pickled.iterator.grouped(10).toList.zipWithIndex.map {
case (row, i) => s"${i}0: ${row.mkString(" ")}"
}
if (ctx.settings.YemitTastyInClass.value) {
unit.pickled += (cls -> pickled)
} else {
unit.tastyUUID += (cls -> uuid)
val parts = cls.fullName.stripModuleClassSuffix.mangledString.split('.')
val name = parts.last
val tastyDirectory = parts.init.foldLeft(ctx.settings.outputDir.value)((dir, part) => dir.subdirectoryNamed(part))
val tastyFile = tastyDirectory.fileNamed(s"${name}.tasty")
val tastyOutput = tastyFile.output
try tastyOutput.write(pickled)
finally tastyOutput.close()
}

// def rawBytes = // not needed right now, but useful to print raw format.
// pickled.iterator.grouped(10).toList.zipWithIndex.map {
// case (row, i) => s"${i}0: ${row.mkString(" ")}"
// }
// println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
if (pickling ne noPrinter) {
println(i"**** pickled info of $cls")
new TastyPrinter(pickler.assembleParts()).printContents()
new TastyPrinter(pickled).printContents()
}
}
}
@@ -97,7 +110,8 @@ class Pickler extends Phase {
ctx.initialize()
val unpicklers =
for ((cls, pickler) <- picklers) yield {
val unpickler = new DottyUnpickler(pickler.assembleParts())
val bytes = pickler.assembleParts()._2
val unpickler = new DottyUnpickler(bytes)
unpickler.enter(roots = Set.empty)
cls -> unpickler
}