summaryrefslogtreecommitdiff
path: root/src/compiler/scala/reflect/internal/SymbolTable.scala
blob: 68bf0082d24a59a83d59e385d00298ba62017b70 (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* NSC -- new scala compiler
 * Copyright 2005-2011 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala.reflect
package internal

import scala.collection.{ mutable, immutable }
import util._

abstract class SymbolTable extends api.Universe
                              with Names
                              with Symbols
                              with Types
                              with Scopes
                              with Definitions
                              with Constants
                              with BaseTypeSeqs
                              with InfoTransformers
                              with StdNames
                              with AnnotationInfos
                              with AnnotationCheckers
                              with Trees
                              with TreePrinters
                              with Positions
                              with TypeDebugging
                              with Required
{
  def rootLoader: LazyType
  def log(msg: => AnyRef): Unit
  def abort(msg: String): Nothing = throw new Error(msg)
  def abort(): Nothing = throw new Error()

  /** Are we compiling for Java SE? */
  // def forJVM: Boolean

  /** Are we compiling for .NET? */
  def forMSIL: Boolean = false

  /** A period is an ordinal number for a phase in a run.
   *  Phases in later runs have higher periods than phases in earlier runs.
   *  Later phases have higher periods than earlier phases in the same run.
   */
  type Period = Int
  final val NoPeriod = 0

  /** An ordinal number for compiler runs. First run has number 1. */
  type RunId = Int
  final val NoRunId = 0

  private var ph: Phase = NoPhase
  private var per = NoPeriod

  final def phase: Phase = ph

  final def phase_=(p: Phase) {
    //System.out.println("setting phase to " + p)
    assert((p ne null) && p != NoPhase)
    ph = p
    per = (currentRunId << 8) + p.id
  }

  /** The current compiler run identifier. */
  def currentRunId: RunId

  /** The run identifier of the given period. */
  final def runId(period: Period): RunId = period >> 8

  /** The phase identifier of the given period. */
  final def phaseId(period: Period): Phase#Id = period & 0xFF

  /** The period at the start of run that includes `period`. */
  final def startRun(period: Period): Period = period & 0xFFFFFF00

  /** The current period. */
  final def currentPeriod: Period = {
    //assert(per == (currentRunId << 8) + phase.id)
    per
  }

  /** The phase associated with given period. */
  final def phaseOf(period: Period): Phase = phaseWithId(phaseId(period))

  final def period(rid: RunId, pid: Phase#Id): Period =
    (currentRunId << 8) + pid

  /** Perform given operation at given phase. */
  final def atPhase[T](ph: Phase)(op: => T): T = {
    val current = phase
    phase = ph
    try op
    finally phase = current
  }
  final def afterPhase[T](ph: Phase)(op: => T): T =
    atPhase(ph.next)(op)

  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)
    }
  }

  object perRunCaches {
    import java.lang.ref.WeakReference

    // We can allow ourselves a structural type, these methods
    // amount to a few calls per run at most.  This does suggest
    // a "Clearable" trait may be useful.
    private type Clearable = {
      def size: Int
      def clear(): Unit
    }
    // Weak references so the garbage collector will take care of
    // letting us know when a cache is really out of commission.
    private val caches = mutable.HashSet[WeakReference[Clearable]]()

    def clearAll() = {
      if (settings.debug.value) {
        val size = caches flatMap (ref => Option(ref.get)) map (_.size) sum;
        log("Clearing " + caches.size + " caches totalling " + size + " entries.")
      }
      caches foreach { ref =>
        val cache = ref.get()
        if (cache == null)
          caches -= ref
        else
          cache.clear()
      }
    }

    def newMap[K, V]() = { val m = mutable.HashMap[K, V]() ; caches += new WeakReference(m) ; m }
    def newSet[K]()    = { val s = mutable.HashSet[K]() ; caches += new WeakReference(s) ; s }
  }

  /** Break into repl debugger if assertion is true. */
  // def breakIf(assertion: => Boolean, args: Any*): Unit =
  //   if (assertion)
  //     ILoop.break(args.toList)

  /** The set of all installed infotransformers. */
  var infoTransformers = new InfoTransformer {
    val pid = NoPhase.id
    val changesBaseClasses = true
    def transform(sym: Symbol, tpe: Type): Type = tpe
  }

  /** The phase which has given index as identifier. */
  val phaseWithId: Array[Phase]
}