aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-02-24 15:37:14 +0100
committerMartin Odersky <odersky@gmail.com>2014-02-24 18:56:48 +0100
commited7755b781bd1b444d38329cb22eacaa3fc1c005 (patch)
tree2eb43f71741310e77248111f5fa5c39203e33c8d /src/dotty/tools/dotc/core
parentcdeafeafd252b20a0df5440e0420211af95e0cdc (diff)
downloaddotty-ed7755b781bd1b444d38329cb22eacaa3fc1c005.tar.gz
dotty-ed7755b781bd1b444d38329cb22eacaa3fc1c005.tar.bz2
dotty-ed7755b781bd1b444d38329cb22eacaa3fc1c005.zip
Avoid memory leaks on repeated compilation.
Several measures: 1. Invalidate classOfId and superIdOfClass in ContextBase after each run. These contain local classes that should become inaccessible. 2. Also clear implicitScope cache that maps types to their implicit scopes after each run. (not sure whether this is needed; it did show up in paths from root, but on second thought this might have been a gc-able cycle. 3. Avoid capturing contexts in lazy annotations. 4. Avoid capturing contexts in functions that compute souceModule and moduleClass 5. Avoid capturing contexts in Unpickler's postReadOp hook.
Diffstat (limited to 'src/dotty/tools/dotc/core')
-rw-r--r--src/dotty/tools/dotc/core/Annotations.scala22
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala3
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala31
-rw-r--r--src/dotty/tools/dotc/core/SymbolLoaders.scala7
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala2
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala2
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala12
7 files changed, 46 insertions, 33 deletions
diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala
index 562974c48..947593ca4 100644
--- a/src/dotty/tools/dotc/core/Annotations.scala
+++ b/src/dotty/tools/dotc/core/Annotations.scala
@@ -6,22 +6,24 @@ import Symbols._, Types._, util.Positions._, Contexts._, Constants._, ast.tpd._
object Annotations {
abstract class Annotation {
- def tree: Tree
+ def tree(implicit ctx: Context): Tree
def symbol(implicit ctx: Context): Symbol = tree.tpe.typeSymbol
def matches(cls: Symbol)(implicit ctx: Context): Boolean = symbol.derivesFrom(cls)
def appliesToModule: Boolean = true // for now; see remark in SymDenotations
- def derivedAnnotation(tree: Tree) =
+ def derivedAnnotation(tree: Tree)(implicit ctx: Context) =
if (tree eq this.tree) this else Annotation(tree)
}
- case class ConcreteAnnotation(val tree: Tree) extends Annotation
+ case class ConcreteAnnotation(t: Tree) extends Annotation {
+ def tree(implicit ctx: Context): Tree = t
+ }
- case class LazyAnnotation(sym: Symbol)(treeFn: => Tree) extends Annotation {
- private var _tree: Tree = null
- def tree = {
- if (_tree == null) _tree = treeFn
- _tree
+ case class LazyAnnotation(sym: Symbol)(treeFn: Context => Tree) extends Annotation {
+ private var myTree: Tree = null
+ def tree(implicit ctx: Context) = {
+ if (myTree == null) myTree = treeFn(ctx)
+ myTree
}
override def symbol(implicit ctx: Context): Symbol = sym
}
@@ -48,11 +50,11 @@ object Annotations {
def apply(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =
apply(New(atp, args))
- def deferred(sym: Symbol, treeFn: => Tree): Annotation =
+ def deferred(sym: Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation =
new LazyAnnotation(sym)(treeFn)
def deferred(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =
- deferred(atp.classSymbol, New(atp, args))
+ deferred(atp.classSymbol, implicit ctx => New(atp, args))
def makeAlias(sym: TermSymbol)(implicit ctx: Context) =
apply(defn.AliasAnnot, List(Ident(TermRef.withSig(sym.owner.thisType, sym.name, sym.signature, sym))))
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index cfaa3720f..325ff5f74 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -471,6 +471,9 @@ object Contexts {
def reset() = {
for ((_, set) <- uniqueSets) set.clear()
+ for (i <- 0 until classOfId.length) classOfId(i) = null
+ superIdOfClass.clear()
+ lastSuperId = -1
}
}
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 5bd4bb6ea..7bd64a6c2 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -847,6 +847,14 @@ object SymDenotations {
private[this] var myBaseClasses: List[ClassSymbol] = null
private[this] var mySuperClassBits: BitSet = null
+ /** Invalidate baseTypeCache and superClassBits on new run */
+ private def checkBasesUpToDate()(implicit ctx: Context) =
+ if (baseTypeValid != ctx.runId) {
+ baseTypeCache = new java.util.HashMap[CachedType, Type]
+ mySuperClassBits = null
+ baseTypeValid = ctx.runId
+ }
+
private def computeBases(implicit ctx: Context): Unit = {
if (myBaseClasses == Nil) throw new CyclicReference(this)
myBaseClasses = Nil
@@ -879,6 +887,7 @@ object SymDenotations {
private def superClassBits(implicit ctx: Context): BitSet =
if (classParents.isEmpty) BitSet() // can happen when called too early in Namers
else {
+ checkBasesUpToDate()
if (mySuperClassBits == null) computeBases
mySuperClassBits
}
@@ -1093,10 +1102,7 @@ object SymDenotations {
/*>|>*/ ctx.debugTraceIndented(s"$tp.baseType($this)") /*<|<*/ {
tp match {
case tp: CachedType =>
- if (baseTypeValid != ctx.runId) {
- baseTypeCache = new java.util.HashMap[CachedType, Type]
- baseTypeValid = ctx.runId
- }
+ checkBasesUpToDate()
var basetp = baseTypeCache get tp
if (basetp == null) {
baseTypeCache.put(tp, NoPrefix)
@@ -1239,8 +1245,8 @@ object SymDenotations {
def apply(module: TermSymbol, modcls: ClassSymbol) = this
private var myDecls: Scope = EmptyScope
- private var mySourceModuleFn: () => Symbol = NoSymbolFn
- private var myModuleClassFn: () => Symbol = NoSymbolFn
+ private var mySourceModuleFn: Context => Symbol = NoSymbolFn
+ private var myModuleClassFn: Context => Symbol = NoSymbolFn
/** A proxy to this lazy type that keeps the complete operation
* but provides fresh slots for scope/sourceModule/moduleClass
@@ -1250,15 +1256,15 @@ object SymDenotations {
}
def decls: Scope = myDecls
- def sourceModule: Symbol = mySourceModuleFn()
- def moduleClass: Symbol = myModuleClassFn()
+ def sourceModule(implicit ctx: Context): Symbol = mySourceModuleFn(ctx)
+ def moduleClass(implicit ctx: Context): Symbol = myModuleClassFn(ctx)
def withDecls(decls: Scope): this.type = { myDecls = decls; this }
- def withSourceModule(sourceModule: => Symbol): this.type = { mySourceModuleFn = () => sourceModule; this }
- def withModuleClass(moduleClass: => Symbol): this.type = { myModuleClassFn = () => moduleClass; this }
+ def withSourceModule(sourceModuleFn: Context => Symbol): this.type = { mySourceModuleFn = sourceModuleFn; this }
+ def withModuleClass(moduleClassFn: Context => Symbol): this.type = { myModuleClassFn = moduleClassFn; this }
}
- val NoSymbolFn = () => NoSymbol
+ val NoSymbolFn = (ctx: Context) => NoSymbol
/** A missing completer */
class NoCompleter extends LazyType {
@@ -1270,7 +1276,8 @@ object SymDenotations {
* Completion of modules is always completion of the underlying
* module class, followed by copying the relevant fields to the module.
*/
- class ModuleCompleter(override val moduleClass: ClassSymbol) extends LazyType {
+ class ModuleCompleter(_moduleClass: ClassSymbol) extends LazyType {
+ override def moduleClass(implicit ctx: Context) = _moduleClass
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
val from = moduleClass.denot.asClass
denot.setFlag(from.flags.toTermFlags & RetainedModuleValFlags)
diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala
index 6161d0e57..2484165f3 100644
--- a/src/dotty/tools/dotc/core/SymbolLoaders.scala
+++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala
@@ -49,7 +49,7 @@ class SymbolLoaders {
modFlags: FlagSet = EmptyFlags, clsFlags: FlagSet = EmptyFlags, scope: Scope = EmptyScope)(implicit ctx: Context): Symbol = {
val module = ctx.newModuleSymbol(
owner, name.toTermName, modFlags, clsFlags,
- (modul, _) => completer.proxy withDecls newScope withSourceModule modul,
+ (module, _) => completer.proxy withDecls newScope withSourceModule (_ => module),
assocFile = completer.sourceFileOrNull)
enterNew(owner, module, completer, scope)
enterNew(owner, module.moduleClass, completer, scope)
@@ -142,8 +142,9 @@ class SymbolLoaders {
/** Load contents of a package
*/
- class PackageLoader(override val sourceModule: TermSymbol, classpath: ClassPath)
+ class PackageLoader(_sourceModule: TermSymbol, classpath: ClassPath)
extends SymbolLoader {
+ override def sourceModule(implicit ctx: Context) = _sourceModule
def description = "package loader " + classpath.name
private[core] val preDecls: MutableScope = newScope
@@ -242,7 +243,7 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {
else
ctx.newModuleSymbol(
rootDenot.owner, rootDenot.name.toTermName, Synthetic, Synthetic,
- (module, _) => new NoCompleter() withDecls newScope withSourceModule module)
+ (module, _) => new NoCompleter() withDecls newScope withSourceModule (_ => module))
.moduleClass.denot.asClass
}
if (rootDenot is ModuleClass) (linkedDenot, rootDenot)
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 35ab8419e..a7e59d356 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -499,7 +499,7 @@ object Symbols {
}
/** Have we seen a subclass of this class? */
- def hasChildren = superIdHint >= 0
+ def hasChildren = superIdHint >= 0 // dubious, does not survive runs if children are deleted!
override protected def prefixString = "ClassSymbol"
}
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index 1395b4f43..012fc7af3 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -32,7 +32,7 @@ class ClassfileParser(
protected var classTParams = Map[Name,Symbol]()
classRoot.info = (new NoCompleter).withDecls(instanceScope)
- moduleRoot.info = (new NoCompleter).withDecls(staticScope).withSourceModule(staticModule)
+ moduleRoot.info = (new NoCompleter).withDecls(staticScope).withSourceModule(_ => staticModule)
private def currentIsTopLevel(implicit ctx: Context) = classRoot.owner is Flags.PackageClass
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index 78a91b2ef..544a2ebdb 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -171,7 +171,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
case _ => errorBadSignature(s"a runtime exception occured: $ex", Some(ex))
}
- private var postReadOp: () => Unit = null
+ private var postReadOp: Context => Unit = null
def run()(implicit ctx: Context) =
try {
@@ -182,7 +182,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
readIndex = index(i)
entries(i) = readSymbol()
if (postReadOp != null) {
- postReadOp()
+ postReadOp(ctx)
postReadOp = null
}
readIndex = savedIndex
@@ -457,7 +457,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
ctx.newSymbol(owner, name1, flags1, localMemberUnpickler, coord = start)
case CLASSsym =>
val infoRef = readNat()
- postReadOp = () => atReadPos(index(infoRef), readTypeParams) // force reading type params early, so they get entered in the right order.
+ postReadOp = implicit ctx => atReadPos(index(infoRef), readTypeParams) // force reading type params early, so they get entered in the right order.
if (isClassRoot)
completeRoot(
classRoot, rootClassUnpickler(start, classRoot.symbol, NoSymbol))
@@ -471,7 +471,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
def completer(cls: Symbol) = {
val unpickler = new LocalUnpickler() withDecls symScope(cls)
if (flags is ModuleClass)
- unpickler withSourceModule (
+ unpickler withSourceModule (implicit ctx =>
cls.owner.decls.lookup(cls.name.sourceModuleName)
.suchThat(_ is Module).symbol)
else unpickler
@@ -543,7 +543,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
def rootClassUnpickler(start: Coord, cls: Symbol, module: Symbol) =
(new LocalUnpickler with SymbolLoaders.SecondCompleter {
override def startCoord(denot: SymDenotation): Coord = start
- }) withDecls symScope(cls) withSourceModule module
+ }) withDecls symScope(cls) withSourceModule (_ => module)
/** Convert
* tp { type name = sym } forSome { sym >: L <: H }
@@ -852,7 +852,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
val start = readIndex
val atp = readTypeRef()
Annotation.deferred(
- atp.typeSymbol, atReadPos(start, () => readAnnotationContents(end)))
+ atp.typeSymbol, implicit ctx => atReadPos(start, () => readAnnotationContents(end)))
}
/* Read an abstract syntax tree */