@@ -194,16 +194,22 @@ class Semantic {
194
194
import Env ._
195
195
196
196
object Promoted {
197
+ class PromotionInfo {
198
+ var isCurrentObjectPromoted : Boolean = false
199
+ val values = mutable.Set .empty[Value ]
200
+ }
197
201
/** Values that have been safely promoted */
198
- opaque type Promoted = mutable. Set [ Value ]
202
+ opaque type Promoted = PromotionInfo
199
203
200
204
/** Note: don't use `val` to avoid incorrect sharing */
201
- def empty : Promoted = mutable. Set .empty
205
+ def empty : Promoted = new PromotionInfo
202
206
203
207
extension (promoted : Promoted )
204
- def contains (value : Value ): Boolean = promoted.contains(value)
205
- def add (value : Value ): Unit = promoted += value
206
- def remove (value : Value ): Unit = promoted -= value
208
+ def isCurrentObjectPromoted : Boolean = promoted.isCurrentObjectPromoted
209
+ def promoteCurrent (thisRef : ThisRef ): Unit = promoted.isCurrentObjectPromoted = true
210
+ def contains (value : Value ): Boolean = promoted.values.contains(value)
211
+ def add (value : Value ): Unit = promoted.values += value
212
+ def remove (value : Value ): Unit = promoted.values -= value
207
213
end extension
208
214
}
209
215
type Promoted = Promoted .Promoted
@@ -374,6 +380,9 @@ class Semantic {
374
380
def call (meth : Symbol , args : List [Value ], superType : Type , source : Tree , needResolve : Boolean = true ): Contextual [Result ] =
375
381
def checkArgs = args.flatMap { arg => arg.promote(" May only use initialized value as arguments" , arg.source) }
376
382
383
+ // fast track if the current object is already initialized
384
+ if promoted.isCurrentObjectPromoted then return Result (Hot , Nil )
385
+
377
386
value match {
378
387
case Hot =>
379
388
Result (Hot , checkArgs)
@@ -402,7 +411,7 @@ class Semantic {
402
411
if target.isPrimaryConstructor then
403
412
given Env = env2
404
413
val tpl = cls.defTree.asInstanceOf [TypeDef ].rhs.asInstanceOf [Template ]
405
- val res = eval(tpl, addr, cls, cacheResult = true )
414
+ val res = use(trace.add(cls.defTree)) { eval(tpl, addr, cls, cacheResult = true ) }
406
415
Result (addr, res.errors)
407
416
else if target.isConstructor then
408
417
given Env = env2
@@ -451,6 +460,7 @@ class Semantic {
451
460
if errors.isEmpty then Hot
452
461
else arg.widen
453
462
}
463
+
454
464
if buffer.isEmpty then Result (Hot , Errors .empty)
455
465
else
456
466
val value = Warm (klass, Hot , ctor, args2)
@@ -496,64 +506,37 @@ class Semantic {
496
506
end extension
497
507
498
508
// ----- Promotion ----------------------------------------------------
499
-
500
- extension (value : Value )
501
- /** Can we promote the value by checking the extrinsic values?
502
- *
503
- * The extrinsic values are environment values, e.g. outers for `Warm`
504
- * and `thisV` captured in functions.
505
- *
506
- * This is a fast track for early promotion of values.
507
- */
508
- def canPromoteExtrinsic : Contextual [Boolean ] = log(" canPromoteExtrinsic " + value + " , promoted = " + promoted, printer) {
509
- value match
510
- case Hot => true
511
- case Cold => false
512
-
513
- case warm : Warm =>
514
- (warm.outer :: warm.args).forall(_.canPromoteExtrinsic) && {
515
- promoted.add(warm)
516
- true
517
- }
518
-
519
- case thisRef : ThisRef =>
520
- promoted.contains(thisRef) || {
521
- val obj = heap(thisRef)
522
- // If we have all fields initialized, then we can promote This to hot.
523
- val allFieldsInitialized = thisRef.klass.appliedRef.fields.forall { denot =>
524
- val sym = denot.symbol
525
- sym.isOneOf(Flags .Lazy | Flags .Deferred ) || obj.fields.contains(sym)
526
- }
527
- if allFieldsInitialized then promoted.add(thisRef)
528
- allFieldsInitialized
529
- }
530
-
531
- case fun : Fun =>
532
- fun.thisV.canPromoteExtrinsic && {
533
- promoted.add(fun)
534
- true
509
+ extension (thisRef : ThisRef )
510
+ def tryPromoteCurrentObject : Contextual [Boolean ] = log(" tryPromoteCurrentObject " , printer) {
511
+ promoted.isCurrentObjectPromoted || {
512
+ val obj = heap(thisRef)
513
+ // If we have all fields initialized, then we can promote This to hot.
514
+ val allFieldsInitialized = thisRef.klass.appliedRef.fields.forall { denot =>
515
+ val sym = denot.symbol
516
+ sym.isOneOf(Flags .Lazy | Flags .Deferred ) || obj.fields.contains(sym)
535
517
}
536
-
537
- case RefSet (refs) =>
538
- refs.forall(_.canPromoteExtrinsic)
539
-
518
+ if allFieldsInitialized then promoted.promoteCurrent(thisRef)
519
+ allFieldsInitialized
520
+ }
540
521
}
541
522
523
+ extension (value : Value )
542
524
/** Promotion of values to hot */
543
525
def promote (msg : String , source : Tree ): Contextual [List [Error ]] = log(" promoting " + value + " , promoted = " + promoted, printer) {
544
- value match
526
+ if promoted.isCurrentObjectPromoted then Nil else
527
+
528
+ value.match
545
529
case Hot => Nil
546
530
547
531
case Cold => PromoteError (msg, source, trace.toVector) :: Nil
548
532
549
533
case thisRef : ThisRef =>
550
534
if promoted.contains(thisRef) then Nil
551
- else if thisRef.canPromoteExtrinsic then Nil
535
+ else if thisRef.tryPromoteCurrentObject then Nil
552
536
else PromoteError (msg, source, trace.toVector) :: Nil
553
537
554
538
case warm : Warm =>
555
539
if promoted.contains(warm) then Nil
556
- else if warm.canPromoteExtrinsic then Nil
557
540
else {
558
541
promoted.add(warm)
559
542
val errors = warm.tryPromote(msg, source)
@@ -902,7 +885,7 @@ class Semantic {
902
885
/** Resolve C.this that appear in `klass` */
903
886
def resolveThis (target : ClassSymbol , thisV : Value , klass : ClassSymbol , source : Tree ): Contextual [Value ] = log(" resolving " + target.show + " , this = " + thisV.show + " in " + klass.show, printer, res => res.asInstanceOf [Value ].show) {
904
887
if target == klass then thisV
905
- else if target.is(Flags .Package ) || target.isStaticOwner then Hot
888
+ else if target.is(Flags .Package ) then Hot
906
889
else
907
890
thisV match
908
891
case Hot => Hot
@@ -1005,6 +988,7 @@ class Semantic {
1005
988
if ctor.exists then superCall(tref, ctor, Nil , superParent)
1006
989
}
1007
990
991
+ var fieldsChanged = true
1008
992
1009
993
// class body
1010
994
tpl.body.foreach {
@@ -1013,10 +997,17 @@ class Semantic {
1013
997
val res = eval(vdef.rhs, thisV, klass, cacheResult = true )
1014
998
errorBuffer ++= res.errors
1015
999
thisV.updateField(vdef.symbol, res.value)
1000
+ fieldsChanged = true
1016
1001
1017
1002
case _ : MemberDef =>
1018
1003
1019
1004
case tree =>
1005
+ thisV match
1006
+ case thisRef : ThisRef =>
1007
+ if fieldsChanged then thisRef.tryPromoteCurrentObject
1008
+ fieldsChanged = false
1009
+ case _ =>
1010
+
1020
1011
given Env = Env .empty
1021
1012
errorBuffer ++= eval(tree, thisV, klass).errors
1022
1013
}
0 commit comments