Skip to content

Commit 9960e5a

Browse files
committed
Support early promotion of warm objects
1 parent 366c972 commit 9960e5a

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

compiler/src/dotty/tools/dotc/transform/init/Checking.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,6 @@ object Checking {
321321
val f = denot.symbol
322322
if !f.isOneOf(excludedFlags) && f.hasSource then
323323
buffer += Promote(FieldReturn(warm, f)(source))(source)
324-
buffer += FieldAccess(warm, f)(source)
325324
}
326325

327326
classRef.membersBasedOnFlags(Flags.Method, Flags.Deferred).foreach { denot =>

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ class Semantic {
321321

322322
case warm: Warm =>
323323
if warm.outer.canDirectlyPromote then Nil
324-
else PromoteWarm(source, trace) :: Nil
324+
else warm.tryPromote(msg, source)
325325

326326
case Fun(body, thisV, klass) =>
327327
val res = eval(body, thisV, klass)
@@ -335,6 +335,48 @@ class Semantic {
335335
refs.flatMap(_.promote(msg, source))
336336
end extension
337337

338+
extension (warm: Warm)
339+
/** Try early promotion of warm objects
340+
*
341+
* Promotion is expensive and should only be performed for small classes.
342+
*
343+
* 1. for each concrete method `m` of the warm object:
344+
* call the method and promote the result
345+
*
346+
* 2. for each concrete field `f` of the warm object:
347+
* promote the field value
348+
*
349+
*/
350+
def tryPromote(msg: String, source: Tree)(using Context, Trace): List[Error] =
351+
val classRef = warm.klass.appliedRef
352+
if classRef.memberClasses.nonEmpty then
353+
return PromoteWarm(source, trace) :: Nil
354+
355+
val fields = classRef.fields
356+
val methods = classRef.membersBasedOnFlags(Flags.Method, Flags.Deferred | Flags.Accessor)
357+
val buffer = new mutable.ArrayBuffer[Error]
358+
359+
fields.exists { denot =>
360+
val f = denot.symbol
361+
if !f.isOneOf(Flags.Deferred | Flags.Private | Flags.Protected) && f.hasSource then
362+
val res = warm.select(f, source)
363+
buffer ++= res.ensureHot(msg, source).errors
364+
buffer.nonEmpty
365+
}
366+
367+
buffer.nonEmpty || methods.exists { denot =>
368+
val m = denot.symbol
369+
if !m.isConstructor && m.hasSource then
370+
val res = warm.call(m, superType = m.owner.typeRef, source = source)
371+
buffer ++= res.ensureHot(msg, source).errors
372+
buffer.nonEmpty
373+
}
374+
375+
if buffer.isEmpty then Nil
376+
else UnsafePromotion(source, trace, buffer.toList) :: Nil
377+
378+
end extension
379+
338380
extension (ref: ThisRef | Warm)
339381
def updateField(field: Symbol, value: Value): Unit =
340382
ref match
@@ -669,7 +711,7 @@ class Semantic {
669711
// class body
670712
tpl.body.foreach {
671713
case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) =>
672-
val res = eval(vdef.rhs, thisV, klass)
714+
val res = eval(vdef.rhs, thisV, klass, cacheResult = true)
673715
errorBuffer ++= res.errors
674716
thisV.updateField(vdef.symbol, res.value)
675717

0 commit comments

Comments
 (0)