aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Periods.scala
blob: ed7156d7bfb0062f08006833110db8be0a7a6e4e (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
package dotty.tools.dotc.core

import Contexts._

/** Periods are the central "clock" of the compiler.
 *  A period consists of a run id and a phase id.
 *  run ids represent compiler runs
 *  phase ids represent compiler phases
 */
abstract class Periods { self: Context =>
  import Periods._

  /** The current phase identifier */
  def phaseId = period.phaseId

  /** The current run identifier */
  def runId = period.runId

  /** A new context that differs from the current one in its period */
  def withPeriod(pd: Period): Context =
    if (period == pd) this
    else new SubContext(self) {
      override val period = pd
    }

  /** Execute `op` at given period */
  def atPeriod[T](pd: Period)(op: Context => T) =
    op(ctx withPeriod pd)

  /** Execute `op` at given phase id */
  def atPhase[T](pid: PhaseId)(op: Context => T) =
    op(ctx withPeriod Period(runId, pid))
}

object Periods {

  /** A period is represented by 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.
   *  Periods are coded (in big endian) as:
   *
   *     sign, always 0        1 bit
   *     runid                21 bits
   *     phase id:             5 bits
   *     unused:               5 bits
   *
   *  A period interval is an interval between two periods that share the same runid.
   *  It is coded as follows:
   *
   *     sign, always 0        1 bit
   *     runid                21 bits
   *     last phase id:        5 bits
   *     #phases before last:  5 bits
   */
  class Period(val code: Int) extends AnyVal {

    /** The run identifier of this period. */
    def runId: Int = code >>> (PhaseWidth * 2)

    /** The phase identifier of this single-phase period. */
    def phaseId: Int = {
      assert((code & PhaseMask) == 0)
      (code >>> PhaseWidth) & PhaseMask
    }

    /** The last phase of this period */
    def lastPhaseId: Int =
      (code >>> PhaseWidth) & PhaseMask

    /** The first phase of this period */
    def firstPhaseId = lastPhaseId - (code & PhaseMask)

    /** Does this period contain given period?
     *  this = A .. B
     */
    def contains(that: Period): Boolean = {
      val lastDiff = (code - that.code) >>> PhaseWidth
      lastDiff + (that.code & PhaseMask ) <= (this.code & PhaseMask)
    }

    /** Does this period overlpa with given period? */
    def overlaps(that: Period): Boolean =
      this.runId == that.runId &&
      this.firstPhaseId <= that.lastPhaseId &&
      that.firstPhaseId <= this.lastPhaseId

    def & (that: Period): Period =
      if (this overlaps that)
        Period(
          this.runId,
          this.firstPhaseId max that.firstPhaseId,
          this.lastPhaseId min that.lastPhaseId)
      else
        Nowhere
  }

  object Period {

    /** The single-phase period consisting of given run id and phase id */
    def apply(rid: RunId, pid: PhaseId): Period =
      new Period(((rid << PhaseWidth) | pid) << PhaseWidth)

    /** The period consisting of given run id, and lo/hi phase ids */
    def apply(rid: RunId, loPid: PhaseId, hiPid: PhaseId): Period =
      new Period(((rid << PhaseWidth) | hiPid) << PhaseWidth | (hiPid - loPid))

    /** The interval consisting of all periods of given run id */
    def allInRun(rid: RunId) =
      apply(rid, 0, PhaseMask)

  }

  final val Nowhere = new Period(0)

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

  /** An ordinal number for phases. First phase has number 1. */
  type PhaseId = Int
  final val NoPhaseId = 0
  final val FirstPhaseId = 1

  /** The number of bits needed to encode a phase identifier. */
  final val PhaseWidth = 5
  final val PhaseMask = (1 << PhaseWidth) - 1

}