Skip to content

Commit e59e751

Browse files
committed
Refactor context pools
Also have a context pool for committable typer states, which gets used in isFullyDefined.
1 parent a6bb4c2 commit e59e751

File tree

2 files changed

+77
-56
lines changed

2 files changed

+77
-56
lines changed

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

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,9 @@ object Contexts {
500500
implicitsCache = null
501501
related = null
502502

503-
/** Reuse this context as a fresh context nested inside `outer` */
503+
/** Reuse this context as a fresh context nested inside `outer`
504+
* But keep the typerstate, this one has to be set explicitly if needed.
505+
*/
504506
def reuseIn(outer: Context): this.type
505507
}
506508

@@ -752,56 +754,40 @@ object Contexts {
752754
final def retractMode(mode: Mode): c.type = c.setMode(c.mode &~ mode)
753755
}
754756

755-
private def exploreCtx(using Context): FreshContext =
756-
util.Stats.record("explore")
757-
val base = ctx.base
758-
import base._
759-
val nestedCtx =
760-
if exploresInUse < exploreContexts.size then
761-
exploreContexts(exploresInUse).reuseIn(ctx)
762-
else
763-
val ts = TyperState()
764-
.setReporter(ExploringReporter())
765-
.setCommittable(false)
766-
val c = FreshContext(ctx.base).init(ctx, ctx).setTyperState(ts)
767-
exploreContexts += c
768-
c
769-
exploresInUse += 1
770-
val nestedTS = nestedCtx.typerState
771-
nestedTS.init(ctx.typerState, ctx.typerState.constraint)
772-
nestedCtx
773-
774-
private def wrapUpExplore(ectx: Context) =
775-
ectx.reporter.asInstanceOf[ExploringReporter].reset()
776-
ectx.base.exploresInUse -= 1
777-
757+
/** Run `op` with a pool-allocated context that has an ExporeTyperState. */
778758
inline def explore[T](inline op: Context ?=> T)(using Context): T =
779-
val ectx = exploreCtx
780-
try op(using ectx) finally wrapUpExplore(ectx)
759+
exploreInFreshCtx(op)
781760

761+
/** Run `op` with a pool-allocated FreshContext that has an ExporeTyperState. */
782762
inline def exploreInFreshCtx[T](inline op: FreshContext ?=> T)(using Context): T =
783-
val ectx = exploreCtx
784-
try op(using ectx) finally wrapUpExplore(ectx)
785-
786-
private def changeOwnerCtx(owner: Symbol)(using Context): Context =
787-
val base = ctx.base
788-
import base._
789-
val nestedCtx =
790-
if changeOwnersInUse < changeOwnerContexts.size then
791-
changeOwnerContexts(changeOwnersInUse).reuseIn(ctx)
792-
else
793-
val c = FreshContext(ctx.base).init(ctx, ctx)
794-
changeOwnerContexts += c
795-
c
796-
changeOwnersInUse += 1
797-
nestedCtx.setOwner(owner).setTyperState(ctx.typerState)
798-
799-
/** Run `op` in current context, in a reusable context that has the specified owner.
763+
val pool = ctx.base.exploreContextPool
764+
val nestedCtx = pool.next()
765+
try op(using nestedCtx)
766+
finally
767+
nestedCtx.typerState.reporter.asInstanceOf[ExploringReporter].reset()
768+
pool.free()
769+
770+
/** Run `op` with a pool-allocated context that has a fresh typer state.
771+
* Commit the typer state if `commit` applied to `op`'s result returns true.
800772
*/
773+
inline def withFreshTyperState[T](inline op: Context ?=> T, inline commit: T => Context ?=> Boolean)(using Context): T =
774+
val pool = ctx.base.freshTSContextPool
775+
val nestedCtx = pool.next()
776+
try
777+
val result = op(using nestedCtx)
778+
if commit(result)(using nestedCtx) then
779+
nestedCtx.typerState.commit()
780+
nestedCtx.typerState.setCommittable(true)
781+
result
782+
finally
783+
pool.free()
784+
785+
/** Run `op` with a pool-allocated context that has the given `owner`. */
801786
inline def runWithOwner[T](owner: Symbol)(inline op: Context ?=> T)(using Context): T =
802787
if Config.reuseOwnerContexts then
803-
try op(using changeOwnerCtx(owner))
804-
finally ctx.base.changeOwnersInUse -= 1
788+
val pool = ctx.base.generalContextPool
789+
try op(using pool.next().setOwner(owner).setTyperState(ctx.typerState))
790+
finally pool.free()
805791
else
806792
op(using ctx.fresh.setOwner(owner))
807793

@@ -893,6 +879,47 @@ object Contexts {
893879
allPhases.find(_.period.containsPhaseId(p.id)).getOrElse(NoPhase)
894880
}
895881

882+
class ContextPool:
883+
protected def fresh()(using Context): FreshContext =
884+
FreshContext(ctx.base).init(ctx, ctx)
885+
886+
private var inUse: Int = 0
887+
private var pool = new mutable.ArrayBuffer[FreshContext]
888+
889+
def next()(using Context): FreshContext =
890+
val base = ctx.base
891+
import base._
892+
val nestedCtx =
893+
if inUse < pool.size then
894+
pool(inUse).reuseIn(ctx)
895+
else
896+
val c = fresh()
897+
pool += c
898+
c
899+
inUse += 1
900+
nestedCtx
901+
902+
final def free(): Unit =
903+
inUse -= 1
904+
end ContextPool
905+
906+
class TSContextPool extends ContextPool:
907+
override def next()(using Context) =
908+
val nextCtx = super.next()
909+
nextCtx.typerState.init(ctx.typerState, ctx.typerState.constraint)
910+
nextCtx
911+
912+
class FreshTSContextPool extends TSContextPool:
913+
override protected def fresh()(using Context) =
914+
super.fresh().setTyperState(ctx.typerState.fresh(committable = true))
915+
916+
class ExploreContextPool extends TSContextPool:
917+
override protected def fresh()(using Context) =
918+
val ts = TyperState()
919+
.setReporter(ExploringReporter())
920+
.setCommittable(false)
921+
super.fresh().setTyperState(ts)
922+
896923
/** The essential mutable state of a context base, collected into a common class */
897924
class ContextState {
898925
// Symbols state
@@ -975,11 +1002,9 @@ object Contexts {
9751002

9761003
protected[dotc] val indentTab: String = " "
9771004

978-
private[Contexts] val exploreContexts = new mutable.ArrayBuffer[FreshContext]
979-
private[Contexts] var exploresInUse: Int = 0
980-
981-
private[Contexts] val changeOwnerContexts = new mutable.ArrayBuffer[FreshContext]
982-
private[Contexts] var changeOwnersInUse: Int = 0
1005+
val exploreContextPool = ExploreContextPool()
1006+
val freshTSContextPool = FreshTSContextPool()
1007+
val generalContextPool = ContextPool()
9831008

9841009
private[Contexts] val comparers = new mutable.ArrayBuffer[TypeComparer]
9851010
private[Contexts] var comparersInUse: Int = 0

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,8 @@ object Inferencing {
2626
* but only if the overall result of `isFullyDefined` is `true`.
2727
* Variables that are successfully minimized do not count as uninstantiated.
2828
*/
29-
def isFullyDefined(tp: Type, force: ForceDegree.Value)(using Context): Boolean = {
30-
val nestedCtx = ctx.fresh.setNewTyperState()
31-
val result = new IsFullyDefinedAccumulator(force)(using nestedCtx).process(tp)
32-
if (result) nestedCtx.typerState.commit()
33-
result
34-
}
29+
def isFullyDefined(tp: Type, force: ForceDegree.Value)(using Context): Boolean =
30+
withFreshTyperState(new IsFullyDefinedAccumulator(force).process(tp), x => x)
3531

3632
/** Try to fully define `tp`. Return whether constraint has changed.
3733
* Any changed constraint is kept.

0 commit comments

Comments
 (0)