aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/core/Periods.scala
blob: c2779b4f73a961e51105f480eb8e335a784abf0a (plain) (tree)

































































































                                                                                     



                                                                      
 
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 = phaseIdOf(period)

  /** The current run identifier */
  def runId = runIdOf(period)

  /** 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)(implicit ctx: Context) =
    op(ctx withPeriod pd)

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

object Periods {

  /** 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.
   *  Periods are coded (in big endian) as:
   *
   *     sign, always 0        1 bit
   *     runid                21 bits
   *     phase id:             5 bits
   *     unused:               5 bits
   */
  type Period = Int
  final val NoPeriod = 0

  /** 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
   */
  type Interval = Int
  final val Nowhere = NoPeriod

  /** 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

  /** The run identifier of the given period. */
  final def runIdOf(period: Period): RunId = period >>> (PhaseWidth * 2)

  /** The phase identifier of the given period. */
  final def phaseIdOf(period: Period): PhaseId = (period >>> PhaseWidth) & PhaseMask

  /** The last phase of the given interval */
  final def lastPhaseIdOf(ivl: Interval) = phaseIdOf(ivl)

  /** The first phase of the given interval */
  final def firstPhaseIdOf(ivl: Interval) = lastPhaseIdOf(ivl) - (ivl & PhaseMask)

  /** Does given interval contain given period */
  final def containsPeriod(ivl: Interval, period: Period): Boolean =
    ((ivl - period) >>> PhaseWidth) <= (ivl & PhaseMask)

  final def intervalsOverlap(ivl1: Interval, ivl2: Interval): Boolean = ???

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

  /** The interval consisting of given run id, and lo/hi phase ids */
  final def intervalOf(rid: RunId, loPid: PhaseId, hiPid: PhaseId): Interval =
    periodOf(rid, hiPid) | (hiPid - loPid)

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

}