summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/symtab/Caches.scala
blob: 10d7500f09220d91e2f46e92e85086fe42e40efb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/* NSC -- new scala compiler
 * Copyright 2005-2011 LAMP/EPFL
 * @author  Paul Phillips
 */

package scala.tools.nsc
package symtab

import scala.collection.{ mutable, immutable }

/** A cache for some entity whose validity depends on a monotonically
 *  increasing sequence number.
 */
abstract class SequencedCache[T >: Null] {
  def zero: Int
  def sequenceId: Int
  def calculate(): T

  /** If sequence numbers differ, this condition is consulted before
   *  updating the cached value.
   */
  def isCacheValid: Boolean

  /** Public so accesses can be inlined. */
  @inline var cachedId: Int = 0
  @inline var cachedValue: T = _

  /** Puts cache back in uninitialized state. */
  @inline final def clear() = {
    cachedId = zero
    cachedValue = null
  }
  /** Resets the sequence id without touching the cached value. */
  @inline final def reset() = {
    cachedId = zero
  }

  final def get(): T = {
    if (cachedValue == null) {
      cachedValue = calculate()
      cachedId = sequenceId
    }
    else if (cachedId != sequenceId) {
      if (!isCacheValid)
        cachedValue = calculate()

      cachedId = sequenceId
    }
    cachedValue
  }
}

trait Caches {
  self: SymbolTable =>

  final def isValid(period: Period): Boolean =
    period != 0 && runId(period) == currentRunId && {
      val pid = phaseId(period)
      if (phase.id > pid) infoTransformers.nextFrom(pid).pid >= phase.id
      else infoTransformers.nextFrom(phase.id).pid >= pid
    }

  final def isValidForBaseClasses(period: Period): Boolean = {
    def noChangeInBaseClasses(it: InfoTransformer, limit: Phase#Id): Boolean = (
      it.pid >= limit ||
      !it.changesBaseClasses && noChangeInBaseClasses(it.next, limit)
    );
    period != 0 && runId(period) == currentRunId && {
      val pid = phaseId(period)
      if (phase.id > pid) noChangeInBaseClasses(infoTransformers.nextFrom(pid), phase.id)
      else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), pid)
    }
  }

  abstract class PeriodCache[T >: Null] extends SequencedCache[T] {
    final val zero = NoPeriod
    @inline final def sequenceId = currentPeriod
  }

  abstract class ListOfTypesCache extends PeriodCache[List[Type]] {
    @inline final def isCacheValid = isValidForBaseClasses(cachedId)
  }
  abstract class ListOfSymbolsCache extends PeriodCache[List[Symbol]] {
    @inline final def isCacheValid = isValidForBaseClasses(cachedId)
  }
  abstract class BaseTypeSeqCache extends PeriodCache[BaseTypeSeq] {
    @inline final def isCacheValid = isValidForBaseClasses(cachedId)
  }
  abstract class TypeCache extends PeriodCache[Type] {
    @inline final def isCacheValid = isValid(cachedId)
  }
  abstract class TypeCacheForRunId extends SequencedCache[Type] {
    final val zero = NoRunId
    @inline final def sequenceId = currentRunId
    @inline final override def isCacheValid = false
  }
  object TypeCache {
    def apply(body: => Type): TypeCache = new TypeCache {
      @inline final def calculate() = body
    }
  }
}