Skip to content

Commit 06756eb

Browse files
committed
Streamline treatment of withPhase and withSource
Use a joint SimpleIdentityMap for both.
1 parent e9509f8 commit 06756eb

File tree

1 file changed

+44
-51
lines changed

1 file changed

+44
-51
lines changed

compiler/src/dotty/tools/dotc/core/Contexts.scala

+44-51
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ object Contexts {
6969

7070
/** Execute `op` at given phase */
7171
inline def atPhase[T](phase: Phase)(inline op: Context ?=> T)(using Context): T =
72-
atPhase(phase.id)(op)
72+
op(using ctx.withPhase(phase))
7373

7474
inline def atNextPhase[T](inline op: Context ?=> T)(using Context): T =
7575
atPhase(ctx.phase.next)(op)
@@ -262,7 +262,7 @@ object Contexts {
262262

263263
/** Sourcefile corresponding to given abstract file, memoized */
264264
def getSource(file: AbstractFile, codec: => Codec = Codec(settings.encoding.value)) = {
265-
util.Stats.record("getSource")
265+
util.Stats.record("Context.getSource")
266266
base.sources.getOrElseUpdate(file, new SourceFile(file, codec))
267267
}
268268

@@ -285,33 +285,49 @@ object Contexts {
285285
/** Sourcefile with given path, memoized */
286286
def getSource(path: String): SourceFile = getSource(path.toTermName)
287287

288-
/** Those fields are used to cache phases created in withPhase.
289-
* phasedCtx is first phase with altered phase ever requested.
290-
* phasedCtxs is array that uses phaseId's as indexes,
291-
* contexts are created only on request and cached in this array
292-
*/
293-
private var phasedCtx: Context = this
294-
private var phasedCtxs: Array[Context] = null
288+
private var related: SimpleIdentityMap[Phase | SourceFile, Context] = null
295289

296-
/** This context at given phase.
297-
* This method will always return a phase period equal to phaseId, thus will never return a fused phase
298-
*/
299-
final def withPhase(phaseId: PhaseId): Context =
300-
if (this.period.phaseId == phaseId) this
301-
else if (phasedCtx.period.phaseId == phaseId) phasedCtx
302-
else if (phasedCtxs != null && phasedCtxs(phaseId) != null) phasedCtxs(phaseId)
303-
else {
304-
val ctx1 = fresh.setPhase(phaseId)
305-
if (phasedCtx eq this) phasedCtx = ctx1
306-
else {
307-
if (phasedCtxs == null) phasedCtxs = new Array[Context](base.phases.length)
308-
phasedCtxs(phaseId) = ctx1
309-
}
290+
private def lookup(key: Phase | SourceFile): Context =
291+
util.Stats.record("Context.related.lookup")
292+
if related == null then
293+
related = SimpleIdentityMap.Empty
294+
null
295+
else
296+
related(key)
297+
298+
private def withPhase(phase: Phase, pid: PhaseId): Context =
299+
util.Stats.record("Context.withPhase")
300+
val curId = phaseId
301+
if curId == pid then
302+
this
303+
else
304+
var ctx1 = lookup(phase)
305+
if ctx1 == null then
306+
util.Stats.record("Context.withPhase.new")
307+
ctx1 = fresh.setPhase(pid)
308+
related = related.updated(phase, ctx1)
310309
ctx1
311-
}
312310

313-
final def withPhase(phase: Phase): Context =
314-
withPhase(phase.id)
311+
final def withPhase(phase: Phase): Context = withPhase(phase, phase.id)
312+
final def withPhase(pid: PhaseId): Context = withPhase(base.phases(pid), pid)
313+
314+
final def withSource(source: SourceFile): Context =
315+
util.Stats.record("Context.withSource")
316+
if this.source eq source then
317+
this
318+
else
319+
var ctx1 = lookup(source)
320+
if ctx1 == null then
321+
util.Stats.record("Context.withSource.new")
322+
val ctx2 = fresh.setSource(source)
323+
if ctx2.compilationUnit == null then
324+
// `source` might correspond to a file not necessarily
325+
// in the current project (e.g. when inlining library code),
326+
// so set `mustExist` to false.
327+
ctx2.setCompilationUnit(CompilationUnit(source, mustExist = false))
328+
ctx1 = ctx2
329+
related = related.updated(source, ctx2)
330+
ctx1
315331

316332
inline def evalAt[T](phase: Phase)(inline op: Context ?=> T): T =
317333
val saved = period
@@ -482,8 +498,7 @@ object Contexts {
482498

483499
def reuseIn(outer: Context): this.type =
484500
implicitsCache = null
485-
phasedCtxs = null
486-
sourceCtx = null
501+
related = null
487502
init(outer, outer)
488503

489504
/** A fresh clone of this context embedded in this context. */
@@ -497,29 +512,6 @@ object Contexts {
497512
final def withOwner(owner: Symbol): Context =
498513
if (owner ne this.owner) fresh.setOwner(owner) else this
499514

500-
private var sourceCtx: SimpleIdentityMap[SourceFile, Context] = null
501-
502-
final def withSource(source: SourceFile): Context =
503-
if (source `eq` this.source) this
504-
else if ((source `eq` outer.source) &&
505-
outer.sourceCtx != null &&
506-
(outer.sourceCtx(this.source) `eq` this)) outer
507-
else {
508-
if (sourceCtx == null) sourceCtx = SimpleIdentityMap.Empty
509-
val prev = sourceCtx(source)
510-
if (prev != null) prev
511-
else {
512-
val newCtx = fresh.setSource(source)
513-
if (newCtx.compilationUnit == null)
514-
// `source` might correspond to a file not necessarily
515-
// in the current project (e.g. when inlining library code),
516-
// so set `mustExist` to false.
517-
newCtx.setCompilationUnit(CompilationUnit(source, mustExist = false))
518-
sourceCtx = sourceCtx.updated(source, newCtx)
519-
newCtx
520-
}
521-
}
522-
523515
final def withProperty[T](key: Key[T], value: Option[T]): Context =
524516
if (property(key) == value) this
525517
else value match {
@@ -738,6 +730,7 @@ object Contexts {
738730
result
739731

740732
inline def comparing[T](inline op: TypeComparer => T)(using Context): T =
733+
util.Stats.record("comparing")
741734
val saved = ctx.base.comparersInUse
742735
try op(comparer)
743736
finally ctx.base.comparersInUse = saved

0 commit comments

Comments
 (0)