Skip to content

Commit b0c4f33

Browse files
authored
Merge pull request #9659 from dotty-staging/optimize-change-owner
Re-use contexts when changing owners in MegaPhase
2 parents 2c330d2 + 57e233b commit b0c4f33

File tree

3 files changed

+83
-50
lines changed

3 files changed

+83
-50
lines changed

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,36 @@ package dotty.tools.dotc.config
22

33
object Config {
44

5-
final val cacheMembersNamed = true
6-
final val cacheAsSeenFrom = true
7-
final val cacheMemberNames = true
8-
final val cacheImplicitScopes = true
9-
final val cacheMatchReduced = true
5+
inline val cacheMembersNamed = true
6+
inline val cacheAsSeenFrom = true
7+
inline val cacheMemberNames = true
8+
inline val cacheImplicitScopes = true
9+
inline val cacheMatchReduced = true
1010

11-
final val checkCacheMembersNamed = false
11+
/** If true, the `runWithOwner` operation uses a re-usable context,
12+
* similar to explore. This requires that the context does not escape
13+
* the call. If false, `runWithOwner` runs its operation argument
14+
* in a fresh context.
15+
*/
16+
inline val reuseOwnerContexts = true
17+
18+
inline val checkCacheMembersNamed = false
1219

1320
/** When updating a constraint bound, check that the constrained parameter
1421
* does not appear at the top-level of either of its bounds.
1522
*/
16-
final val checkConstraintsNonCyclic = false
23+
inline val checkConstraintsNonCyclic = false
1724

1825
/** Check that each constraint resulting from a subtype test
1926
* is satisfiable.
2027
*/
21-
final val checkConstraintsSatisfiable = false
28+
inline val checkConstraintsSatisfiable = false
2229

2330
/** Check that each constraint is fully propagated. i.e.
2431
* If P <: Q then the upper bound of P is a subtype of the upper bound of Q
2532
* and the lower bound of Q is a subtype of the lower bound of P.
2633
*/
27-
final val checkConstraintsPropagated = false
34+
inline val checkConstraintsPropagated = false
2835

2936
/** Check that constraints of globally committable typer states are closed.
3037
* NOTE: When enabled, the check can cause CyclicReference errors because
@@ -35,51 +42,51 @@ object Config {
3542
* It is recommended to turn this option on only when chasing down
3643
* a TypeParamRef instantiation error. See comment in Types.TypeVar.instantiate.
3744
*/
38-
final val debugCheckConstraintsClosed = false
45+
inline val debugCheckConstraintsClosed = false
3946

4047
/** Check that no type appearing as the info of a SymDenotation contains
4148
* skolem types.
4249
*/
43-
final val checkNoSkolemsInInfo = false
50+
inline val checkNoSkolemsInInfo = false
4451

4552
/** Check that Name#toString is not called directly from backend by analyzing
4653
* the stack trace of each toString call on names. This is very expensive,
4754
* so not suitable for continuous testing. But it can be used to find a problem
4855
* when running a specific test.
4956
*/
50-
final val checkBackendNames = false
57+
inline val checkBackendNames = false
5158

5259
/** Check that re-used type comparers are in their initialization state */
53-
final val checkTypeComparerReset = false
60+
inline val checkTypeComparerReset = false
5461

5562
/** Type comparer will fail with an assert if the upper bound
5663
* of a constrained parameter becomes Nothing. This should be turned
5764
* on only for specific debugging as normally instantiation to Nothing
5865
* is not an error condition.
5966
*/
60-
final val failOnInstantiationToNothing = false
67+
inline val failOnInstantiationToNothing = false
6168

6269
/** Enable noDoubleDef checking if option "-YnoDoubleDefs" is set.
6370
* The reason to have an option as well as the present global switch is
6471
* that the noDoubleDef checking is done in a hotspot, and we do not
6572
* want to incur the overhead of checking an option each time.
6673
*/
67-
final val checkNoDoubleBindings = true
74+
inline val checkNoDoubleBindings = true
6875

6976
/** Check positions for consistency after parsing */
70-
final val checkPositions = true
77+
inline val checkPositions = true
7178

7279
/** Check that typed trees don't point to untyped ones */
73-
final val checkTreesConsistent = false
80+
inline val checkTreesConsistent = false
7481

7582
/** Show subtype traces for all deep subtype recursions */
76-
final val traceDeepSubTypeRecursions = false
83+
inline val traceDeepSubTypeRecursions = false
7784

7885
/** When explaining subtypes and this flag is set, also show the classes of the compared types. */
79-
final val verboseExplainSubtype = false
86+
inline val verboseExplainSubtype = false
8087

8188
/** If this flag is set, take the fast path when comparing same-named type-aliases and types */
82-
final val fastPathForRefinedSubtype = true
89+
inline val fastPathForRefinedSubtype = true
8390

8491
/** If this flag is set, and we compute `T1[X1]` & `T2[X2]` as a new
8592
* upper bound of a constrained parameter, try to align the arguments by computing
@@ -88,20 +95,20 @@ object Config {
8895
*
8996
* For more info, see the comment in `TypeComparer#glbArgs`.
9097
*/
91-
final val alignArgsInAnd = true
98+
inline val alignArgsInAnd = true
9299

93100
/** If this flag is set, higher-kinded applications are checked for validity
94101
*/
95-
final val checkHKApplications = false
102+
inline val checkHKApplications = false
96103

97104
/** If this flag is set, method types are checked for valid parameter references
98105
*/
99-
final val checkMethodTypes = false
106+
inline val checkMethodTypes = false
100107

101108
/** If this flag is set, it is checked that TypeRefs don't refer directly
102109
* to themselves.
103110
*/
104-
final val checkTypeRefCycles = false
111+
inline val checkTypeRefCycles = false
105112

106113
/** If this flag is set, we check that types assigned to trees are error types only
107114
* if some error was already reported. There are complicicated scenarios where this
@@ -113,35 +120,35 @@ object Config {
113120
* this in all circumstances. But since it is almost always true it is useful to
114121
* keep the Config option for debugging.
115122
*/
116-
final val checkUnreportedErrors = false
123+
inline val checkUnreportedErrors = false
117124

118125
/** If this flag is set, it is checked that class type parameters are
119126
* only references with NoPrefix or ThisTypes as prefixes. This option
120127
* is usually disabled, because there are still some legitimate cases where
121128
* this can arise (e.g. for pos/Map.scala, in LambdaType.integrate).
122129
*/
123-
final val checkTypeParamRefs = false
130+
inline val checkTypeParamRefs = false
124131

125132
/** The recursion depth for showing a summarized string */
126-
final val summarizeDepth = 2
133+
inline val summarizeDepth = 2
127134

128135
/** Check that variances of lambda arguments match the
129136
* variance of the underlying lambda class.
130137
*/
131-
final val checkLambdaVariance = false
138+
inline val checkLambdaVariance = false
132139

133140
/** Check that certain types cannot be created in erasedTypes phases.
134141
* Note: Turning this option on will get some false negatives, since it is
135142
* possible that And/Or types are still created during erasure as the result
136143
* of some operation on an existing type.
137144
*/
138-
final val checkUnerased = false
145+
inline val checkUnerased = false
139146

140147
/** Check that atoms-based comparisons match regular comparisons that do not
141148
* take atoms into account. The two have to give the same results, since
142149
* atoms comparison is intended to be just an optimization.
143150
*/
144-
final val checkAtomsComparisons = false
151+
inline val checkAtomsComparisons = false
145152

146153
/** In `derivedSelect`, rewrite
147154
*
@@ -151,39 +158,39 @@ object Config {
151158
* Not sure whether this is useful. Preliminary measurements show a slowdown of about
152159
* 7% for the build when this option is enabled.
153160
*/
154-
final val splitProjections = false
161+
inline val splitProjections = false
155162

156163
/** If this flag is on, always rewrite an application `S[Ts]` where `S` is an alias for
157164
* `[Xs] -> U` to `[Xs := Ts]U`.
158165
* Turning this flag on was observed to give a ~6% speedup on the JUnit test suite.
159166
*/
160-
final val simplifyApplications = true
167+
inline val simplifyApplications = true
161168

162169
/** Assume -indent by default */
163-
final val defaultIndent = true
170+
inline val defaultIndent = true
164171

165172
/** If set, prints a trace of all symbol completions */
166-
final val showCompletions = false
173+
inline val showCompletions = false
167174

168175
/** If set, method results that are context functions are flattened by adding
169176
* the parameters of the context function results to the methods themselves.
170177
* This is an optimization that reduces closure allocations.
171178
*/
172-
final val flattenContextFunctionResults = true
179+
inline val flattenContextFunctionResults = true
173180

174181
/** If set, enables tracing */
175-
final val tracingEnabled = false
182+
inline val tracingEnabled = false
176183

177184
/** Initial capacity of uniques HashMap.
178185
* Note: This MUST BE a power of two to work with util.HashSet
179186
*/
180-
final val initialUniquesCapacity = 65536
187+
inline val initialUniquesCapacity = 65536
181188

182189
/** How many recursive calls to NamedType#underlying are performed before logging starts. */
183-
final val LogPendingUnderlyingThreshold = 50
190+
inline val LogPendingUnderlyingThreshold = 50
184191

185192
/** How many recursive calls to isSubType are performed before logging starts. */
186-
final val LogPendingSubTypesThreshold = 50
193+
inline val LogPendingSubTypesThreshold = 50
187194

188195
/** How many recursive calls to findMember are performed before logging names starts
189196
* Note: this threshold has to be chosen carefully. Too large, and programs
@@ -194,8 +201,8 @@ object Config {
194201
* dotty itself only causes small pending names lists to be generated (we measured
195202
* at max 6 elements) and these lists are never searched with contains.
196203
*/
197-
final val LogPendingFindMemberThreshold = 9
204+
inline val LogPendingFindMemberThreshold = 9
198205

199206
/** When in IDE, turn StaleSymbol errors into warnings instead of crashing */
200-
final val ignoreStaleInIDE = true
207+
inline val ignoreStaleInIDE = true
201208
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,28 @@ object Contexts {
701701
val ectx = exploreCtx
702702
try op(using ectx) finally wrapUpExplore(ectx)
703703

704+
private def changeOwnerCtx(owner: Symbol)(using Context): Context =
705+
val base = ctx.base
706+
import base._
707+
val nestedCtx =
708+
if changeOwnersInUse < changeOwnerContexts.size then
709+
changeOwnerContexts(changeOwnersInUse).reuseIn(ctx)
710+
else
711+
val c = FreshContext(ctx.base).init(ctx, ctx)
712+
changeOwnerContexts += c
713+
c
714+
changeOwnersInUse += 1
715+
nestedCtx.setOwner(owner).setTyperState(ctx.typerState)
716+
717+
/** Run `op` in current context, with a mode is temporarily set as specified.
718+
*/
719+
inline def runWithOwner[T](owner: Symbol)(inline op: Context ?=> T)(using Context): T =
720+
if Config.reuseOwnerContexts then
721+
try op(using changeOwnerCtx(owner))
722+
finally ctx.base.changeOwnersInUse -= 1
723+
else
724+
op(using ctx.fresh.setOwner(owner))
725+
704726
/** The type comparer of the kind created by `maker` to be used.
705727
* This is the currently active type comparer CMP if
706728
* - CMP is associated with the current context, and
@@ -890,6 +912,9 @@ object Contexts {
890912
private[Contexts] val exploreContexts = new mutable.ArrayBuffer[FreshContext]
891913
private[Contexts] var exploresInUse: Int = 0
892914

915+
private[Contexts] val changeOwnerContexts = new mutable.ArrayBuffer[FreshContext]
916+
private[Contexts] var changeOwnersInUse: Int = 0
917+
893918
private[Contexts] val comparers = new mutable.ArrayBuffer[TypeComparer]
894919
private[Contexts] var comparersInUse: Int = 0
895920

compiler/src/dotty/tools/dotc/transform/MegaPhase.scala

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,10 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
213213

214214
/** Transform full tree using all phases in this group that have idxInGroup >= start */
215215
def transformTree(tree: Tree, start: Int)(using Context): Tree = {
216-
def localContext(using Context) = {
216+
217+
inline def inLocalContext[T](inline op: Context ?=> T)(using Context): T =
217218
val sym = tree.symbol
218-
val owner = if (sym.is(PackageVal)) sym.moduleClass else sym
219-
ctx.fresh.setOwner(owner)
220-
}
219+
runWithOwner(if (sym.is(PackageVal)) sym.moduleClass else sym)(op)
221220

222221
def transformNamed(tree: Tree, start: Int, outerCtx: Context): Tree = tree match {
223222
case tree: Ident =>
@@ -236,8 +235,10 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
236235
val rhs = transformTree(tree.rhs, start)
237236
cpy.ValDef(tree)(tree.name, tpt, rhs)
238237
}
239-
if (tree.isEmpty) tree
240-
else goValDef(mapValDef(using if (tree.symbol.exists) localContext else ctx), start)
238+
if tree.isEmpty then tree
239+
else goValDef(
240+
if tree.symbol.exists then inLocalContext(mapValDef) else mapValDef,
241+
start)
241242
}
242243
case tree: DefDef =>
243244
inContext(prepDefDef(tree, start)(using outerCtx)) {
@@ -248,11 +249,11 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
248249
val rhs = transformTree(tree.rhs, start)
249250
cpy.DefDef(tree)(tree.name, tparams, vparamss, tpt, rhs)
250251
}
251-
goDefDef(mapDefDef(using localContext), start)
252+
goDefDef(inLocalContext(mapDefDef), start)
252253
}
253254
case tree: TypeDef =>
254255
inContext(prepTypeDef(tree, start)(using outerCtx)) {
255-
val rhs = transformTree(tree.rhs, start)(using localContext)
256+
val rhs = inLocalContext(transformTree(tree.rhs, start))
256257
goTypeDef(cpy.TypeDef(tree)(tree.name, rhs), start)
257258
}
258259
case tree: Labeled =>
@@ -381,7 +382,7 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
381382
val stats = transformStats(tree.stats, tree.symbol, start)
382383
cpy.PackageDef(tree)(pid, stats)
383384
}
384-
goPackageDef(mapPackage(using localContext), start)
385+
goPackageDef(inLocalContext(mapPackage), start)
385386
}
386387
case tree: Try =>
387388
inContext(prepTry(tree, start)(using outerCtx)) {

0 commit comments

Comments
 (0)