diff options
author | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2012-09-25 05:52:35 -0700 |
---|---|---|
committer | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2012-09-25 05:52:35 -0700 |
commit | ebeb3684b2e80f826f55276c760c192510b3b84d (patch) | |
tree | 23f2e7113b8de7508eadb86884aeb4e228cb507a /src | |
parent | db8dea0055739ec39c8765565c5f479ab360acf9 (diff) | |
parent | bb48b7a4528335770c7c72341f58f326c11f6284 (diff) | |
download | scala-ebeb3684b2e80f826f55276c760c192510b3b84d.tar.gz scala-ebeb3684b2e80f826f55276c760c192510b3b84d.tar.bz2 scala-ebeb3684b2e80f826f55276c760c192510b3b84d.zip |
Merge pull request #1392 from gkossakowski/revert-leaks-fix
Revert "SI-6412 alleviates leaks in toolboxes"
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/ToolBoxFactory.scala | 21 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Importers.scala | 164 |
3 files changed, 82 insertions, 107 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 0fbd930ad7..58fcee4b30 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1079,12 +1079,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) * of what file was being compiled when it broke. Since I really * really want to know, this hack. */ - protected var lastSeenSourceFile: SourceFile = NoSourceFile + private var lastSeenSourceFile: SourceFile = NoSourceFile /** Let's share a lot more about why we crash all over the place. * People will be very grateful. */ - protected var lastSeenContext: analyzer.Context = null + private var lastSeenContext: analyzer.Context = null /** The currently active run */ diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 790c78cbf5..f985eedf99 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -46,23 +46,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => newTermName("__wrapper$" + wrapCount + "$" + java.util.UUID.randomUUID.toString.replace("-", "")) } - // should be called after every use of ToolBoxGlobal in order to prevent leaks - // there's the `withCleanupCaches` method defined below, which provides a convenient interface for that - def cleanupCaches(): Unit = { - lub(List(IntTpe, IntTpe)) // indirectly clears lubResults and glbResults - // I didn't want to turn those caches from private to protected - // in order not to screw up the performance - perRunCaches.clearAll() - undoLog.clear() - analyzer.lastTreeToTyper = EmptyTree - lastSeenSourceFile = NoSourceFile - lastSeenContext = null - } - - def withCleanupCaches[T](body: => T): T = - try body - finally cleanupCaches() - def verify(expr: Tree): Unit = { // Previously toolboxes used to typecheck their inputs before compiling. // Actually, the initial demo by Martin first typechecked the reified tree, @@ -354,7 +337,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => lazy val importer = compiler.mkImporter(u) lazy val exporter = importer.reverse - def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = compiler.withCleanupCaches { + def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = { if (compiler.settings.verbose.value) println("importing "+tree+", expectedType = "+expectedType) var ctree: compiler.Tree = importer.importTree(tree) var cexpectedType: compiler.Type = importer.importType(expectedType) @@ -374,7 +357,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => inferImplicit(tree, viewTpe, isView = true, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos) } - private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = compiler.withCleanupCaches { + private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = { if (compiler.settings.verbose.value) println("importing "+pt, ", tree = "+tree+", pos = "+pos) var ctree: compiler.Tree = importer.importTree(tree) var cpt: compiler.Type = importer.importType(pt) diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 02209d0712..c116928d37 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -1,8 +1,6 @@ package scala.reflect package internal - import scala.collection.mutable.WeakHashMap -import scala.ref.WeakReference // SI-6241: move importers to a mirror trait Importers extends api.Importers { self: SymbolTable => @@ -28,20 +26,8 @@ trait Importers extends api.Importers { self: SymbolTable => val from: SymbolTable - protected lazy val symMap = new Cache[from.Symbol, Symbol]() - protected lazy val tpeMap = new Cache[from.Type, Type]() - protected class Cache[K <: AnyRef, V <: AnyRef] extends WeakHashMap[K, WeakReference[V]] { - def weakGet(key: K): Option[V] = this get key flatMap WeakReference.unapply - def weakUpdate(key: K, value: V) = this.update(key, WeakReference(value)) - def weakGetOrElseUpdate(key: K)(value: => V): V = - weakGet(key) match { - case Some(result) => result - case None => - val result = value - this(key) = WeakReference(result) - result - } - } + lazy val symMap: WeakHashMap[from.Symbol, Symbol] = new WeakHashMap + lazy val tpeMap: WeakHashMap[from.Type, Type] = new WeakHashMap // fixups and maps prevent stackoverflows in importer var pendingSyms = 0 @@ -58,10 +44,8 @@ trait Importers extends api.Importers { self: SymbolTable => object reverse extends from.StandardImporter { val from: self.type = self - // FIXME this and reverse should be constantly kept in sync - // not just synced once upon the first usage of reverse - for ((fromsym, WeakReference(mysym)) <- StandardImporter.this.symMap) symMap += ((mysym, WeakReference(fromsym))) - for ((fromtpe, WeakReference(mytpe)) <- StandardImporter.this.tpeMap) tpeMap += ((mytpe, WeakReference(fromtpe))) + for ((fromsym, mysym) <- StandardImporter.this.symMap) symMap += ((mysym, fromsym)) + for ((fromtpe, mytpe) <- StandardImporter.this.tpeMap) tpeMap += ((mytpe, fromtpe)) } // todo. careful import of positions @@ -69,70 +53,70 @@ trait Importers extends api.Importers { self: SymbolTable => pos.asInstanceOf[Position] def importSymbol(sym0: from.Symbol): Symbol = { - def doImport(sym: from.Symbol): Symbol = - symMap weakGet sym match { - case Some(result) => result - case _ => - val myowner = importSymbol(sym.owner) - val mypos = importPosition(sym.pos) - val myname = importName(sym.name).toTermName - val myflags = sym.flags - def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = { - symMap.weakUpdate(x, mysym) - mysym.referenced = op(x.referenced) - mysym + def doImport(sym: from.Symbol): Symbol = { + if (symMap.contains(sym)) + return symMap(sym) + + val myowner = importSymbol(sym.owner) + val mypos = importPosition(sym.pos) + val myname = importName(sym.name).toTermName + val myflags = sym.flags + def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = { + symMap(x) = mysym + mysym.referenced = op(x.referenced) + mysym + } + val mysym = sym match { + case x: from.MethodSymbol => + linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol) + case x: from.ModuleSymbol => + linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, importSymbol) + case x: from.FreeTermSymbol => + newFreeTermSymbol(importName(x.name).toTermName, x.value, x.flags, x.origin) setInfo importType(x.info) + case x: from.FreeTypeSymbol => + newFreeTypeSymbol(importName(x.name).toTypeName, x.flags, x.origin) + case x: from.TermSymbol => + linkReferenced(myowner.newValue(myname, mypos, myflags), x, importSymbol) + case x: from.TypeSkolem => + val origin = x.unpackLocation match { + case null => null + case y: from.Tree => importTree(y) + case y: from.Symbol => importSymbol(y) } - val mysym = sym match { - case x: from.MethodSymbol => - linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol) - case x: from.ModuleSymbol => - linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, importSymbol) - case x: from.FreeTermSymbol => - newFreeTermSymbol(importName(x.name).toTermName, x.value, x.flags, x.origin) setInfo importType(x.info) - case x: from.FreeTypeSymbol => - newFreeTypeSymbol(importName(x.name).toTypeName, x.flags, x.origin) - case x: from.TermSymbol => - linkReferenced(myowner.newValue(myname, mypos, myflags), x, importSymbol) - case x: from.TypeSkolem => - val origin = x.unpackLocation match { - case null => null - case y: from.Tree => importTree(y) - case y: from.Symbol => importSymbol(y) - } - myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags) - case x: from.ModuleClassSymbol => - val mysym = myowner.newModuleClass(myname.toTypeName, mypos, myflags) - symMap.weakUpdate(x, mysym) - mysym.sourceModule = importSymbol(x.sourceModule) - mysym - case x: from.ClassSymbol => - val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags) - symMap.weakUpdate(x, mysym) - if (sym.thisSym != sym) { - mysym.typeOfThis = importType(sym.typeOfThis) - mysym.thisSym setName importName(sym.thisSym.name) - } - mysym - case x: from.TypeSymbol => - myowner.newTypeSymbol(myname.toTypeName, mypos, myflags) + myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags) + case x: from.ModuleClassSymbol => + val mysym = myowner.newModuleClass(myname.toTypeName, mypos, myflags) + symMap(x) = mysym + mysym.sourceModule = importSymbol(x.sourceModule) + mysym + case x: from.ClassSymbol => + val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags) + symMap(x) = mysym + if (sym.thisSym != sym) { + mysym.typeOfThis = importType(sym.typeOfThis) + mysym.thisSym setName importName(sym.thisSym.name) } - symMap.weakUpdate(sym, mysym) - mysym setFlag Flags.LOCKED - mysym setInfo { - val mytypeParams = sym.typeParams map importSymbol - new LazyPolyType(mytypeParams) { - override def complete(s: Symbol) { - val result = sym.info match { - case from.PolyType(_, res) => res - case result => result - } - s setInfo GenPolyType(mytypeParams, importType(result)) - s setAnnotations (sym.annotations map importAnnotationInfo) - } + mysym + case x: from.TypeSymbol => + myowner.newTypeSymbol(myname.toTypeName, mypos, myflags) + } + symMap(sym) = mysym + mysym setFlag Flags.LOCKED + mysym setInfo { + val mytypeParams = sym.typeParams map importSymbol + new LazyPolyType(mytypeParams) { + override def complete(s: Symbol) { + val result = sym.info match { + case from.PolyType(_, res) => res + case result => result } + s setInfo GenPolyType(mytypeParams, importType(result)) + s setAnnotations (sym.annotations map importAnnotationInfo) } - mysym resetFlag Flags.LOCKED - } // end doImport + } + } + mysym resetFlag Flags.LOCKED + } // end doImport def importOrRelink: Symbol = { val sym = sym0 // makes sym visible in the debugger @@ -202,10 +186,14 @@ trait Importers extends api.Importers { self: SymbolTable => } // end importOrRelink val sym = sym0 - symMap.weakGetOrElseUpdate(sym) { + if (symMap contains sym) { + symMap(sym) + } else { pendingSyms += 1 - try importOrRelink - finally { + + try { + symMap getOrElseUpdate (sym, importOrRelink) + } finally { pendingSyms -= 1 tryFixup() } @@ -270,10 +258,14 @@ trait Importers extends api.Importers { self: SymbolTable => def importOrRelink: Type = doImport(tpe) - tpeMap.weakGetOrElseUpdate(tpe) { + if (tpeMap contains tpe) { + tpeMap(tpe) + } else { pendingTpes += 1 - try importOrRelink - finally { + + try { + tpeMap getOrElseUpdate (tpe, importOrRelink) + } finally { pendingTpes -= 1 tryFixup() } |