package scala.reflect.internal package util import scala.collection.{ mutable, immutable } import scala.language.postfixOps trait TraceSymbolActivity { val global: SymbolTable import global._ private[this] var enabled = traceSymbolActivity if (enabled && global.isCompilerUniverse) scala.sys addShutdownHook showAllSymbols() private type Set[T] = scala.collection.immutable.Set[T] private val Set = scala.collection.immutable.Set val allSymbols = mutable.Map[Int, Symbol]() val allChildren = mutable.Map[Int, List[Int]]() withDefaultValue Nil val prevOwners = mutable.Map[Int, List[(Int, Phase)]]() withDefaultValue Nil val symsCaused = mutable.Map[Int, Int]() withDefaultValue 0 val allTrees = mutable.Set[Tree]() def recordSymbolsInTree(tree: Tree) { if (enabled) allTrees += tree } def recordNewSymbol(sym: Symbol) { if (enabled && sym.id > 1) { allSymbols(sym.id) = sym allChildren(sym.owner.id) ::= sym.id } } def recordNewSymbolOwner(sym: Symbol, newOwner: Symbol) { if (enabled) { val sid = sym.id val oid = sym.owner.id val nid = newOwner.id prevOwners(sid) ::= (oid -> phase) allChildren(oid) = allChildren(oid) filterNot (_ == sid) allChildren(nid) ::= sid } } /** TODO. */ private def reachableDirectlyFromSymbol(sym: Symbol): List[Symbol] = ( List(sym.owner, sym.alias, sym.thisSym) ++ sym.children ++ sym.info.parents.map(_.typeSymbol) ++ sym.typeParams ++ sym.paramss.flatten ) private def reachable[T](inputs: Traversable[T], mkSymbol: T => Symbol): Set[Symbol] = { def loop(seen: Set[Symbol], remaining: List[Symbol]): Set[Symbol] = { remaining match { case Nil => seen case head :: rest => if ((head eq null) || (head eq NoSymbol) || seen(head)) loop(seen, rest) else loop(seen + head, rest ++ reachableDirectlyFromSymbol(head).filterNot(seen)) } } loop(immutable.Set(), inputs.toList map mkSymbol filterNot (_ eq null) distinct) } private def treeList(t: Tree) = { val buf = mutable.ListBuffer[Tree]() t foreach (buf += _) buf.toList } private def reachableFromSymbol(root: Symbol): Set[Symbol] = reachable[Symbol](List(root, root.info.typeSymbol), x => x) private def reachableFromTree(tree: Tree): Set[Symbol] = reachable[Tree](treeList(tree), _.symbol) private def signature(id: Int) = runBeforeErasure(allSymbols(id).defString) private def dashes(s: Any): String = ("" + s) map (_ => '-') private def show(s1: Any, ss: Any*) { println("%-12s".format(s1) +: ss mkString " ") } private def showHeader(s1: Any, ss: Any*) { show(s1, ss: _*) show(dashes(s1), ss map dashes: _*) } private def showSym(sym: Symbol) { def prefix = (" " * (sym.ownerChain.length - 1)) + sym.id try println("%s#%s %s".format(prefix, sym.accurateKindString, sym.name.decode)) catch { case x: Throwable => println(prefix + " failed: " + x) } allChildren(sym.id).sorted foreach showIdAndRemove } private def showIdAndRemove(id: Int) { allSymbols remove id foreach showSym } private def symbolStr(id: Int): String = { if (id == 1) "NoSymbol" else { val sym = allSymbols(id) sym.accurateKindString + " " + sym.name.decode } } private def ownerStr(id: Int): String = { val sym = allSymbols(id) sym.name.decode + "#" + sym.id } private def freq[T, U](xs: scala.collection.Traversable[T])(fn: T => U): List[(U, Int)] = { val ys = xs groupBy fn mapValues (_.size) ys.toList sortBy (-_._2) } private def showMapFreq[T](xs: scala.collection.Map[T, Traversable[_]])(showFn: T => String) { xs.mapValues(_.size).toList.sortBy(-_._2) take 100 foreach { case (k, size) => show(size, showFn(k)) } println("\n") } private def showFreq[T, U](xs: Traversable[T])(groupFn: T => U, showFn: U => String = (x: U) => "" + x) = { showMapFreq(xs.toList groupBy groupFn)(showFn) } private lazy val findErasurePhase: Phase = { var ph = phase while (ph != NoPhase && ph.name != "erasure") { ph = ph.prev } ph } private def runBeforeErasure[T](body: => T): T = atPhase(findErasurePhase)(body) def showAllSymbols() { if (!enabled) return enabled = false allSymbols(1) = NoSymbol println("" + allSymbols.size + " symbols created.") println("") showHeader("descendants", "symbol") showFreq(allSymbols.values flatMap (_.ownerChain drop 1))(_.id, symbolStr) showHeader("children", "symbol") showMapFreq(allChildren)(symbolStr) if (prevOwners.nonEmpty) { showHeader("prev owners", "symbol") showMapFreq(prevOwners) { k => val owners = (((allSymbols(k).owner.id, NoPhase)) :: prevOwners(k)) map { case (oid, NoPhase) => "-> owned by " + ownerStr(oid) case (oid, ph) => "-> owned by %s (until %s)".format(ownerStr(oid), ph) } signature(k) :: owners mkString "\n " } } val nameFreq = allSymbols.values.toList groupBy (_.name) showHeader("frequency", "%-15s".format("name"), "owners") showMapFreq(nameFreq) { name => "%-15s %s".format(name.decode, { val owners = freq(nameFreq(name))(_.owner) "%4s owners (%s)".format( owners.size, owners.take(3).map({ case (k, v) => v + "/" + k }).mkString(", ") + ", ..." ) }) } allSymbols.keys.toList.sorted foreach showIdAndRemove } }