Skip to content

Homogenize mutable symbol maps #3122

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 2 commits into from
Nov 22, 2017
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
2 changes: 1 addition & 1 deletion compiler/sjs/backend/sjs/JSPrimitives.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class JSPrimitives(ctx: Context) extends DottyPrimitives(ctx) {
/** Initialize the primitive map */
private def initJSPrimitives(implicit ctx: Context): Map[Symbol, Int] = {

val primitives = new mutable.HashMap[Symbol, Int]()
val primitives = newMutableSymbolMap[Int]

// !!! Code duplicate with DottyPrimitives
/** Add a primitive operation to the map */
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ class GenBCode extends Phase {
private val entryPoints = new mutable.HashSet[Symbol]()
def registerEntryPoint(sym: Symbol) = entryPoints += sym

private val superCallsMap = new mutable.HashMap[Symbol, Set[ClassSymbol]]()
private val superCallsMap = newMutableSymbolMap[Set[ClassSymbol]]
def registerSuperCall(sym: Symbol, calls: ClassSymbol) = {
val old = superCallsMap.getOrElse(sym, Set.empty)
superCallsMap.put(sym, old + calls)
superCallsMap.update(sym, old + calls)
}

def outputDir(implicit ctx: Context): AbstractFile =
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/backend/jvm/LabelDefs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class LabelDefs extends MiniPhase {
case t: DefDef =>
assert(t.symbol is Label)
EmptyTree
case _ => if (labelDefs.nonEmpty) super.transform(tree) else tree
case _ => if (!labelDefs.isEmpty) super.transform(tree) else tree
}
}
}
Expand All @@ -86,9 +86,9 @@ class LabelDefs extends MiniPhase {
}
}

private def collectLabelDefs(tree: Tree)(implicit ctx: Context): mutable.HashMap[Symbol, DefDef] = {
private def collectLabelDefs(tree: Tree)(implicit ctx: Context): MutableSymbolMap[DefDef] = {
// labelSymbol -> Defining tree
val labelDefs = new mutable.HashMap[Symbol, DefDef]()
val labelDefs = newMutableSymbolMap[DefDef]
new TreeTraverser {
override def traverse(tree: Tree)(implicit ctx: Context): Unit = tree match {
case t: DefDef =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class DottyPrimitives(ctx: Context) {
implicit val ctx = this.ctx

import core.Symbols.defn
val primitives = new mutable.HashMap[Symbol, Int]()
val primitives = core.Symbols.newMutableSymbolMap[Int]

/** Add a primitive operation to the map */
def addPrimitive(s: Symbol, code: Int): Unit = {
Expand Down
8 changes: 3 additions & 5 deletions compiler/src/dotty/tools/dotc/core/Comments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@ object Comments {
* docstrings via `Symbol` and expanding templates
*/
class ContextDocstrings {
import scala.collection.mutable

private[this] val _docstrings: mutable.Map[Symbol, Comment] =
mutable.Map.empty
private[this] val _docstrings: MutableSymbolMap[Comment] = newMutableSymbolMap

val templateExpander = new CommentExpander

Expand All @@ -35,7 +33,7 @@ object Comments {
def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym)

def addDocstring(sym: Symbol, doc: Option[Comment]): Unit =
doc.map(d => _docstrings += (sym -> d))
doc.map(d => _docstrings.update(sym, d))
}

/** A `Comment` contains the unformatted docstring as well as a position
Expand Down Expand Up @@ -182,7 +180,7 @@ object Comments {
protected def superComment(sym: Symbol)(implicit ctx: Context): Option[String] =
allInheritedOverriddenSymbols(sym).iterator map (x => cookedDocComment(x)) find (_ != "")

private val cookedDocComments = mutable.HashMap[Symbol, String]()
private val cookedDocComments = newMutableSymbolMap[String]

/** The raw doc comment of symbol `sym`, minus usecase and define sections, augmented by
* missing sections of an inherited doc comment.
Expand Down
66 changes: 66 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -678,4 +678,70 @@ object Symbols {
def currentClass(implicit ctx: Context): ClassSymbol = ctx.owner.enclosingClass.asClass

@sharable var stubs: List[Symbol] = Nil // diagnostic only

/* Mutable map from symbols any T */
class MutableSymbolMap[T](private[Symbols] val value: java.util.IdentityHashMap[Symbol, T]) extends AnyVal {

def apply(sym: Symbol): T = value.get(sym)

def get(sym: Symbol): Option[T] = Option(value.get(sym))

def getOrElse[U >: T](sym: Symbol, default: => U): U = {
val v = value.get(sym)
if (v != null) v else default
}

def getOrElseUpdate(sym: Symbol, op: => T): T = {
val v = value.get(sym)
if (v != null) v
else {
val v = op
assert(v != null)
value.put(sym, v)
v
}
}

def update(sym: Symbol, x: T): Unit = {
assert(x != null)
value.put(sym, x)
}
def put(sym: Symbol, x: T): T = {
assert(x != null)
value.put(sym, x)
}

def -=(sym: Symbol): Unit = value.remove(sym)
def remove(sym: Symbol): Option[T] = Option(value.remove(sym))

def contains(sym: Symbol): Boolean = value.containsKey(sym)

def isEmpty: Boolean = value.isEmpty

def clear(): Unit = value.clear()

def filter(p: ((Symbol, T)) => Boolean): Map[Symbol, T] = {
import scala.collection.JavaConversions._
value.toMap.filter(p)
}

def iterator: Iterator[(Symbol, T)] = {
import scala.collection.JavaConversions._
value.iterator
}

def keysIterator: Iterator[Symbol] = {
import scala.collection.JavaConversions._
value.keySet().iterator
}

def toMap: Map[Symbol, T] = {
import scala.collection.JavaConversions._
value.toMap
}
}

@inline def newMutableSymbolMap[T]: MutableSymbolMap[T] =
new MutableSymbolMap(new java.util.IdentityHashMap[Symbol, T]())

}
10 changes: 5 additions & 5 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ class TreePickler(pickler: TastyPickler) {
import pickler.nameBuffer.nameIndex
import ast.tpd._

private val symRefs = new mutable.HashMap[Symbol, Addr]
private val forwardSymRefs = new mutable.HashMap[Symbol, List[Addr]]
private val symRefs = Symbols.newMutableSymbolMap[Addr]
private val forwardSymRefs = Symbols.newMutableSymbolMap[List[Addr]]
private val pickledTypes = new java.util.IdentityHashMap[Type, Any] // Value type is really Addr, but that's not compatible with null

private def withLength(op: => Unit) = {
Expand Down Expand Up @@ -586,15 +586,15 @@ class TreePickler(pickler: TastyPickler) {

def pickle(trees: List[Tree])(implicit ctx: Context) = {
trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree))
def missing = forwardSymRefs.keySet.toList.map(_.showLocated)
def missing = forwardSymRefs.keysIterator.map(_.showLocated).toList
assert(forwardSymRefs.isEmpty, i"unresolved symbols: $missing%, % when pickling ${ctx.source}")
}

def compactify() = {
buf.compactify()

def updateMapWithDeltas[T](mp: collection.mutable.Map[T, Addr]) =
for (key <- mp.keysIterator.toBuffer[T]) mp(key) = adjusted(mp(key))
def updateMapWithDeltas(mp: MutableSymbolMap[Addr]) =
for (key <- mp.keysIterator.toBuffer[Symbol]) mp(key) = adjusted(mp(key))

updateMapWithDeltas(symRefs)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Bridges.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Bridges(root: ClassSymbol)(implicit ctx: Context) {
private[this] var toBeRemoved = immutable.Set[Symbol]()
private val bridges = mutable.ListBuffer[Tree]()
private val bridgesScope = newScope
private val bridgeTarget = mutable.HashMap[Symbol, Symbol]()
private val bridgeTarget = newMutableSymbolMap[Symbol]

/** Add a bridge between `member` and `other`, where `member` overrides `other`
* before erasure, if the following conditions are satisfied.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete
extensionMeth
}

private val extensionDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]()
private val extensionDefs = newMutableSymbolMap[mutable.ListBuffer[Tree]]
// TODO: this is state and should be per-run
// todo: check that when transformation finished map is empty

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class NonLocalReturns extends MiniPhase {
defn.NonLocalReturnControlType.appliedTo(argtype)

/** A hashmap from method symbols to non-local return keys */
private val nonLocalReturnKeys = mutable.Map[Symbol, TermSymbol]()
private val nonLocalReturnKeys = newMutableSymbolMap[TermSymbol]

/** Return non-local return key for given method */
private def nonLocalReturnKey(meth: Symbol)(implicit ctx: Context) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ object OverridingPairs {
}

private val subParents = {
val subParents = new mutable.HashMap[Symbol, BitSet]
val subParents = newMutableSymbolMap[BitSet]
for (bc <- base.info.baseClasses)
subParents(bc) = BitSet(parents.indices.filter(parents(_).derivesFrom(bc)): _*)
subParents
Expand Down
10 changes: 5 additions & 5 deletions compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ object PatternMatcher {
/** A map from variable symbols to their defining trees
* and from labels to their defining plans
*/
private val initializer = mutable.Map[Symbol, Tree]()
private val labelled = mutable.Map[Symbol, Plan]()
private val initializer = newMutableSymbolMap[Tree]
private val labelled = newMutableSymbolMap[Plan]

private def newVar(rhs: Tree, flags: FlagSet): TermSymbol =
ctx.newSymbol(ctx.owner, PatMatStdBinderName.fresh(), Synthetic | Case | flags,
Expand Down Expand Up @@ -529,7 +529,7 @@ object PatternMatcher {
tests1.filter { case(test, outcome) => tests2.get(test) == Some(outcome) }

/** The tests with known outcomes valid at entry to label */
val seenAtLabel = mutable.HashMap[Symbol, SeenTests]()
val seenAtLabel = newMutableSymbolMap[SeenTests]

class ElimRedundant(seenTests: SeenTests) extends PlanTransform {
override def apply(plan: TestPlan): Plan = {
Expand Down Expand Up @@ -609,12 +609,12 @@ object PatternMatcher {
type SeenVars = Map[RHS, TermSymbol]

/** The variables known at entry to label */
val seenAtLabel = mutable.HashMap[Symbol, SeenVars]()
val seenAtLabel = newMutableSymbolMap[SeenVars]

/** Parameters of label; these are passed additional variables
* which are known at all callsites.
*/
val paramsOfLabel = mutable.HashMap[Symbol, SeenVars]()
val paramsOfLabel = newMutableSymbolMap[SeenVars]

class Merge(seenVars: SeenVars) extends PlanTransform {
override val treeMap = new TreeMap {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisPh
/** A map to cache mapping local methods to their direct counterparts.
* A fresh map is created for each unit.
*/
private var DirectMeth: Store.Location[mutable.HashMap[Symbol, Symbol]] = _
private var DirectMeth: Store.Location[MutableSymbolMap[Symbol]] = _
private def directMeth(implicit ctx: Context) = ctx.store(DirectMeth)

override def initContext(ctx: FreshContext) =
DirectMeth = ctx.addLocation[mutable.HashMap[Symbol, Symbol]]()
DirectMeth = ctx.addLocation[MutableSymbolMap[Symbol]]()

/** If this option is true, we don't specialize symbols that are known to be only
* targets of monomorphic calls.
Expand All @@ -70,7 +70,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisPh
final val specializeMonoTargets = true

override def prepareForUnit(tree: Tree)(implicit ctx: Context) =
ctx.fresh.updateStore(DirectMeth, new mutable.HashMap[Symbol, Symbol])
ctx.fresh.updateStore(DirectMeth, newMutableSymbolMap[Symbol])

/** Should `sym` get a ..$direct companion?
* This is the case if (1) `sym` is a method with an implicit function type as final result type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class SuperAccessors(thisPhase: DenotTransformer) {
ctx.owner.enclosingClass != invalidEnclClass

/** List buffers for new accessor definitions, indexed by class */
private val accDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]()
private val accDefs = newMutableSymbolMap[mutable.ListBuffer[Tree]]

/** A super accessor call corresponding to `sel` */
private def superAccessorCall(sel: Select)(implicit ctx: Context) = {
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class TreeChecker extends Phase with SymTransformer {
class Checker(phasesToCheck: Seq[Phase]) extends ReTyper with Checking {

val nowDefinedSyms = new mutable.HashSet[Symbol]
val everDefinedSyms = new mutable.HashMap[Symbol, untpd.Tree]
val everDefinedSyms = newMutableSymbolMap[untpd.Tree]

// don't check value classes after typer, as the constraint about constructors doesn't hold after transform
override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = ()
Expand Down
26 changes: 13 additions & 13 deletions compiler/src/dotty/tools/dotc/transform/localopt/Devalify.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ import transform.SymUtils._
class Devalify extends Optimisation {
import ast.tpd._

val timesUsed = mutable.HashMap[Symbol, Int]()
val timesUsedAsType = mutable.HashMap[Symbol, Int]()
val timesUsed = newMutableSymbolMap[Int]
val timesUsedAsType = newMutableSymbolMap[Int]

val defined = mutable.HashSet[Symbol]()
val usedInInnerClass = mutable.HashMap[Symbol, Int]()
val usedInInnerClass = newMutableSymbolMap[Int]
// Either a duplicate or a read through series of immutable fields
val copies = mutable.HashMap[Symbol, Tree]()
val copies = newMutableSymbolMap[Tree]

def clear(): Unit = {
timesUsed.clear()
Expand All @@ -43,27 +43,27 @@ class Devalify extends Optimisation {
tp.foreachPart(x => x match {
case TermRef(NoPrefix, _) =>
val b4 = timesUsedAsType.getOrElseUpdate(x.termSymbol, 0)
timesUsedAsType.put(x.termSymbol, b4 + 1)
timesUsedAsType.update(x.termSymbol, b4 + 1)
case _ =>
})
}

def doVisit(tree: Tree, used: mutable.HashMap[Symbol, Int])(implicit ctx: Context): Unit = tree match {
def doVisit(tree: Tree, used: MutableSymbolMap[Int])(implicit ctx: Context): Unit = tree match {
case valdef: ValDef if !valdef.symbol.is(Param | Mutable | Module | Lazy) &&
valdef.symbol.exists && !valdef.symbol.owner.isClass =>
defined += valdef.symbol

dropCasts(valdef.rhs) match {
case t: Tree if readingOnlyVals(t) =>
copies.put(valdef.symbol, valdef.rhs)
copies.update(valdef.symbol, valdef.rhs)
case _ =>
}
visitType(valdef.symbol.info)
case t: New =>
val normalized = t.tpt.tpe.normalizedPrefix
val symIfExists = normalized.termSymbol
val b4 = used.getOrElseUpdate(symIfExists, 0)
used.put(symIfExists, b4 + 1)
used(symIfExists) = b4 + 1
visitType(normalized)

case valdef: ValDef if valdef.symbol.exists && !valdef.symbol.owner.isClass &&
Expand All @@ -77,7 +77,7 @@ class Devalify extends Optimisation {
case t: TypeApply => t.args.foreach(x => visitType(x.tpe))
case t: RefTree =>
val b4 = used.getOrElseUpdate(t.symbol, 0)
used.put(t.symbol, b4 + 1)
used.update(t.symbol, b4 + 1)
case _ =>
}

Expand Down Expand Up @@ -107,21 +107,21 @@ class Devalify extends Optimisation {
}

def transformer(implicit ctx: Context): Tree => Tree = {
val valsToDrop = defined -- timesUsed.keySet -- timesUsedAsType.keySet
val valsToDrop = defined -- timesUsed.keysIterator -- timesUsedAsType.keysIterator
val copiesToReplaceAsDuplicates = copies.filter { x =>
val rhs = dropCasts(x._2)
rhs.isInstanceOf[Literal] || (!rhs.symbol.owner.isClass && !rhs.symbol.is(Method | Mutable))
} -- timesUsedAsType.keySet
} -- timesUsedAsType.keysIterator
// TODO: if a non-synthetic val is duplicate of a synthetic one, rename a synthetic one and drop synthetic flag?

val copiesToReplaceAsUsedOnce =
timesUsed.filter(x => x._2 == 1)
.flatMap(x => copies.get(x._1) match {
case Some(tr) => List((x._1, tr))
case None => Nil
}) -- timesUsedAsType.keySet
}) -- timesUsedAsType.keysIterator

val replacements = copiesToReplaceAsDuplicates ++ copiesToReplaceAsUsedOnce -- usedInInnerClass.keySet
val replacements = copiesToReplaceAsDuplicates ++ copiesToReplaceAsUsedOnce -- usedInInnerClass.keysIterator

val deepReplacer = new TreeMap() {
override def transform(tree: Tree)(implicit ctx: Context): Tree = {
Expand Down
Loading