Skip to content

Backend backport2 #124

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

Merged
merged 8 commits into from
May 7, 2014
Merged
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
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Compiler {
List(
List(new FrontEnd),
List(new LazyValsCreateCompanionObjects,
/* new Constructors, */
new TailRec), //force separataion between lazyVals and LVCreateCO
List(new PatternMatcher,
new LazyValTranformContext().transformer,
Expand All @@ -29,7 +30,7 @@ class Compiler {
new TypeTestsCasts,
new InterceptedMethods),
List(new Erasure),
List(new UncurryTreeTransform)
List(new UncurryTreeTransform, new CollectEntryPoints)
)

var runId = 1
Expand Down
20 changes: 19 additions & 1 deletion src/dotty/tools/dotc/config/JavaPlatform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ package config
import io.{AbstractFile,ClassPath,JavaClassPath,MergedClassPath,DeltaClassPath}
import ClassPath.{ JavaContext, DefaultJavaContext }
import core.Contexts._
import core.SymDenotations._, core.Symbols._, core.{SymbolLoader, ClassfileLoader}
import core.SymDenotations._, core.Symbols._, dotty.tools.dotc.core._
import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._
import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._

class JavaPlatform extends Platform {

Expand All @@ -17,6 +19,22 @@ class JavaPlatform extends Platform {
currentClassPath.get
}

// The given symbol is a method with the right name and signature to be a runnable java program.
def isJavaMainMethod(sym: SymDenotation)(implicit ctx: Context) = {
val dn = defn
(sym.name == nme.main) && (sym.info match {
case t@MethodType(_, dn.ArrayType(el) :: Nil) => el =:= defn.StringType && (t.resultType isRef defn.UnitClass)
case _ => false
})
}

// The given class has a main method.
def hasJavaMainMethod(sym: Symbol)(implicit ctx: Context): Boolean =
(sym.info member nme.main).hasAltWith {
case x: SymDenotation => isJavaMainMethod(x)
case _ => false
}

/** Update classpath with a substituted subentry */
def updateClassPath(subst: Map[ClassPath, ClassPath]) =
currentClassPath = Some(new DeltaClassPath(currentClassPath.get, subst))
Expand Down
23 changes: 23 additions & 0 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ class Definitions {

lazy val ScalaPredefModule = ctx.requiredModule("scala.Predef")
lazy val ScalaRuntimeModule = ctx.requiredModule("scala.runtime.ScalaRunTime")
lazy val BoxesRunTimeModule = ctx.requiredModule("scala.runtime.BoxesRunTime")
lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass
lazy val DottyPredefModule = ctx.requiredModule("dotty.DottyPredef")
lazy val NilModule = ctx.requiredModule("scala.collection.immutable.Nil")

Expand All @@ -168,6 +170,10 @@ class Definitions {
List(AnyClass.typeRef), EmptyScope)
lazy val SeqClass: ClassSymbol = ctx.requiredClass("scala.collection.Seq")
lazy val ArrayClass: ClassSymbol = ctx.requiredClass("scala.Array")
lazy val Array_apply = ctx.requiredMethod(ArrayClass, nme.apply)
lazy val Array_update = ctx.requiredMethod(ArrayClass, nme.update)
lazy val Array_length = ctx.requiredMethod(ArrayClass, nme.length)
lazy val Array_clone = ctx.requiredMethod(ArrayClass, nme.clone_)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it matters in Dotty, but in scalac these should be def-s, not vals. Why? Subsequent runs of the compiler might recompile Array (this happens if you navigate to its sources in Scala IDE, for example), which would result in new symbols for its members.

That's why I split out RunDefinitions in scalac, so we could have correctness and speed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Dotty definitions are part of context and I would say that in case discarding is required, the better approach would be to discard context itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed we should do the same thing. (Keep them as lazyvals but break them
out into a new class) It's planned by has not been done yet. - Martin

On Tue, May 6, 2014 at 4:11 PM, Jason Zaugg [email protected]:

In src/dotty/tools/dotc/core/Definitions.scala:

@@ -168,6 +170,10 @@ class Definitions {
List(AnyClass.typeRef), EmptyScope)
lazy val SeqClass: ClassSymbol = ctx.requiredClass("scala.collection.Seq")
lazy val ArrayClass: ClassSymbol = ctx.requiredClass("scala.Array")

  • lazy val Array_apply = ctx.requiredMethod(ArrayClass, nme.apply)
  • lazy val Array_update = ctx.requiredMethod(ArrayClass, nme.update)
  • lazy val Array_length = ctx.requiredMethod(ArrayClass, nme.length)
  • lazy val Array_clone = ctx.requiredMethod(ArrayClass, nme.clone_)

Not sure if it matters in Dotty, but in scalac these should be def-s, not
vals. Why? Subsequent runs of the compiler might recompile Array (this
happens if you navigate to its sources in Scala IDE, for example), which
would result in new symbols for its members.

That's why I split out RunDefinitions in scalac, so we could have
correctness and speed.


Reply to this email directly or view it on GitHubhttps://github.com//pull/124/files#r12325734
.

Martin Odersky

EPFL

JOIN US. REGISTER TODAY! http://www.scaladays.org/
Scala http://www.scaladays.org/
Days http://www.scaladays.org/
June 16th-18th, http://www.scaladays.org/
Berlin http://www.scaladays.org/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Martin, why do you need a new class for this? Isn't Definitions itself a class that can be discarded with context holding it.

lazy val uncheckedStableClass: ClassSymbol = ctx.requiredClass("scala.annotation.unchecked.uncheckedStable")

lazy val UnitClass = valueClassSymbol("scala.Unit", BoxedUnitClass, java.lang.Void.TYPE, UnitEnc)
Expand Down Expand Up @@ -211,8 +217,20 @@ class Definitions {

// fundamental classes
lazy val StringClass = ctx.requiredClass("java.lang.String")
lazy val StringModule = StringClass.moduleClass

lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final)
lazy val String_valueOf_Object = StringModule.info.member(nme.valueOf).suchThat(_.info.firstParamTypes match {
case List(pt) => pt isRef ObjectClass
case _ => false
}).symbol

// in scalac modified to have Any as parrent

lazy val SerializableClass = ctx.requiredClass("scala.Serializable")
lazy val JavaCloneableClass = ctx.requiredClass("java.lang.Cloneable")
lazy val StringBuilderClass = ctx.requiredClass("scala.collection.mutable.StringBuilder")
lazy val NullPointerExceptionClass = ctx.requiredClass(jnme.NPException)

lazy val StringAddClass = ctx.requiredClass("scala.runtime.StringAdd")

Expand All @@ -238,6 +256,11 @@ class Definitions {
lazy val ClassfileAnnotationClass = ctx.requiredClass("scala.annotation.ClassfileAnnotation")
lazy val StaticAnnotationClass = ctx.requiredClass("scala.annotation.StaticAnnotation")
lazy val TailrecAnnotationClass = ctx.requiredClass("scala.annotation.tailrec")
lazy val RemoteAnnot = ctx.requiredClass("scala.remote")
lazy val SerialVersionUIDAnnot = ctx.requiredClass("scala.SerialVersionUID")
lazy val TransientAnnot = ctx.requiredClass("scala.transient")
lazy val NativeAnnot = ctx.requiredClass("scala.native")
lazy val ScalaStrictFPAnnot = ctx.requiredClass("scala.annotation.strictfp")

// Annotation classes
lazy val AliasAnnot = ctx.requiredClass("dotty.annotation.internal.Alias")
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ object Types {
Set()
}

private def memberDenots(keepOnly: NameFilter, f: (Name, mutable.Buffer[SingleDenotation]) => Unit)(implicit ctx: Context): Seq[SingleDenotation] = {
def memberDenots(keepOnly: NameFilter, f: (Name, mutable.Buffer[SingleDenotation]) => Unit)(implicit ctx: Context): Seq[SingleDenotation] = {
val buf = mutable.ArrayBuffer[SingleDenotation]()
for (name <- memberNames(keepOnly)) f(name, buf)
buf
Expand Down
115 changes: 115 additions & 0 deletions src/dotty/tools/dotc/transform/CollectEntryPoints.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package dotty.tools.dotc.transform

import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import scala.collection.mutable.ListBuffer
import dotty.tools.dotc.core.{Scopes, Flags}
import dotty.tools.dotc.core.Symbols.NoSymbol
import scala.annotation.tailrec
import dotty.tools.dotc.core._
import Symbols._
import scala.Some
import dotty.tools.dotc.transform.TreeTransforms.{NXTransformations, TransformerInfo, TreeTransform, TreeTransformer}
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import scala.collection.mutable
import dotty.tools.dotc.core.Names.Name
import NameOps._
import Types._
import scala.collection.SortedSet
import Decorators._
import StdNames._
import dotty.tools.dotc.util.Positions.Position
import dotty.tools.dotc.config.JavaPlatform

class CollectEntryPoints extends TreeTransform {

/** perform context-dependant initialization */
override def init(implicit ctx: Context, info: TransformerInfo): Unit = {
entryPoints = collection.immutable.TreeSet.empty[Symbol](new SymbolOrdering())
assert(ctx.platform.isInstanceOf[JavaPlatform], "Java platform specific phase")
}

private var entryPoints: Set[Symbol] = _

def getEntryPoints = entryPoints.toList

override def name: String = "collectEntryPoints"
override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
if (tree.symbol.owner.isClass && isJavaEntryPoint(tree.symbol)) {
// collecting symbols for entry points here (as opposed to GenBCode where they are used)
// has the advantage of saving an additional pass over all ClassDefs.
entryPoints += tree.symbol
}
tree
}

def isJavaEntryPoint(sym: Symbol)(implicit ctx: Context): Boolean = {
def fail(msg: String, pos: Position = sym.pos) = {
ctx.warning(sym.name +
s" has a main method with parameter type Array[String], but ${sym.fullName} will not be a runnable program.\n Reason: $msg",
sourcePos(sym.pos)
// TODO: make this next claim true, if possible
// by generating valid main methods as static in module classes
// not sure what the jvm allows here
// + " You can still run the program by calling it as " + javaName(sym) + " instead."
)
false
}
def failNoForwarder(msg: String) = {
fail(s"$msg, which means no static forwarder can be generated.\n")
}
val possibles = if (sym.flags is Flags.Module) (sym.info nonPrivateMember nme.main).alternatives else Nil
val hasApproximate = possibles exists {
m =>
m.info match {
case MethodType(_, p :: Nil) =>
p.typeSymbol == defn.ArrayClass
case _ => false
}
}
def precise(implicit ctx: Context) = {
val companion = sym.companionClass //sym.asClass.linkedClassOfClass
val javaPlatform = ctx.platform.asInstanceOf[JavaPlatform]
if (javaPlatform.hasJavaMainMethod(companion))
failNoForwarder("companion contains its own main method")
else if (companion != NoSymbol && companion.info.member(nme.main) != NoSymbol)
// this is only because forwarders aren't smart enough yet
failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)")
else if (companion.flags is Flags.Trait)
failNoForwarder("companion is a trait")
// Now either succeeed, or issue some additional warnings for things which look like
// attempts to be java main methods.
else (possibles exists (x => javaPlatform.isJavaMainMethod(x.symbol))) || {
possibles exists {
m =>
m.symbol.info match {
case t: PolyType =>
fail("main methods cannot be generic.")
case t@MethodType(paramNames, paramTypes) =>
if (t.resultType :: paramTypes exists (_.typeSymbol.isAbstractType))
fail("main methods cannot refer to type parameters or abstract types.", m.symbol.pos)
else
javaPlatform.isJavaMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.pos)
case tp =>
fail(s"don't know what this is: $tp", m.symbol.pos)
}
}
}
}

// At this point it's a module with a main-looking method, so either succeed or warn that it isn't.
hasApproximate && precise(ctx.withPhase(ctx.erasurePhase))
// Before erasure so we can identify generic mains.


}

}

class SymbolOrdering(implicit ctx: Context) extends Ordering[Symbol] {
override def compare(x: Symbol, y: Symbol): Int = {
x.fullName.toString.compareTo(y.fullName.toString)
}
}
27 changes: 27 additions & 0 deletions src/dotty/tools/dotc/transform/Constructors.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dotty.tools.dotc.transform

import TreeTransforms._
import dotty.tools.dotc.ast.tpd._
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.StdNames._

/** This transform moves initializers from body to constructor.
* Right now it's a dummy.
* Awaiting for real implemetation
*/
class Constructors extends TreeTransform {

override def name: String = "constructors"
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
if(tree.symbol.isClassConstructor) {
val claz = tree.symbol.enclosingClass.asClass
val zuper = claz.info.parents.head.typeSymbol
cpy.DefDef(tree, tree.mods, tree.name, tree.tparams, tree.vparamss, tree.tpt, rhs = {
val parentCall = Apply(Select(Super(This(claz), tpnme.EMPTY, true), zuper.primaryConstructor), Nil)
if(tree.rhs.isEmpty) parentCall
else Block(List(parentCall), tree.rhs)

})
} else tree
}
}
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ object Erasure {
else recur(cast(qual, erasedPre))

def recur(qual: Tree): Tree = {
val qualIsPrimitive = isPrimitiveValueType(qual.tpe)
val qualIsPrimitive = isPrimitiveValueType(qual.tpe.widen)
val symIsPrimitive = sym.owner.isPrimitiveValueClass
if ((sym.owner eq defn.AnyClass) || (sym.owner eq defn.AnyValClass))
select(qual, defn.ObjectClass.info.decl(sym.name).symbol)
Expand Down
25 changes: 15 additions & 10 deletions src/dotty/tools/dotc/transform/LazyVals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class LazyValTranformContext {

def transformer = new LazyValsTransform

val containerFlags = Flags.Synthetic | Flags.Mutable

/** this map contains mutable state of transformation: OffsetDefs to be appended to companion object definitions,
* and number of bits currently used */
class OffsetInfo(var defs: List[Tree], var ord:Int)
Expand Down Expand Up @@ -140,9 +142,12 @@ class LazyValTranformContext {

val holderImpl = ctx.requiredClass("dotty.runtime." + holderType)

val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, Flags.Synthetic, holderImpl.typeRef, coord = x.symbol.coord)
val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.symbol.coord)
val holderTree = ValDef(holderSymbol, New(holderImpl.typeRef, List(valueInitter)))
val methodTree = DefDef(x.symbol.asTerm, Select(Ident(holderSymbol.termRef), "value".toTermName))
val methodBody =
if(holderType != "LazyRef") Select(Ident(holderSymbol.termRef), "value".toTermName)
else TypeApply(Select(Select(Ident(holderSymbol.termRef), "value".toTermName), defn.Any_asInstanceOf), List(TypeTree(tpe)))
val methodTree = DefDef(x.symbol.asTerm, methodBody)
ctx.debuglog(s"found a lazy val ${x.show},\n rewrote with ${holderTree.show}")
Thicket(holderTree, methodTree)
}
Expand Down Expand Up @@ -201,7 +206,7 @@ class LazyValTranformContext {
val tpe = x.tpe.widen
assert(!(mods is Flags.Mutable))
val containerName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL).toTermName
val containerSymbol = ctx.newSymbol(claz, containerName, (mods &~ Flags.Lazy & Flags.Synthetic).flags, tpe, coord = x.symbol.coord)
val containerSymbol = ctx.newSymbol(claz, containerName, (mods &~ Flags.Lazy | containerFlags).flags, tpe, coord = x.symbol.coord)
addSym(claz, containerSymbol)

val containerTree = ValDef(containerSymbol, Literal(initValue(tpe)))
Expand All @@ -211,7 +216,7 @@ class LazyValTranformContext {
}
else {
val flagName = ctx.freshName(name.toString + StdNames.nme.BITMAP_PREFIX).toTermName
val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, Flags.Synthetic, defn.BooleanType)
val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags, defn.BooleanType)
val flag = ValDef(flagSymbol, Literal(Constants.Constant(false)))
val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(containerSymbol, flagSymbol, rhs))
Thicket(List(containerTree, flag, slowPath))
Expand Down Expand Up @@ -256,15 +261,15 @@ class LazyValTranformContext {
val computeState = Literal(Constants.Constant(1))
val notifyState = Literal(Constants.Constant(2))
val computedState = Literal(Constants.Constant(3))
val flagSymbol = ctx.newSymbol(methodSymbol, "flag".toTermName, Flags.Mutable & Flags.Synthetic, defn.LongType)
val flagSymbol = ctx.newSymbol(methodSymbol, "flag".toTermName, containerFlags, defn.LongType)
val flagDef = ValDef(flagSymbol, Literal(Constant(0L)))

val thiz = This(claz)(ctx.fresh.setOwner(claz))

val resultSymbol = ctx.newSymbol(methodSymbol, "result".toTermName, Flags.Mutable & Flags.Synthetic, tp)
val resultSymbol = ctx.newSymbol(methodSymbol, "result".toTermName, containerFlags, tp)
val resultDef = ValDef(resultSymbol, Literal(initValue(tp.widen)))

val retrySymbol = ctx.newSymbol(methodSymbol, "retry".toTermName, Flags.Mutable & Flags.Synthetic, defn.BooleanType)
val retrySymbol = ctx.newSymbol(methodSymbol, "retry".toTermName, containerFlags, defn.BooleanType)
val retryDef = ValDef(retrySymbol, Literal(Constants.Constant(true)))

val whileCond = Ident(retrySymbol.termRef)
Expand Down Expand Up @@ -345,7 +350,7 @@ class LazyValTranformContext {
} else { // need to create a new flag
offsetSymbol = ctx.newSymbol(companion.moduleClass, (StdNames.nme.LAZY_FIELD_OFFSET + id.toString).toTermName, Flags.Synthetic, defn.LongType).entered
val flagName = (StdNames.nme.BITMAP_PREFIX + id.toString).toTermName
val flagSymbol = ctx.newSymbol(claz, flagName, Flags.Synthetic, defn.LongType)
val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType)
addSym(claz, flagSymbol)
flag = ValDef(flagSymbol, Literal(Constants.Constant(0L)))
val offsetTree = ValDef(offsetSymbol, Apply(getOffset, List(thiz, Literal(Constant(flagName.toString)))))
Expand All @@ -355,15 +360,15 @@ class LazyValTranformContext {
case None =>
offsetSymbol = ctx.newSymbol(companion.moduleClass, (StdNames.nme.LAZY_FIELD_OFFSET + "0").toTermName, Flags.Synthetic, defn.LongType).entered
val flagName = (StdNames.nme.BITMAP_PREFIX + "0").toTermName
val flagSymbol = ctx.newSymbol(claz, flagName, Flags.Synthetic, defn.LongType)
val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType)
addSym(claz, flagSymbol)
flag = ValDef(flagSymbol, Literal(Constants.Constant(0L)))
val offsetTree = ValDef(offsetSymbol, Apply(getOffset, List(thiz, Literal(Constant(flagName.toString)))))
appendOffsetDefs += (companion.name.moduleClassName -> new OffsetInfo(List(offsetTree), ord))
}

val containerName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL).toTermName
val containerSymbol = ctx.newSymbol(claz, containerName, (mods &~ Flags.Lazy & Flags.Synthetic).flags, tpe, coord = x.symbol.coord)
val containerSymbol = ctx.newSymbol(claz, containerName, (mods &~ Flags.Lazy | containerFlags).flags, tpe, coord = x.symbol.coord)
addSym(claz, containerSymbol)
val containerTree = ValDef(containerSymbol, Literal(initValue(tpe)))

Expand Down
Loading