Skip to content

Commit 78e1d1a

Browse files
committed
Optimize for primitive values
1 parent 535e4b2 commit 78e1d1a

File tree

1 file changed

+61
-47
lines changed

1 file changed

+61
-47
lines changed

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

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ object Objects:
162162
val joinedTrace = data.pendingTraces.slice(index + 1, data.checkingObjects.size).foldLeft(pendingTrace) { (a, acc) => acc ++ a }
163163
val callTrace = Trace.buildStacktrace(joinedTrace, "Calling trace:\n")
164164
val cycle = data.checkingObjects.slice(index, data.checkingObjects.size)
165-
val pos = clazz.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template].constr
165+
val pos = clazz.defTree
166166
report.warning("Cyclic initialization: " + cycle.map(_.show).mkString(" -> ") + " -> " + clazz.show + ". " + callTrace, pos)
167167
else if index == -1 && data.checkedObjects.indexOf(clazz) == -1 then
168168
data.pendingTraces += pendingTrace
@@ -186,12 +186,15 @@ object Objects:
186186

187187
def show(using Context): String
188188

189-
/** Local environments can be deeply nested, therefore we need `outer`. */
190-
private case class LocalEnv(private[Env] val params: Map[Symbol, Value], owner: Symbol, outer: Data)(using Context) extends Data:
189+
/** Local environments can be deeply nested, therefore we need `outer`.
190+
*
191+
* For local variables in rhs of class field definitions, the `meth` is the primary constructor.
192+
*/
193+
private case class LocalEnv(private[Env] val params: Map[Symbol, Value], meth: Symbol, outer: Data)(using Context) extends Data:
191194
val level = outer.level + 1
192195

193196
if (level > 3)
194-
report.warning("[Internal error] Deeply nested environemnt, level = " + level + ", " + owner.show + " in " + owner.enclosingClass.show, owner.defTree)
197+
report.warning("[Internal error] Deeply nested environemnt, level = " + level + ", " + meth.show + " in " + meth.enclosingClass.show, meth.defTree)
195198

196199
private[Env] val locals: mutable.Map[Symbol, Value] = mutable.Map.empty
197200

@@ -203,10 +206,10 @@ object Objects:
203206
params.contains(x) || locals.contains(x)
204207

205208
def widen(height: Int)(using Context): Data =
206-
new LocalEnv(params.map(_ -> _.widen(height)), owner, outer.widen(height))
209+
new LocalEnv(params.map(_ -> _.widen(height)), meth, outer.widen(height))
207210

208211
def show(using Context) =
209-
"owner: " + owner.show + "\n" +
212+
"owner: " + meth.show + "\n" +
210213
"params: " + params.map(_.show + " ->" + _.show).mkString("{", ", ", "}") + "\n" +
211214
"locals: " + locals.map(_.show + " ->" + _.show).mkString("{", ", ", "}") + "\n" +
212215
"outer = {\n" + outer.show + "\n}"
@@ -265,19 +268,19 @@ object Objects:
265268
* @param thisV The value for `this` of the enclosing class where the local variable is referenced.
266269
* @param env The local environment where the local variable is referenced.
267270
*/
268-
def resolveEnv(owner: Symbol, thisV: Value, env: Data)(using Context): Option[(Value, Data)] =
271+
def resolveEnv(meth: Symbol, thisV: Value, env: Data)(using Context): Option[(Value, Data)] = log("Resolving env for " + meth.show + ", this = " + thisV.show + ", env = " + env.show, printer) {
269272
env match
270273
case localEnv: LocalEnv =>
271-
if localEnv.owner == owner then Some(thisV -> env)
272-
else resolveEnv(owner, thisV, localEnv.outer)
274+
if localEnv.meth == meth then Some(thisV -> env)
275+
else resolveEnv(meth, thisV, localEnv.outer)
273276
case NoEnv =>
274277
// TODO: handle RefSet
275278
thisV match
276279
case ref: OfClass =>
277-
resolveEnv(owner, ref.outer, ref.env)
280+
resolveEnv(meth, ref.outer, ref.env)
278281
case _ =>
279282
None
280-
end resolveEnv
283+
}
281284

282285
def withEnv[T](env: Data)(fn: Data ?=> T): T = fn(using env)
283286
end Env
@@ -517,7 +520,8 @@ object Objects:
517520
else if target.exists then
518521
if target.isOneOf(Flags.Mutable) then
519522
if ref.owner == State.currentObject then
520-
Heap.read(ref, field)
523+
val isPrimitive = field.info.typeSymbol.isPrimitiveValueClass
524+
if isPrimitive then Bottom else Heap.read(ref, field)
521525
else
522526
report.warning("Reading mutable state of " + ref.owner.show + " during initialization of " + State.currentObject + " is discouraged as it breaks initialization-time irrelevance. Calling trace: " + Trace.show, Trace.position)
523527
Bottom
@@ -566,7 +570,9 @@ object Objects:
566570
if ref.owner != State.currentObject then
567571
errorMutateOtherStaticObject(State.currentObject, ref.owner)
568572
else
569-
Heap.write(ref, field, rhs)
573+
val isPrimitive = field.info.typeSymbol.isPrimitiveValueClass
574+
if !isPrimitive then
575+
Heap.write(ref, field, rhs)
570576
end match
571577

572578
Bottom
@@ -587,7 +593,8 @@ object Objects:
587593
if klass.owner.isClass then
588594
(outer.widen(1), Env.NoEnv)
589595
else
590-
Env.resolveEnv(klass.enclosingMethod, outer, summon[Env.Data]).getOrElse(Cold -> Env.NoEnv)
596+
// klass.enclosingMethod returns its primary constructor
597+
Env.resolveEnv(klass.owner.enclosingMethod, outer, summon[Env.Data]).getOrElse(Cold -> Env.NoEnv)
591598

592599
val instance = OfClass(klass, outerWidened, ctor, args.map(_.value), envWidened, State.currentObject)
593600
callConstructor(instance, ctor, args)
@@ -598,51 +605,58 @@ object Objects:
598605
}
599606

600607
def initLocal(ref: Ref, sym: Symbol, value: Value): Contextual[Unit] = log("initialize local " + sym.show + " with " + value.show, printer) {
601-
if sym.is(Flags.Mutable) then
602-
val env = summon[Env.Data]
603-
Heap.writeLocalVar(ref, env, sym, value)
604-
else
605-
Env.setLocalVal(sym, value)
608+
val isPrimitive = sym.info.typeSymbol.isPrimitiveValueClass
609+
if !isPrimitive then
610+
if sym.is(Flags.Mutable) then
611+
val env = summon[Env.Data]
612+
Heap.writeLocalVar(ref, env, sym, value)
613+
else
614+
Env.setLocalVal(sym, value)
606615
}
607616

608617
def readLocal(thisV: Value, sym: Symbol): Contextual[Value] = log("reading local " + sym.show, printer, (_: Value).show) {
609-
Env.resolveEnv(sym.enclosingMethod, thisV, summon[Env.Data]) match
610-
case Some(thisV -> env) =>
611-
if sym.is(Flags.Mutable) then
612-
thisV match
613-
case ref: Ref =>
614-
Heap.readLocalVar(ref, env, sym)
615-
case _ =>
618+
val isPrimitive = sym.info.typeSymbol.isPrimitiveValueClass
619+
if isPrimitive then
620+
Bottom
621+
else
622+
Env.resolveEnv(sym.enclosingMethod, thisV, summon[Env.Data]) match
623+
case Some(thisV -> env) =>
624+
if sym.is(Flags.Mutable) then
625+
thisV match
626+
case ref: Ref =>
627+
Heap.readLocalVar(ref, env, sym)
628+
case _ =>
629+
Cold
630+
else if sym.isPatternBound then
631+
// TODO: handle patterns
616632
Cold
617-
else if sym.isPatternBound then
618-
// TODO: handle patterns
619-
Cold
620-
else
621-
given Env.Data = env
622-
try
623-
Env(sym)
624-
catch ex =>
625-
report.warning("[Internal error] Not found " + sym.show + "\nenv = " + env.show + ". Calling trace:\n" + Trace.show, Trace.position)
626-
Bottom
633+
else
634+
given Env.Data = env
635+
try
636+
Env(sym)
637+
catch ex =>
638+
report.warning("[Internal error] Not found " + sym.show + "\nenv = " + env.show + ". Calling trace:\n" + Trace.show, Trace.position)
639+
Bottom
627640

628-
case _ => Cold
641+
case _ => Cold
629642
}
630643

631644
def writeLocal(thisV: Value, sym: Symbol, value: Value): Contextual[Value] = log("write local " + sym.show + " with " + value.show, printer, (_: Value).show) {
632645

633646
assert(sym.is(Flags.Mutable), "Writing to immutable variable " + sym.show)
647+
val isPrimitive = sym.info.typeSymbol.isPrimitiveValueClass
648+
if !isPrimitive then
649+
Env.resolveEnv(sym.enclosingMethod, thisV, summon[Env.Data]) match
650+
case Some(thisV -> env) =>
651+
thisV match
652+
case ref: Ref =>
653+
Heap.writeLocalVar(ref, summon[Env.Data], sym, value)
654+
case _ =>
655+
report.warning("Assigning to variables in outer scope", Trace.position)
634656

635-
Env.resolveEnv(sym.enclosingMethod, thisV, summon[Env.Data]) match
636-
case Some(thisV -> env) =>
637-
thisV match
638-
case ref: Ref =>
639-
Heap.writeLocalVar(ref, summon[Env.Data], sym, value)
640657
case _ =>
641658
report.warning("Assigning to variables in outer scope", Trace.position)
642-
643-
case _ =>
644-
report.warning("Assigning to variables in outer scope", Trace.position)
645-
659+
end if
646660
Bottom
647661
}
648662

@@ -660,7 +674,7 @@ object Objects:
660674
def iterate()(using Context): Unit =
661675
count += 1
662676

663-
given Trace = Trace.empty.add(tpl.constr)
677+
given Trace = Trace.empty.add(classSym.defTree)
664678
given env: Env.Data = Env.emptyEnv(tpl.constr.symbol)
665679

666680
log("Iteration " + count) {

0 commit comments

Comments
 (0)