Skip to content

Commit c5e1f0c

Browse files
authored
Merge pull request #9589 from dotty-staging/optimize-context-2
Streamline treatment of withPhase and withSource
2 parents 7cdab7f + 0b344b1 commit c5e1f0c

File tree

1 file changed

+44
-51
lines changed

1 file changed

+44
-51
lines changed

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

Lines changed: 44 additions & 51 deletions
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
// `creationTrace`-related code. To enable, uncomment the code below and the
317333
// call to `setCreationTrace()` in this file.
@@ -478,8 +494,7 @@ object Contexts {
478494

479495
def reuseIn(outer: Context): this.type =
480496
implicitsCache = null
481-
phasedCtxs = null
482-
sourceCtx = null
497+
related = null
483498
init(outer, outer)
484499

485500
/** A fresh clone of this context embedded in this context. */
@@ -493,29 +508,6 @@ object Contexts {
493508
final def withOwner(owner: Symbol): Context =
494509
if (owner ne this.owner) fresh.setOwner(owner) else this
495510

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

736728
inline def comparing[T](inline op: TypeComparer => T)(using Context): T =
729+
util.Stats.record("comparing")
737730
val saved = ctx.base.comparersInUse
738731
try op(comparer)
739732
finally ctx.base.comparersInUse = saved

0 commit comments

Comments
 (0)