Skip to content

Don't retain picklers until backend. #1725

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

Merged
merged 7 commits into from
Nov 22, 2016
Merged
Show file tree
Hide file tree
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
3 changes: 1 addition & 2 deletions src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,7 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
val plainC = pcb.cnode

if (claszSymbol.isClass) // @DarkDimius is this test needed here?
for (pickler <- ctx.compilationUnit.picklers.get(claszSymbol.asClass)) {
val binary = pickler.assembleParts()
for (binary <- ctx.compilationUnit.pickled.get(claszSymbol.asClass)) {
val dataAttr = new CustomAttr(nme.TASTYATTR.toString, binary)
(if (mirrorC ne null) mirrorC else plainC).visitAttribute(dataAttr)
}
Expand Down
8 changes: 2 additions & 6 deletions src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@ class CompilationUnit(val source: SourceFile) {

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

/**
* Picklers used to create TASTY sections, indexed by toplevel class to which they belong.
* Sections: Header, ASTs and Positions are populated by `pickler` phase.
* Subsequent phases can add new sections.
*/
var picklers: Map[ClassSymbol, TastyPickler] = Map()
/** Pickled TASTY binaries, indexed by class. */
var pickled: Map[ClassSymbol, Array[Byte]] = Map()

var unpicklers: Map[ClassSymbol, TastyUnpickler] = Map()
}
4 changes: 3 additions & 1 deletion src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import typer.{FrontEnd, Typer, ImportInfo, RefChecks}
import reporting.{Reporter, ConsoleReporter}
import Phases.Phase
import transform._
import util.FreshNameCreator
import transform.TreeTransforms.{TreeTransform, TreeTransformer}
import core.DenotTransformers.DenotTransformer
import core.Denotations.SingleDenotation
Expand Down Expand Up @@ -140,7 +141,8 @@ class Compiler {
.setTyper(new Typer)
.setMode(Mode.ImplicitsEnabled)
.setTyperState(new MutableTyperState(ctx.typerState, ctx.typerState.reporter, isCommittable = true))
ctx.initialize()(start) // re-initialize the base context with start
.setFreshNames(new FreshNameCreator.Default)
ctx.initialize()(start) // re-initialize the base context with start
def addImport(ctx: Context, refFn: () => TermRef) =
ctx.fresh.setImportInfo(ImportInfo.rootImport(refFn)(ctx))
(start.setRunInfo(new RunInfo(start)) /: defn.RootImportFns)(addImport)
Expand Down
3 changes: 3 additions & 0 deletions src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class Run(comp: Compiler)(implicit ctx: Context) {
ctx.informTime(s"$phase ", start)
}
if (!ctx.reporter.hasErrors) Rewrites.writeBack()
for (unit <- units)
Stats.record("retained typed trees at end", unit.tpdTree.treeSize)
Stats.record("total trees at end", ast.Trees.ntrees)
}

private sealed trait PrintedTree
Expand Down
6 changes: 3 additions & 3 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ object SymDenotations {
ownerIfExists: Symbol,
final val name: Name,
initFlags: FlagSet,
final val initInfo: Type,
initInfo: Type,
initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol) {

//assert(symbol.id != 4940, name)
Expand Down Expand Up @@ -232,7 +232,7 @@ object SymDenotations {
case _ =>
}
*/
if (Config.checkNoSkolemsInInfo) assertNoSkolems(initInfo)
if (Config.checkNoSkolemsInInfo) assertNoSkolems(tp)
myInfo = tp
}

Expand Down Expand Up @@ -751,7 +751,7 @@ object SymDenotations {
// def isOverridable: Boolean = !!! need to enforce that classes cannot be redefined
def isSkolem: Boolean = name == nme.SKOLEM

def isInlineMethod(implicit ctx: Context): Boolean = is(InlineMethod, butNot = Accessor)
def isInlineMethod(implicit ctx: Context): Boolean = is(InlineMethod, butNot = Accessor)

// ------ access to related symbols ---------------------------------

Expand Down
20 changes: 14 additions & 6 deletions src/dotty/tools/dotc/transform/Pickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class Pickler extends Phase {
s.close
}

// Maps that keep a record if -Ytest-pickler is set.
private val beforePickling = new mutable.HashMap[ClassSymbol, String]
private val picklers = new mutable.HashMap[ClassSymbol, TastyPickler]

/** Drop any elements of this list that are linked module classes of other elements in the list */
private def dropCompanionModuleClasses(clss: List[ClassSymbol])(implicit ctx: Context): List[ClassSymbol] = {
Expand All @@ -40,9 +42,11 @@ class Pickler extends Phase {

for { cls <- dropCompanionModuleClasses(topLevelClasses(unit.tpdTree))
tree <- sliceTopLevel(unit.tpdTree, cls) } {
if (ctx.settings.YtestPickler.value) beforePickling(cls) = tree.show
val pickler = new TastyPickler()
unit.picklers += (cls -> pickler)
if (ctx.settings.YtestPickler.value) {
beforePickling(cls) = tree.show
picklers(cls) = pickler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this goes in the right direction, but in my heap dump I noticed that a massive amount of memory was taken by beforePickling so that may not be enough to get the tests to run smoothly. It may be helpful to do beforePickling(cls) = null and picklers(cls) = null in testUnpickler to free up these resources.

}
val treePkl = pickler.treePkl
treePkl.pickle(tree :: Nil)
treePkl.compactify()
Expand All @@ -51,8 +55,12 @@ class Pickler extends Phase {
if (tree.pos.exists)
new PositionPickler(pickler, treePkl.buf.addrsOfTree).picklePositions(tree :: Nil)

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

def rawBytes = // not needed right now, but useful to print raw format.
pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
pickled.iterator.grouped(10).toList.zipWithIndex.map {
case (row, i) => s"${i}0: ${row.mkString(" ")}"
}
// println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
Expand All @@ -66,18 +74,18 @@ class Pickler extends Phase {
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
val result = super.runOn(units)
if (ctx.settings.YtestPickler.value)
testUnpickler(units)(
testUnpickler(
ctx.fresh
.setPeriod(Period(ctx.runId + 1, FirstPhaseId))
.addMode(Mode.ReadPositions))
result
}

private def testUnpickler(units: List[CompilationUnit])(implicit ctx: Context): Unit = {
private def testUnpickler(implicit ctx: Context): Unit = {
pickling.println(i"testing unpickler at run ${ctx.runId}")
ctx.initialize()
val unpicklers =
for (unit <- units; (cls, pickler) <- unit.picklers) yield {
for ((cls, pickler) <- picklers) yield {
val unpickler = new DottyUnpickler(pickler.assembleParts())
unpickler.enter(roots = Set())
cls -> unpickler
Expand Down
13 changes: 7 additions & 6 deletions src/dotty/tools/dotc/typer/FrontEnd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import config.Printers.{typr, default}
import util.Stats._
import scala.util.control.NonFatal
import ast.Trees._
import util.FreshNameCreator

class FrontEnd extends Phase {

Expand Down Expand Up @@ -49,8 +48,8 @@ class FrontEnd extends Phase {
val unit = ctx.compilationUnit
unit.tpdTree = ctx.typer.typedExpr(unit.untpdTree)
typr.println("typed: " + unit.source)
record("retainedUntypedTrees", unit.untpdTree.treeSize)
record("retainedTypedTrees", unit.tpdTree.treeSize)
record("retained untyped trees", unit.untpdTree.treeSize)
record("retained typed trees after typer", unit.tpdTree.treeSize)
}

private def firstTopLevelDef(trees: List[tpd.Tree])(implicit ctx: Context): Symbol = trees match {
Expand All @@ -64,13 +63,15 @@ class FrontEnd extends Phase {
unit.isJava || firstTopLevelDef(unit.tpdTree :: Nil).isPrimitiveValueClass

override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
val unitContexts = for (unit <- units) yield
ctx.fresh.setCompilationUnit(unit).setFreshNames(new FreshNameCreator.Default)
val unitContexts = for (unit <- units) yield {
ctx.inform(s"compiling ${unit.source}")
ctx.fresh.setCompilationUnit(unit)
}
unitContexts foreach (parse(_))
record("parsedTrees", ast.Trees.ntrees)
unitContexts foreach (enterSyms(_))
unitContexts foreach (typeCheck(_))
record("totalTrees", ast.Trees.ntrees)
record("total trees after typer", ast.Trees.ntrees)
unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper)
}

Expand Down
4 changes: 1 addition & 3 deletions src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -477,11 +477,9 @@ object ProtoTypes {
def apply(tp: Type) = wildApprox(tp, this)
}

@sharable private lazy val dummyTree = untpd.Literal(Constant(null))

/** Dummy tree to be used as an argument of a FunProto or ViewProto type */
object dummyTreeOfType {
def apply(tp: Type): Tree = dummyTree withTypeUnchecked tp
def apply(tp: Type): Tree = untpd.Literal(Constant(null)) withTypeUnchecked tp
def unapply(tree: Tree): Option[Type] = tree match {
case Literal(Constant(null)) => Some(tree.typeOpt)
case _ => None
Expand Down
7 changes: 3 additions & 4 deletions test/test/DottyTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,23 @@ import dotty.tools.dotc.Compiler
import dotty.tools.dotc
import dotty.tools.dotc.core.Phases.Phase

class DottyTest /*extends ContextEscapeDetection*/ {
class DottyTest extends ContextEscapeDetection{

dotty.tools.dotc.parsing.Scanners // initialize keywords

implicit var ctx: Contexts.Context = {
val base = new ContextBase
val base = new ContextBase {}
import base.settings._
val ctx = base.initialCtx.fresh
base.initialize()(ctx)
ctx.setSetting(ctx.settings.encoding, "UTF8")
ctx
}
/*

override def getCtx: Context = ctx
override def clearCtx() = {
ctx = null
}
*/
private def compilerWithChecker(phase: String)(assertion:(tpd.Tree, Context) => Unit) = new Compiler {
override def phases = {
val allPhases = super.phases
Expand Down