Skip to content

Commit 57a4c3d

Browse files
committed
Introduce global cache which holds fixed point value
1 parent bcf39c4 commit 57a4c3d

File tree

1 file changed

+46
-12
lines changed

1 file changed

+46
-12
lines changed

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

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,46 @@ object Semantic {
272272
*/
273273

274274
object Cache {
275-
opaque type CacheIn = mutable.Map[Value, EqHashMap[Tree, Value]]
276-
opaque type CacheOut = mutable.Map[Value, EqHashMap[Tree, Value]]
275+
opaque type CacheStore = mutable.Map[Value, EqHashMap[Tree, Value]]
277276

278-
class Cache(val in: CacheIn, var out: CacheOut) {
277+
class Cache {
278+
private val in: CacheStore = mutable.Map.empty
279+
private var out: CacheStore = mutable.Map.empty
280+
private val global: CacheStore = mutable.Map.empty
279281
var changed: Boolean = false
280282

283+
def contains(value: Value, expr: Tree) =
284+
out.contains(value, expr) || global.contains(value, expr)
285+
286+
def apply(value: Value, expr: Tree) =
287+
if out.contains(value, expr) then out(value)(expr)
288+
else global(value)(expr)
289+
290+
def assume(value: Value, expr: Tree) =
291+
val assumeValue = if (in.contains(value, expr)) in.get(value, expr) else Hot
292+
out.put(value, expr, assumeValue)
293+
assumeValue
294+
295+
def update(value: Value, expr: Tree, result: Value) =
296+
out.put(value, expr, result)
297+
298+
def remove(value: Value, expr: Tree) =
299+
out.remove(value, expr)
300+
301+
/** Commit out cache to global cache.
302+
*
303+
* Precondition: the out cache reaches fixed point.
304+
*/
305+
def commit() = {
306+
out.foreach { (v, m) =>
307+
m.iterator.foreach { (e, res) =>
308+
global.put(v, e, res)
309+
}
310+
}
311+
312+
out = mutable.Map.empty
313+
}
314+
281315
/** Copy out to in and reset out to empty */
282316
def update() = {
283317
out.foreach { (v, m) =>
@@ -290,10 +324,10 @@ object Semantic {
290324
}
291325
}
292326

293-
val empty: Cache = new Cache(mutable.Map.empty, mutable.Map.empty)
327+
val empty: Cache = new Cache()
294328

295-
extension (cache: CacheIn | CacheOut)
296-
def contains(value: Value, expr: Tree): Boolean = cache.contains(value) && cache(value).contains(expr)
329+
extension (cache: CacheStore)
330+
def contains(value: Value, expr: Tree) = cache.contains(value) && cache(value).contains(expr)
297331
def get(value: Value, expr: Tree): Value = cache(value)(expr)
298332
def remove(value: Value, expr: Tree) = cache(value).remove(expr)
299333
def put(value: Value, expr: Tree, result: Value): Unit = {
@@ -793,6 +827,7 @@ object Semantic {
793827

794828
if res.errors.nonEmpty || !cache.changed then
795829
pendingTasks = rest
830+
cache.commit()
796831
else
797832
// discard heap changes and copy cache.out to cache.in
798833
cache.update()
@@ -808,7 +843,7 @@ object Semantic {
808843
*
809844
* This method should only be called from the work list scheduler.
810845
*/
811-
private def doTask(task: Task)(using State, Context): Result = {
846+
private def doTask(task: Task)(using State, Context): Result = log("checking " + task) {
812847
val thisRef = task
813848
val tpl = thisRef.klass.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
814849

@@ -870,17 +905,16 @@ object Semantic {
870905
* This method only handles cache logic and delegates the work to `cases`.
871906
*/
872907
def eval(expr: Tree, thisV: Ref, klass: ClassSymbol, cacheResult: Boolean = false): Contextual[Result] = log("evaluating " + expr.show + ", this = " + thisV.show, printer, res => res.asInstanceOf[Result].show) {
873-
if (cache.out.contains(thisV, expr)) Result(cache.out.get(thisV, expr), Errors.empty)
908+
if (cache.contains(thisV, expr)) Result(cache(thisV, expr), Errors.empty)
874909
else {
875-
val assumeValue = if (cache.in.contains(thisV, expr)) cache.in.get(thisV, expr) else Hot
876-
cache.out.put(thisV, expr, assumeValue)
910+
val assumeValue = cache.assume(thisV, expr)
877911
val res = cases(expr, thisV, klass)
878912
if res.value != assumeValue then
879913
// println("changed: old = " + assumeValue + ", res = " + res.value)
880914
cache.changed = true
881-
cache.out.put(thisV, expr, res.value) // must put in cache for termination
915+
cache.update(thisV, expr, res.value) // must put in cache for termination
882916
else
883-
if !cacheResult then cache.out.remove(thisV, expr)
917+
if !cacheResult then cache.remove(thisV, expr)
884918
res
885919
}
886920
}

0 commit comments

Comments
 (0)