Skip to content

Allow MiniPhase to be DenotTransformer & LazyVals #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/dotty/runtime/LazyHolders.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package dotty.runtime

/**
* Classes used as holders for local lazy vals
*/
class LazyInt(init : =>Int) {
lazy val value = init
}

class LazyLong(init : =>Long) {
lazy val value = init
}

class LazyBoolean(init : =>Boolean) {
lazy val value = init
}

class LazyDouble(init : =>Double) {
lazy val value = init
}

class LazyFloat(init : =>Float) {
lazy val value = init
}

class LazyByte(init : =>Byte) {
lazy val value = init
}

class LazyRef(init : =>AnyRef) {
lazy val value = init
}

class LazyShort(init : =>Short) {
lazy val value = init
}

class LazyChar(init : =>Char) {
lazy val value = init
}



69 changes: 69 additions & 0 deletions src/dotty/runtime/LazyVals.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package dotty.runtime

import scala.annotation.tailrec

/**
* Helper methods used in thread-safe lazy vals.
*/
object LazyVals {
private val unsafe = scala.concurrent.util.Unsafe.instance

final val BITS_PER_LAZY_VAL = 2
final val LAZY_VAL_MASK = 3

@inline def STATE(cur: Long, ord: Long) = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK
@inline def CAS(t: Object, offset: Long, e: Long, v: Long, ord: Int) = {
val mask = ~(LAZY_VAL_MASK << ord * BITS_PER_LAZY_VAL)
val n = (e & mask) | (v << (ord * BITS_PER_LAZY_VAL))
compareAndSet(t, offset, e, n)
}
@inline def setFlag(t: Object, offset: Long, v: Int, ord: Int) = {
var retry = true
while (retry) {
val cur = get(t, offset)
if (STATE(cur, ord) == 1) retry = CAS(t, offset, cur, v, ord)
else {
// cur == 2, somebody is waiting on monitor
if (CAS(t, offset, cur, v, ord)) {
val monitor = getMonitor(t, ord)
monitor.synchronized {
monitor.notifyAll()
}
retry = false
}
}
}
}
@inline def wait4Notification(t: Object, offset: Long, cur: Long, ord: Int) = {
var retry = true
while (retry) {
val cur = get(t, offset)
val state = STATE(cur, ord)
if (state == 1) CAS(t, offset, cur, 2, ord)
else if (state == 2) {
val monitor = getMonitor(t, ord)
monitor.synchronized {
monitor.wait()
}
}
else retry = false
}
}

@inline def compareAndSet(t: Object, off: Long, e: Long, v: Long) = unsafe.compareAndSwapLong(t, off, e, v)
@inline def get(t: Object, off: Long) = unsafe.getLongVolatile(t, off)

val processors = java.lang.Runtime.getRuntime.availableProcessors()
val base = 8 * processors * processors
val monitors = (0 to base).map {
x => new Object()
}.toArray

@inline def getMonitor(obj: Object, fieldId: Int = 0) = {
var id = (java.lang.System.identityHashCode(obj) + fieldId) % base
if (id < 0) id += base
monitors(id)
}

@inline def getOffset(obj: Object, name: String) = unsafe.objectFieldOffset(obj.getClass.getDeclaredField(name))
}
13 changes: 11 additions & 2 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,22 @@ import Symbols._
import typer.{FrontEnd, Typer, Mode, ImportInfo}
import reporting.ConsoleReporter
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.transform.{LazyValsCreateCompanionObjects, LazyValTranformContext}
import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
import dotty.tools.dotc.core.Denotations.SingleDenotation

class Compiler {

def phases: List[Phase] = List(new FrontEnd)
def phases: List[Phase] = List(new FrontEnd, new LazyValsCreateCompanionObjects,
new Separator, //force separataion between lazyVals and LVCreateCO
new LazyValTranformContext().transformer, new UncurryTreeTransform)

var runId = 1
def nextRunId = { runId += 1; runId }
def nextRunId = {
runId += 1; runId
}

def rootContext(implicit ctx: Context): Context = {
ctx.definitions.init(ctx)
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Run(comp: Compiler)(implicit ctx: Context) {
def compileSources(sources: List[SourceFile]) = Stats.monitorHeartBeat {
if (sources forall (_.exists)) {
units = sources map (new CompilationUnit(_))
for (phase <- ctx.allPhases) {
for (phase <- ctx.allPhases.init) {
if (!ctx.reporter.hasErrors)
phase.runOn(units)
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ object Trees {
}
}

abstract class TreeTransformer(val cpy: TreeCopier = inst.cpy) {
abstract class TreeMap(val cpy: TreeCopier = inst.cpy) {

def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
case Ident(name) =>
Expand Down
8 changes: 4 additions & 4 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
new DeepFolder(op).apply(z, tree)

def subst(from: List[Symbol], to: List[Symbol])(implicit ctx: Context): ThisTree =
new TreeMapper(typeMap = new ctx.SubstSymMap(from, to)).apply(tree)
new TreeTypeMap(typeMap = new ctx.SubstSymMap(from, to)).apply(tree)

def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree =
new TreeMapper(ownerMap = (sym => if (sym == from) to else sym)).apply(tree)
new TreeTypeMap(ownerMap = (sym => if (sym == from) to else sym)).apply(tree)

def appliedToTypes(targs: List[Type])(implicit ctx: Context): Tree =
if (targs.isEmpty) tree else TypeApply(tree, targs map (TypeTree(_)))
Expand All @@ -344,7 +344,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def tpes: List[Type] = xs map (_.tpe)
}

class TreeMapper(val typeMap: TypeMap = IdentityTypeMap, val ownerMap: Symbol => Symbol = identity _)(implicit ctx: Context) extends TreeTransformer {
class TreeTypeMap(val typeMap: TypeMap = IdentityTypeMap, val ownerMap: Symbol => Symbol = identity _)(implicit ctx: Context) extends TreeMap {
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = super.transform {
tree.withType(typeMap(tree.tpe)) match {
case bind: tpd.Bind =>
Expand Down Expand Up @@ -375,7 +375,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {

/** The current tree map composed with a substitution [from -> to] */
def withSubstitution(from: List[Symbol], to: List[Symbol]) =
new TreeMapper(
new TreeTypeMap(
typeMap andThen ((tp: Type) => tp.substSym(from, to)),
ownerMap andThen (from zip to).toMap)
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] {
}
}

abstract class UntypedTreeTransformer(cpy: UntypedTreeCopier = untpd.cpy) extends TreeTransformer(cpy) {
abstract class UntypedTreeMap(cpy: UntypedTreeCopier = untpd.cpy) extends TreeMap(cpy) {
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
case ModuleDef(mods, name, impl) =>
cpy.ModuleDef(tree, mods, name, transformSub(impl))
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ object Printers {
val completions = noPrinter
val gadts = noPrinter
val incremental = noPrinter

val config = noPrinter
}
12 changes: 10 additions & 2 deletions src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import collection.immutable.BitSet
import printing._
import config.{Settings, ScalaSettings, Platform, JavaPlatform}
import language.implicitConversions

import DenotTransformers.DenotTransformer
object Contexts {

/** A context is passed basically everywhere in dotc.
Expand Down Expand Up @@ -325,6 +325,7 @@ object Contexts {
def withProperty(prop: (String, Any)): this.type = withMoreProperties(moreProperties + prop)

def withPhase(pid: PhaseId): this.type = withPeriod(Period(runId, pid))
def withPhase(phase: Phase): this.type = withPhase(phase.id)

def withSetting[T](setting: Setting[T], value: T): this.type =
withSettings(setting.updateIn(sstate, value))
Expand Down Expand Up @@ -361,7 +362,6 @@ object Contexts {
* compiler run.
*/
class ContextBase extends ContextState
with Transformers.TransformerBase
with Denotations.DenotationsBase
with Phases.PhasesBase {

Expand Down Expand Up @@ -460,6 +460,14 @@ object Contexts {
/** Phases by id */
private[core] var phases: Array[Phase] = _

/** Phases with consecutive Transforms groupped into a single phase */
private [core] var squashedPhases: Array[Phase] = _

/** Next denotation transformer id */
private[core] var nextDenotTransformerId: Array[Int] = _

private[core] var denotTransformers: Array[DenotTransformer] = _

// Printers state
/** Number of recursive invocations of a show method on cuyrrent stack */
private[dotc] var toTextRecursions = 0
Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ class Definitions {
lazy val AnnotationDefaultAnnot = ctx.requiredClass("dotty.annotation.internal.AnnotationDefault")
lazy val ThrowsAnnot = ctx.requiredClass("scala.throws")
lazy val UncheckedAnnot = ctx.requiredClass("scala.unchecked")
lazy val VolatileAnnot = ctx.requiredClass("scala.volatile")

// convenient one-parameter method types
def methOfAny(tp: Type) = MethodType(List(AnyType), tp)
Expand Down Expand Up @@ -266,6 +267,7 @@ class Definitions {
def JavaRepeatedParamType = JavaRepeatedParamClass.typeRef
def ThrowableType = ThrowableClass.typeRef
def OptionType = OptionClass.typeRef
def VolatileAnnotType = VolatileAnnot.typeRef

def ClassType(arg: Type)(implicit ctx: Context) = {
val ctype = ClassClass.typeRef
Expand Down
33 changes: 33 additions & 0 deletions src/dotty/tools/dotc/core/DenotTransformers.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package dotty.tools.dotc
package core

import Periods._
import SymDenotations._
import Contexts._
import Types._
import Denotations._
import Phases._
import java.lang.AssertionError
import dotty.tools.dotc.util.DotClass

object DenotTransformers {

/** A transformer group contains a sequence of transformers,
* ordered by the phase where they apply. Transformers are added
* to a group via `install`.
*/

/** A transformer transforms denotations at a given phase */
trait DenotTransformer extends Phase {

/** The last phase during which the transformed denotations are valid */
def lastPhaseId(implicit ctx: Context) = ctx.nextDenotTransformerId(id + 1)

/** The validity period of the transformer in the given context */
def validFor(implicit ctx: Context): Period =
Period(ctx.runId, id, lastPhaseId)

/** The transformation method */
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation
}
}
28 changes: 20 additions & 8 deletions src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Symbols._
import Types._
import Periods._
import Flags._
import Transformers._
import DenotTransformers._
import Decorators._
import transform.Erasure
import printing.Texts._
Expand Down Expand Up @@ -192,6 +192,9 @@ object Denotations {
def requiredValue(name: PreName)(implicit ctx: Context): TermSymbol =
info.member(name.toTermName).requiredSymbol(_.info.isParameterless).asTerm

def requiredClass(name: PreName)(implicit ctx: Context): ClassSymbol =
info.member(name.toTypeName).requiredSymbol(_.isClass).asClass

/** The denotation that has a type matching `targetType` when seen
* as a member of type `site`, `NoDenotation` if none exists.
*/
Expand Down Expand Up @@ -387,7 +390,6 @@ object Denotations {
if ((symbol eq this.symbol) && (info eq this.info)) this
else newLikeThis(symbol, info)


def orElse(that: => SingleDenotation) = if (this.exists) this else that

def altsWith(p: Symbol => Boolean): List[SingleDenotation] =
Expand Down Expand Up @@ -499,6 +501,8 @@ object Denotations {
def current(implicit ctx: Context): SingleDenotation = {
val currentPeriod = ctx.period
val valid = myValidFor
assert(valid.code > 0, s"negative period $valid: ${valid.code}")

if (valid.runId != currentPeriod.runId) bringForward.current
else {
var cur = this
Expand All @@ -512,36 +516,44 @@ object Denotations {
if (next.validFor.code > valid.code) {
// in this case, next.validFor contains currentPeriod
cur = next
cur
} else {
// not found, cur points to highest existing variant
var startPid = cur.validFor.lastPhaseId + 1
val transformers = ctx.transformersFor(cur)
val transformer = transformers.nextTransformer(startPid)
next = transformer.transform(cur).syncWithParents
val nextTranformerId = ctx.nextDenotTransformerId(startPid)
val transformer = ctx.denotTransformers(nextTranformerId)
//println(s"transforming with $transformer")
if (currentPeriod.lastPhaseId > transformer.id)
next = transformer.transform(cur).syncWithParents
if (next eq cur)
startPid = cur.validFor.firstPhaseId
else {
next match {
case next: ClassDenotation => next.resetFlag(Frozen)
case _ =>
}
next.nextInRun = cur.nextInRun
cur.nextInRun = next
cur = next
}
cur.validFor = Period(
currentPeriod.runId, startPid, transformer.lastPhaseId)
//println(s"new denot: $cur, valid for ${cur.validFor}")
cur.current // multiple transformations could be required
}
} else {
// currentPeriod < valid; in this case a version must exist
// currentPeriod < end of valid; in this case a version must exist
// but to be defensive we check for infinite loop anyway
var cnt = 0
while (!(cur.validFor contains currentPeriod)) {
//println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
cur = cur.nextInRun
cnt += 1
assert(cnt <= MaxPossiblePhaseId, "seems to be a loop in Denotations")
assert(cnt <= MaxPossiblePhaseId, s"seems to be a loop in Denotations for $this, currentPeriod = $currentPeriod")
}
cur
}
cur

}
}

Expand Down
Loading