@@ -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 ] = SimpleIdentityMap .Empty
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)
309+ ctx1
310+
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+ ctx1 = fresh.setSource(source)
323+ related = related.updated(source, ctx1)
310324 ctx1
311- }
312325
313- final def withPhase (phase : Phase ): Context =
314- withPhase(phase.id)
326+ inline def evalAt [T ](phase : Phase )(inline op : Context ?=> T ): T =
327+ val saved = period
328+ this .asInstanceOf [FreshContext ].period = Period (runId, phase.id)
329+ try op(using this )
330+ finally period = saved
315331
316332 // `creationTrace`-related code. To enable, uncomment the code below and the
317333 // call to `setCreationTrace()` in this file.
@@ -476,8 +492,7 @@ object Contexts {
476492
477493 def reuseIn (outer : Context ): this .type =
478494 implicitsCache = null
479- phasedCtxs = null
480- sourceCtx = null
495+ related = null
481496 init(outer, outer)
482497
483498 /** A fresh clone of this context embedded in this context. */
@@ -491,29 +506,6 @@ object Contexts {
491506 final def withOwner (owner : Symbol ): Context =
492507 if (owner ne this .owner) fresh.setOwner(owner) else this
493508
494- private var sourceCtx : SimpleIdentityMap [SourceFile , Context ] = null
495-
496- final def withSource (source : SourceFile ): Context =
497- if (source `eq` this .source) this
498- else if ((source `eq` outer.source) &&
499- outer.sourceCtx != null &&
500- (outer.sourceCtx(this .source) `eq` this )) outer
501- else {
502- if (sourceCtx == null ) sourceCtx = SimpleIdentityMap .Empty
503- val prev = sourceCtx(source)
504- if (prev != null ) prev
505- else {
506- val newCtx = fresh.setSource(source)
507- if (newCtx.compilationUnit == null )
508- // `source` might correspond to a file not necessarily
509- // in the current project (e.g. when inlining library code),
510- // so set `mustExist` to false.
511- newCtx.setCompilationUnit(CompilationUnit (source, mustExist = false ))
512- sourceCtx = sourceCtx.updated(source, newCtx)
513- newCtx
514- }
515- }
516-
517509 final def withProperty [T ](key : Key [T ], value : Option [T ]): Context =
518510 if (property(key) == value) this
519511 else value match {
@@ -732,6 +724,7 @@ object Contexts {
732724 result
733725
734726 inline def comparing [T ](inline op : TypeComparer => T )(using Context ): T =
727+ util.Stats .record(" comparing" )
735728 val saved = ctx.base.comparersInUse
736729 try op(comparer)
737730 finally ctx.base.comparersInUse = saved
0 commit comments