aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Petrashko <dmitry.petrashko@gmail.com>2014-11-25 15:51:55 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-12-16 13:14:59 +0100
commit7d470b3e8c09fffd8a5c42e2aa8b22479e087a3a (patch)
treea6827e22c6b2b4faf2ff205ed8f4120d20cc7b11
parent981a21816e4cb10b8fbe4edcf0659fb3995d63f8 (diff)
downloaddotty-7d470b3e8c09fffd8a5c42e2aa8b22479e087a3a.tar.gz
dotty-7d470b3e8c09fffd8a5c42e2aa8b22479e087a3a.tar.bz2
dotty-7d470b3e8c09fffd8a5c42e2aa8b22479e087a3a.zip
Sharing backend between scalac and dotty.
Due to a lot of error and workarounds required for backend not regress in terms of speed, I guess the original idea was to high to be reached.. Nevertheless it was good to try.
-rw-r--r--src/dotty/tools/backend/jvm/DottyBackendInterface.scala546
-rw-r--r--src/dotty/tools/backend/jvm/GenBCode.scala381
-rwxr-xr-xsrc/dotty/tools/backend/jvm/scalaPrimitives.scala399
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/core/Names.scala2
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala3
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala3
7 files changed, 1334 insertions, 2 deletions
diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
new file mode 100644
index 000000000..f1e685a0d
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -0,0 +1,546 @@
+package dotty.tools.backend.jvm
+
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc
+import dotty.tools.dotc.backend.jvm.DottyPrimitives
+import dotty.tools.dotc.transform.Erasure
+
+import scala.collection.generic.Clearable
+import scala.collection.mutable
+import scala.reflect.ClassTag
+import scala.reflect.internal.util.WeakHashSet
+import scala.reflect.io.AbstractFile
+import scala.tools.asm.{ClassVisitor, FieldVisitor, MethodVisitor}
+import scala.tools.nsc.backend.jvm.{BCodeHelpers, BackendInterface}
+import dotty.tools.dotc.core._
+import Periods._
+import SymDenotations._
+import Contexts._
+import Types._
+import Symbols._
+import Denotations._
+import Phases._
+import java.lang.AssertionError
+import dotty.tools.dotc.util.{Positions, DotClass}
+import Decorators._
+import tpd._
+import StdNames.nme
+
+abstract class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
+ trait NonExistentTree extends tpd.Tree
+ type Symbol = Symbols.Symbol
+ type Type = Types.Type
+ type Tree = tpd.Tree
+ type CompilationUnit = dotc.CompilationUnit
+ type Constant = Constants.Constant
+ type Literal = tpd.Literal
+ type Position = Positions.Position
+ type Name = Names.Name
+ type ClassDef = tpd.TypeDef
+ type TypeDef = tpd.TypeDef
+ type Apply = tpd.Apply
+ type TypeApply = tpd.TypeApply
+ type Try = tpd.Try
+ type Assign = tpd.Assign
+ type Ident = tpd.Ident
+ type If = tpd.If
+ type ValDef = tpd.ValDef
+ type Throw = tpd.Throw
+ type Return = tpd.Return
+ type Block = tpd.Block
+ type Typed = tpd.Typed
+ type Match = tpd.Match
+ type This = tpd.This
+ type CaseDef = tpd.CaseDef
+ type Alternative = tpd.Alternative
+ type DefDef = tpd.DefDef
+ type Template = tpd.Template
+ type Select = tpd.Select
+ type Bind = tpd.Bind
+ type New = tpd.New
+ type Super = tpd.Super
+ type Modifiers = tpd.Modifiers
+ type Annotation = NonExistentTree
+ type ArrayValue = NonExistentTree
+ type ApplyDynamic = NonExistentTree
+ type ModuleDef = NonExistentTree
+ type LabelDef = NonExistentTree
+
+
+ val NoSymbol = Symbols.NoSymbol
+ val NoPosition: Position = Positions.NoPosition
+ val EmptyTree: Tree = tpd.EmptyTree
+
+
+ val UnitTag: ConstantTag = Constants.UnitTag
+ val IntTag: ConstantTag = Constants.IntTag
+ val FloatTag: ConstantTag = Constants.FloatTag
+ val NullTag: ConstantTag = Constants.NullTag
+ val BooleanTag: ConstantTag = Constants.BooleanTag
+ val ByteTag: ConstantTag = Constants.ByteTag
+ val ShortTag: ConstantTag = Constants.ShortTag
+ val CharTag: ConstantTag = Constants.CharTag
+ val DoubleTag: ConstantTag = Constants.DoubleTag
+ val LongTag: ConstantTag = Constants.LongTag
+ val StringTag: ConstantTag = Constants.StringTag
+ val ClazzTag: ConstantTag = Constants.ClazzTag
+ val EnumTag: ConstantTag = Constants.EnumTag
+
+ val nme_This: Name = StdNames.nme.This
+ val nme_EMPTY_PACKAGE_NAME: Name = StdNames.nme.EMPTY_PACKAGE
+ val nme_CONSTRUCTOR: Name = StdNames.nme.CONSTRUCTOR
+ val nme_WILDCARD: Name = StdNames.nme.WILDCARD
+ val nme_THIS: Name = StdNames.nme.THIS
+ val nme_PACKAGE: Name = StdNames.nme.PACKAGE
+ val nme_EQEQ_LOCAL_VAR: Name = StdNames.nme.EQEQ_LOCAL_VAR
+
+ val BoxesRunTimeModule = ctx.requiredModule("scala.runtime.BoxesRunTime")
+ val BoxesRunTimeClass = toDenot(BoxesRunTimeModule).moduleClass.asClass
+
+ val nme_valueOf: Name = StdNames.nme.valueOf
+ val NothingClass: Symbol = defn.NothingClass
+ val NullClass: Symbol = defn.NullClass
+ val ObjectClass: Symbol = defn.ObjectClass
+ val Object_isInstanceOf: Symbol = defn.Any_isInstanceOf
+ val Object_asInstanceOf: Symbol = defn.Any_asInstanceOf
+ val Object_equals: Symbol = defn.Any_equals
+ val ArrayClass: Symbol = defn.ArrayClass
+ val UnitClass: Symbol = defn.UnitClass
+ val BooleanClass: Symbol = defn.BooleanClass
+ val CharClass: Symbol = defn.CharClass
+ val ShortClass: Symbol = defn.ShortClass
+ val ClassClass: Symbol = defn.ClassClass
+ val ByteClass: Symbol = defn.ByteClass
+ val IntClass: Symbol = defn.IntClass
+ val LongClass: Symbol = defn.LongClass
+ val FloatClass: Symbol = defn.FloatClass
+ val DoubleClass: Symbol = defn.DoubleClass
+ val Array_clone: Symbol = defn.Array_clone
+ val hashMethodSym: Symbol = ctx.requiredMethod(ScalaRunTimeModule.asClass, StdNames.nme.hash_)
+ val externalEqualsNumNum: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumNum)
+ val externalEqualsNumChar: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumChar)
+ val externalEqualsNumObject: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumObject)
+ val externalEquals: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equals_)
+ val MaxFunctionArity: Int = Definitions.MaxFunctionArity
+ val FunctionClass: Array[Symbol] = defn.FunctionClass.asInstanceOf[Array[Symbol]]
+ val AbstractFunctionClass: Array[Symbol] = defn.AbstractFunctionClass.asInstanceOf[Array[Symbol]]
+ val PartialFunctionClass: Symbol = defn.PartialFunctionClass
+ val AbstractPartialFunctionClass: Symbol = defn.AbstractPartialFunctionClass
+ val String_valueOf: Symbol = defn.String_valueOf_Object
+
+ def boxMethods: Map[Symbol, Symbol] = defn.ScalaBoxedClasses.map(x => (x, Erasure.Boxing.boxMethod(x.asClass))).toMap
+ def unboxMethods: Map[Symbol, Symbol] = defn.ScalaBoxedClasses.map(x => (x, Erasure.Boxing.unboxMethod(x.asClass))).toMap
+ def isBox(sym: Symbol): Boolean = Erasure.Boxing.isBox(sym)
+ def isUnbox(sym: Symbol): Boolean = Erasure.Boxing.isUnbox(sym)
+
+ val primitives: Primitives = new Primitives {
+ val primitives = new DottyPrimitives(ctx, genBcode)
+ def getPrimitive(methodSym: Symbol, reciever: Type): Int = primitives.getPrimitive(methodSym, reciever)
+
+ def getPrimitive(sym: Symbol): Int = primitives.getPrimitive(sym)
+
+ def isPrimitive(sym: Symbol): Boolean = primitives.isPrimitive(sym)
+ }
+ implicit val TypeDefTag: ClassTag[TypeDef] = ClassTag[TypeDef](classOf[TypeDef])
+ implicit val ApplyTag: ClassTag[Apply] = ClassTag[Apply](classOf[Apply])
+ implicit val SelectTag: ClassTag[Select] = ClassTag[Select](classOf[Select])
+ implicit val TypeApplyTag: ClassTag[TypeApply] = ClassTag[TypeApply](classOf[TypeApply])
+ implicit val ClassDefTag: ClassTag[ClassDef] = ClassTag[TypeDef](classOf[TypeDef])
+ implicit val TryTag: ClassTag[Try] = ClassTag[Try](classOf[Try])
+ implicit val AssignTag: ClassTag[Assign] = ClassTag[Assign](classOf[Assign])
+ implicit val IdentTag: ClassTag[Ident] = ClassTag[Ident](classOf[Ident])
+ implicit val IfTag: ClassTag[If] = ClassTag[If](classOf[If])
+ implicit val LabelDefTag: ClassTag[LabelDef] = ClassTag[LabelDef](classOf[LabelDef])
+ implicit val ValDefTag: ClassTag[ValDef] = ClassTag[ValDef](classOf[ValDef])
+ implicit val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw])
+ implicit val ReturnTag: ClassTag[Return] = ClassTag[Return](classOf[Return])
+ implicit val LiteralTag: ClassTag[Literal] = ClassTag[Literal](classOf[Literal])
+ implicit val BlockTag: ClassTag[Block] = ClassTag[Block](classOf[Block])
+ implicit val TypedTag: ClassTag[Typed] = ClassTag[Typed](classOf[Typed])
+ implicit val ArrayValueTag: ClassTag[ArrayValue] = ClassTag[ArrayValue](classOf[ArrayValue])
+ implicit val MatchTag: ClassTag[Match] = ClassTag[Match](classOf[Match])
+ implicit val CaseDefTag: ClassTag[CaseDef] = ClassTag[CaseDef](classOf[CaseDef])
+ implicit val ThisTag: ClassTag[This] = ClassTag[This](classOf[This])
+ implicit val AlternativeTag: ClassTag[Alternative] = ClassTag[Alternative](classOf[Alternative])
+ implicit val DefDefTag: ClassTag[DefDef] = ClassTag[DefDef](classOf[DefDef])
+ implicit val ModuleDefTag: ClassTag[ModuleDef] = ClassTag[ModuleDef](classOf[ModuleDef])
+ implicit val NameTag: ClassTag[Name] = ClassTag[Name](classOf[Name])
+ implicit val TemplateTag: ClassTag[Template] = ClassTag[Template](classOf[Template])
+ implicit val BindTag: ClassTag[Bind] = ClassTag[Bind](classOf[Bind])
+ implicit val NewTag: ClassTag[New] = ClassTag[New](classOf[New])
+ implicit val ApplyDynamicTag: ClassTag[ApplyDynamic] = ClassTag[ApplyDynamic](classOf[ApplyDynamic])
+ implicit val SuperTag: ClassTag[Super] = ClassTag[Super](classOf[Super])
+ implicit val ConstantClassTag: ClassTag[Constant] = ClassTag[Constant](classOf[Constant])
+
+ /* dont emit any annotations for now*/
+ def isRuntimeVisible(annot: Annotation): Boolean = false
+ def shouldEmitAnnotation(annot: Annotation): Boolean = false
+
+ def emitAnnotations(cw: ClassVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
+ def emitAnnotations(mw: MethodVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
+ def emitAnnotations(fw: FieldVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
+ def emitParamAnnotations(jmethod: MethodVisitor, pannotss: List[List[Annotation]], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
+ def getAnnotPickle(jclassName: String, sym: Symbol): Option[Annotation] = None
+
+
+ def getRequiredClass(fullname: String): Symbol = ctx.requiredClass(fullname.toTermName)
+
+ def getClassIfDefined(fullname: String): Symbol = NoSymbol // used only for android. todo: implement
+
+ private def erasureString(clazz: Class[_]): String = {
+ if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]"
+ else clazz.getName
+ }
+
+ def requiredClass[T](implicit evidence: ClassTag[T]): Symbol = {
+ ctx.requiredClass(erasureString(evidence.runtimeClass).toTermName)
+ }
+
+ def requiredModule[T](implicit evidence: ClassTag[T]): Symbol = {
+ ctx.requiredModule(erasureString(evidence.runtimeClass).toTermName)
+ }
+
+
+ def debuglog(msg: => String): Unit = ctx.debuglog(msg)
+ def informProgress(msg: String): Unit = ctx.informProgress(msg)
+ def log(msg: => String): Unit = ctx.log(msg)
+ def error(pos: Position, msg: String): Unit = ctx.error(msg, pos)
+ def warning(pos: Position, msg: String): Unit = ctx.warning(msg, pos)
+ def abort(msg: String): Nothing = {
+ ctx.error(msg)
+ ???
+ }
+
+ def emitAsmp: Option[String] = None
+
+ def dumpClasses: Option[String] =
+ if(ctx.settings.Ydumpclasses.isDefault) None
+ else Some(ctx.settings.Ydumpclasses.value)
+
+ def mainClass: Option[String] =
+ if (ctx.settings.mainClass.isDefault) None
+ else Some(ctx.settings.mainClass.value)
+ def setMainClass(name: String): Unit = ctx.settings.mainClass.update(name)
+
+
+ def noForwarders: Boolean = ctx.settings.noForwarders.value
+ def debuglevel: Int = 0
+ def settings_debug: Boolean = ctx.settings.debug.value
+ def targetPlatform: String = ctx.settings.target.value
+
+ val perRunCaches: Caches = new Caches {
+ def newAnyRefMap[K <: AnyRef, V](): mutable.AnyRefMap[K, V] = new mutable.AnyRefMap[K, V]()
+ def newWeakMap[K, V](): mutable.WeakHashMap[K, V] = new mutable.WeakHashMap[K, V]()
+ def recordCache[T <: Clearable](cache: T): T = cache
+ def newWeakSet[K <: AnyRef](): WeakHashSet[K] = new WeakHashSet[K]()
+ def newMap[K, V](): mutable.HashMap[K, V] = new mutable.HashMap[K, V]()
+ def newSet[K](): mutable.Set[K] = new mutable.HashSet[K]
+ }
+
+
+
+ val MODULE_INSTANCE_FIELD: String = nme.MODULE_INSTANCE_FIELD.toString
+
+ def internalNameString(offset: Int, length: Int): String = new String(Names.chrs, offset, length)
+
+ def newTermName(prefix: String): Name = prefix.toTermName
+
+ val Flag_SYNTHETIC: Flags = Flags.Synthetic.bits
+ val Flag_METHOD: Flags = Flags.Method.bits
+ val ExcludedForwarderFlags: Flags = {
+ Flags.Specialized | Flags.Lifted | Flags.Protected | Flags.JavaStatic |
+ Flags.ExpandedName | Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro
+ }.bits
+
+
+ def isQualifierSafeToElide(qual: Tree): Boolean = false // todo: implement
+ def getLabelDefOwners(t: Tree): Map[Tree, List[LabelDef]] = Map.empty
+
+ // todo: remove
+ def isMaybeBoxed(sym: Symbol) = {
+ (sym == ObjectClass) ||
+ (sym == JavaSerializableClass) ||
+ (sym == defn.ComparableClass) ||
+ (sym derivesFrom BoxedNumberClass) ||
+ (sym derivesFrom BoxedCharacterClass) ||
+ (sym derivesFrom BoxedBooleanClass)
+ }
+
+ def getSingleOutput: Option[AbstractFile] = None // todo: implement
+
+
+ def getGenericSignature(sym: Symbol, owner: Symbol): String = "" // todo: implement
+
+ def getStaticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol): String = "" // todo: implement
+
+
+ def sourceFileFor(cu: CompilationUnit): String = cu.source.file.name
+
+
+
+ implicit def positionHelper(a: Position): PositionHelper = new PositionHelper {
+ def isDefined: Boolean = a.exists
+ def line: Int = sourcePos(a).line
+ def finalPosition: Position = a
+ }
+
+ implicit def constantHelper(a: Constant): ConstantHelper = new ConstantHelper {
+ def booleanValue: Boolean = a.booleanValue
+ def longValue: Long = a.longValue
+ def byteValue: Byte = a.byteValue
+ def stringValue: String = a.stringValue
+ def symbolValue: Symbol = a.symbolValue
+ def floatValue: Float = a.floatValue
+ def value: Any = a.value
+ def tag: ConstantTag = a.tag
+ def typeValue: Type = a.typeValue
+ def shortValue: Short = a.shortValue
+ def intValue: Int = a.intValue
+ def doubleValue: Double = a.doubleValue
+ def charValue: Char = a.charValue
+ }
+
+
+ implicit def treeHelper(a: Tree): TreeHelper = new TreeHelper {
+ def symbol: Symbol = a.symbol
+
+ def pos: Position = a.pos
+
+ def isEmpty: Boolean = a.isEmpty
+
+ def tpe: Type = a.tpe
+
+ def exists(pred: (Tree) => Boolean): Boolean = a.find(pred).isDefined
+ }
+
+
+ implicit def annotHelper(a: Annotation): AnnotationHelper = new AnnotationHelper {
+ def atp: Type = a.tree.tpe
+
+ def assocs: List[(Name, Object)] = ???
+
+ def symbol: Symbol = a.tree.symbol
+
+ def args: List[Tree] = ???
+ }
+
+
+ implicit def nameHelper(n: Name): NameHelper = new NameHelper {
+ def toTypeName: Name = n.toTypeName
+ def isTypeName: Boolean = n.isTypeName
+ def toTermName: Name = n.toTermName
+ def dropModule: Name = ???
+
+ def len: Int = n.length
+ def offset: Int = n.start
+ def isTermName: Boolean = n.isTermName
+ def startsWith(s: String): Boolean = n.startsWith(s)
+ }
+
+
+ implicit def symHelper(sym: Symbol): SymbolHelper = new SymbolHelper {
+ // names
+ def fullName(sep: Char): String = sym.showFullName
+ def fullName: String = sym.showFullName
+ def simpleName: Name = sym.name
+ def javaSimpleName: Name = toDenot(sym).fullName // addModuleSuffix(simpleName.dropLocal)
+ def javaBinaryName: Name = toDenot(sym).fullNameSeparated('/') // addModuleSuffix(fullNameInternal('/'))
+ def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString
+ def name: Name = sym.name
+ def rawname: Name = sym.name // todo ????
+
+ // types
+ def info: Type = toDenot(sym).info
+ def tpe: Type = toDenot(sym).info // todo whats the differentce between tpe and info?
+ def thisType: Type = toDenot(sym).thisType
+
+ // tests
+ def isClass: Boolean = sym.isClass
+ def isType: Boolean = sym.isType
+ def isAnonymousClass: Boolean = toDenot(sym).isAnonymousClass
+ def isConstructor: Boolean = toDenot(sym).isConstructor
+ def isAnonymousFunction: Boolean = toDenot(sym).isAnonymousFunction
+ def isMethod: Boolean = sym is Flags.Method
+ def isPublic: Boolean = sym.flags.is(Flags.EmptyFlags, Flags.Private | Flags.Protected)
+ def isSynthetic: Boolean = sym is Flags.Synthetic
+ def isPackageClass: Boolean = sym is Flags.PackageClass
+ def isModuleClass: Boolean = sym is Flags.ModuleClass
+ def isModule: Boolean = sym is Flags.Module
+ def isStrictFP: Boolean = false // todo: implement
+ def isLabel: Boolean = sym is Flags.Label
+ def hasPackageFlag: Boolean = sym is Flags.Package
+ def isImplClass: Boolean = sym is Flags.ImplClass
+ def isInterface: Boolean = (sym is Flags.JavaInterface) || (sym is Flags.PureInterface)
+ def hasGetter: Boolean = false // used only for generaration of beaninfo todo: implement
+ def isGetter: Boolean = toDenot(sym).isGetter
+ def isSetter: Boolean = toDenot(sym).isSetter
+ def isGetClass: Boolean = sym eq defn.Any_getClass
+ def isJavaDefined: Boolean = sym is Flags.JavaDefined
+ def isDeferred: Boolean = sym is Flags.Deferred
+ def isPrivate: Boolean = sym is Flags.Private
+ def isFinal: Boolean = sym is Flags.Final
+ def isStaticMember: Boolean = (sym is Flags.JavaStatic) || (owner is Flags.ImplClass)
+ def isBottomClass: Boolean = (sym ne defn.NullClass) && (sym ne defn.NothingClass)
+ def isBridge: Boolean = sym is Flags.Bridge
+ def isArtifact: Boolean = sym is Flags.Artifact
+ def hasEnumFlag: Boolean = sym is Flags.Enum
+ def hasAccessBoundary: Boolean = sym.accessBoundary(defn.RootClass) ne defn.RootClass
+ def isVarargsMethod: Boolean = sym is Flags.JavaVarargs
+ def isDeprecated: Boolean = false
+ def isMutable: Boolean = sym is Flags.Mutable
+ def hasAbstractFlag: Boolean = sym is Flags.Abstract
+ def hasModuleFlag: Boolean = sym is Flags.Module
+ def isSynchronized: Boolean = sym is Flags.Synchronized
+ def isNonBottomSubClass(other: Symbol): Boolean = sym.derivesFrom(other)
+ def hasAnnotation(sym: Symbol): Boolean = false
+ def shouldEmitForwarders: Boolean = //exitingPickler { !(sym.name.toString contains '$')
+ (sym is Flags.Module) && !(sym is Flags.ImplClass) /// !sym.isNestedClass
+ def isJavaEntryPoint: Boolean = {
+ import Types.MethodType
+ val d = ctx.definitions
+ val StringType = d.StringType
+ def isJavaMainMethod(sym: Symbol) = (sym.name == nme.main) && (toDenot(sym).info match {
+ case r@ MethodType(_, List(d.ArrayType(StringType))) => r.resultType eq d.UnitType
+ case _ => false
+ })
+ // The given class has a main method.
+ def hasJavaMainMethod(sym: Symbol): Boolean =
+ (toDenot(sym).info member nme.main).alternatives exists(x => isJavaMainMethod(x.symbol))
+
+ def fail(msg: String, pos: Position = sym.pos) = {
+ ctx.warning( sym.name +
+ s" has a main method with parameter type Array[String], but ${toDenot(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) (toDenot(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
+ }
+ }
+ // At this point it's a module with a main-looking method, so either succeed or warn that it isn't.
+ hasApproximate && {
+ // Before erasure so we can identify generic mains.
+ {
+ // implicit val c = ctx.withPhase(ctx.erasurePhase)
+
+ val companion = sym.asClass.moduleClass
+
+ if (hasJavaMainMethod(companion))
+ failNoForwarder("companion contains its own main method")
+ else if (toDenot(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=> isJavaMainMethod(x.symbol))) || {
+ possibles exists { m =>
+ toDenot(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
+ 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)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ def isClassConstructor: Boolean = sym.name == nme.CONSTRUCTOR
+
+ /**
+ * True for module classes of modules that are top-level or owned only by objects. Module classes
+ * for such objects will get a MODULE$ flag and a corresponding static initializer.
+ */
+ def isStaticModuleClass: Boolean
+
+ def isStaticConstructor: Boolean = isStaticMember && isClassConstructor
+
+
+ // navigation
+ def owner: Symbol
+ def rawowner: Symbol // todo ???
+ def originalOwner: Symbol
+ def parentSymbols: List[Symbol]
+ def superClass: Symbol
+ def enclClass: Symbol
+ def linkedClassOfClass: Symbol
+ def linkedClass: Symbol
+ def companionClass: Symbol
+ def companionModule: Symbol
+ def companionSymbol: Symbol
+ def moduleClass: Symbol
+ def enclosingClassSym: Symbol
+
+
+
+ // members
+ def primaryConstructor: Symbol
+ def nestedClasses: List[Symbol]
+ def memberClasses: List[Symbol]
+ def annotations: List[Annotation]
+ def companionModuleMembers: List[Symbol]
+ def fieldSymbols: List[Symbol]
+ def methodSymbols: List[Symbol]
+ def serialVUID: Option[Long]
+
+
+ def freshLocal(cunit: CompilationUnit, name: String, pos: Position, flags: Flags): Symbol
+
+ def getter(clz: Symbol): Symbol
+ def setter(clz: Symbol): Symbol
+
+ def moduleSuffix: String
+ def outputDirectory: AbstractFile
+ def pos: Position
+
+ def throwsAnnotations: List[Symbol]
+
+ /**
+ * All interfaces implemented by a class, except for those inherited through the superclass.
+ *
+ */
+ def superInterfaces: List[Symbol]
+
+ /**
+ * True for module classes of package level objects. The backend will generate a mirror class for
+ * such objects.
+ */
+ def isTopLevelModuleClass: Boolean
+
+ /**
+ * This is basically a re-implementation of sym.isStaticOwner, but using the originalOwner chain.
+ *
+ * The problem is that we are interested in a source-level property. Various phases changed the
+ * symbol's properties in the meantime, mostly lambdalift modified (destructively) the owner.
+ * Therefore, `sym.isStatic` is not what we want. For example, in
+ * object T { def f { object U } }
+ * the owner of U is T, so UModuleClass.isStatic is true. Phase travel does not help here.
+ */
+ def isOriginallyStaticOwner: Boolean
+
+
+ def addRemoteRemoteExceptionAnnotation: Unit
+ }
+
+ val genBcode: GenBCode
+} \ No newline at end of file
diff --git a/src/dotty/tools/backend/jvm/GenBCode.scala b/src/dotty/tools/backend/jvm/GenBCode.scala
new file mode 100644
index 000000000..ff9958b46
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/GenBCode.scala
@@ -0,0 +1,381 @@
+package dotty.tools.backend.jvm
+
+import dotty.tools.dotc.CompilationUnit
+import dotty.tools.dotc.ast.Trees.PackageDef
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Phases.Phase
+
+import scala.tools.nsc.Settings
+import scala.tools.nsc.backend.jvm.{FileConflictException, BCodeSyncAndTry, BackendInterface, AsmUtils}
+import dotty.tools.dotc
+import dotty.tools.dotc.backend.jvm.DottyPrimitives
+import dotty.tools.dotc.transform.Erasure
+
+import scala.reflect.ClassTag
+import dotty.tools.dotc.core._
+import Periods._
+import SymDenotations._
+import Contexts._
+import Types._
+import Symbols._
+import Denotations._
+import Phases._
+import java.lang.AssertionError
+import scala.tools.asm
+import scala.tools.asm.tree._
+import dotty.tools.dotc.util.{Positions, DotClass}
+import tpd._
+
+import scala.tools.nsc.backend.jvm.opt.LocalOpt
+
+/**
+ * Created by dark on 24/11/14.
+ */
+abstract class GenBCode extends Phase with BCodeSyncAndTry{
+
+ val int: DottyBackendInterface
+ implicit val ctx: Context
+
+ def entryPoints: List[Symbol] = ???
+ def tree: Tree = ???
+ def toTypeKind(t: Type)(implicit ctx: Context): bTypes.BType = ???
+ val phaseName = "jvm"
+
+ final class PlainClassBuilder(cunit: CompilationUnit) extends SyncAndTryBuilder(cunit)
+
+ class BCodePhase() {
+
+ private var bytecodeWriter : BytecodeWriter = null
+ private var mirrorCodeGen : JMirrorBuilder = null
+ private var beanInfoCodeGen : JBeanInfoBuilder = null
+
+ /* ---------------- q1 ---------------- */
+
+ case class Item1(arrivalPos: Int, cd: TypeDef, cunit: CompilationUnit) {
+ def isPoison = { arrivalPos == Int.MaxValue }
+ }
+ private val poison1 = Item1(Int.MaxValue, null, ???)
+ private val q1 = new java.util.LinkedList[Item1]
+
+ /* ---------------- q2 ---------------- */
+
+ case class Item2(arrivalPos: Int,
+ mirror: asm.tree.ClassNode,
+ plain: asm.tree.ClassNode,
+ bean: asm.tree.ClassNode,
+ outFolder: scala.tools.nsc.io.AbstractFile) {
+ def isPoison = { arrivalPos == Int.MaxValue }
+ }
+
+ private val poison2 = Item2(Int.MaxValue, null, null, null, null)
+ private val q2 = new _root_.java.util.LinkedList[Item2]
+
+ /* ---------------- q3 ---------------- */
+
+ /*
+ * An item of queue-3 (the last queue before serializing to disk) contains three of these
+ * (one for each of mirror, plain, and bean classes).
+ *
+ * @param jclassName internal name of the class
+ * @param jclassBytes bytecode emitted for the class SubItem3 represents
+ */
+ case class SubItem3(
+ jclassName: String,
+ jclassBytes: Array[Byte]
+ )
+
+ case class Item3(arrivalPos: Int,
+ mirror: SubItem3,
+ plain: SubItem3,
+ bean: SubItem3,
+ outFolder: scala.tools.nsc.io.AbstractFile) {
+
+ def isPoison = { arrivalPos == Int.MaxValue }
+ }
+ private val i3comparator = new java.util.Comparator[Item3] {
+ override def compare(a: Item3, b: Item3) = {
+ if (a.arrivalPos < b.arrivalPos) -1
+ else if (a.arrivalPos == b.arrivalPos) 0
+ else 1
+ }
+ }
+ private val poison3 = Item3(Int.MaxValue, null, null, null, null)
+ private val q3 = new java.util.PriorityQueue[Item3](1000, i3comparator)
+
+ /*
+ * Pipeline that takes ClassDefs from queue-1, lowers them into an intermediate form, placing them on queue-2
+ */
+ class Worker1(needsOutFolder: Boolean) {
+
+ val caseInsensitively = scala.collection.mutable.Map.empty[String, Symbol]
+
+ def run() {
+ while (true) {
+ val item = q1.poll
+ if (item.isPoison) {
+ q2 add poison2
+ return
+ }
+ else {
+ try { /*withCurrentUnit(item.cunit)*/(visit(item)) }
+ catch {
+ case ex: Throwable =>
+ ex.printStackTrace()
+ error(s"Error while emitting ${int.sourceFileFor(item.cunit)}\n${ex.getMessage}")
+ }
+ }
+ }
+ }
+
+ /*
+ * Checks for duplicate internal names case-insensitively,
+ * builds ASM ClassNodes for mirror, plain, and bean classes;
+ * enqueues them in queue-2.
+ *
+ */
+ def visit(item: Item1) {
+ val Item1(arrivalPos, cd, cunit) = item
+ val claszSymbol = cd.symbol
+
+ // GenASM checks this before classfiles are emitted, https://github.com/scala/scala/commit/e4d1d930693ac75d8eb64c2c3c69f2fc22bec739
+ // todo: add back those checks
+ /*val lowercaseJavaClassName = claszSymbol.javaClassName.toLowerCase
+ caseInsensitively.get(lowercaseJavaClassName) match {
+ case None =>
+ caseInsensitively.put(lowercaseJavaClassName, claszSymbol)
+ case Some(dupClassSym) =>
+ reporter.warning(
+ claszSymbol.pos,
+ s"Class ${claszSymbol.javaClassName} differs only in case from ${dupClassSym.javaClassName}. " +
+ "Such classes will overwrite one another on case-insensitive filesystems."
+ )
+ }*/
+
+ // -------------- mirror class, if needed --------------
+ val mirrorC =
+ if (int.symHelper(claszSymbol).isTopLevelModuleClass) {
+ if (claszSymbol.companionClass == NoSymbol) {
+ mirrorCodeGen.genMirrorClass(claszSymbol, cunit)
+ } else {
+ ctx.log(s"No mirror class for module with linked class: ${claszSymbol.fullName}")
+ null
+ }
+ } else null
+
+ // -------------- "plain" class --------------
+ val pcb = new PlainClassBuilder(cunit)
+ pcb.genPlainClass(cd)
+ val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName) else null;
+ val plainC = pcb.cnode
+
+ // -------------- bean info class, if needed --------------
+ val beanC =
+ if (claszSymbol hasAnnotation int.BeanInfoAttr) {
+ beanInfoCodeGen.genBeanInfoClass(
+ claszSymbol, cunit,
+ int.symHelper(claszSymbol).fieldSymbols,
+ int.symHelper(claszSymbol).methodSymbols
+ )
+ } else null
+
+ // ----------- hand over to pipeline-2
+
+ val item2 =
+ Item2(arrivalPos,
+ mirrorC, plainC, beanC,
+ outF)
+
+ q2 add item2 // at the very end of this method so that no Worker2 thread starts mutating before we're done.
+
+ } // end of method visit(Item1)
+
+ } // end of class BCodePhase.Worker1
+
+ /*
+ * Pipeline that takes ClassNodes from queue-2. The unit of work depends on the optimization level:
+ *
+ * (a) no optimization involves:
+ * - converting the plain ClassNode to byte array and placing it on queue-3
+ */
+ class Worker2 {
+ lazy val localOpt = new LocalOpt(new Settings())
+
+ def localOptimizations(classNode: ClassNode): Unit = {
+ /*BackendStats.timed(BackendStats.methodOptTimer)*/(localOpt.methodOptimizations(classNode))
+ }
+
+ def run() {
+ while (true) {
+ val item = q2.poll
+ if (item.isPoison) {
+ q3 add poison3
+ return
+ }
+ else {
+ try {
+ localOptimizations(item.plain)
+ addToQ3(item)
+ } catch {
+ case ex: Throwable =>
+ ex.printStackTrace()
+ error(s"Error while emitting ${item.plain.name}\n${ex.getMessage}")
+ }
+ }
+ }
+ }
+
+ private def addToQ3(item: Item2) {
+
+ def getByteArray(cn: asm.tree.ClassNode): Array[Byte] = {
+ val cw = new CClassWriter(extraProc)
+ cn.accept(cw)
+ cw.toByteArray
+ }
+
+ val Item2(arrivalPos, mirror, plain, bean, outFolder) = item
+
+ val mirrorC = if (mirror == null) null else SubItem3(mirror.name, getByteArray(mirror))
+ val plainC = SubItem3(plain.name, getByteArray(plain))
+ val beanC = if (bean == null) null else SubItem3(bean.name, getByteArray(bean))
+
+ if (AsmUtils.traceSerializedClassEnabled && plain.name.contains(AsmUtils.traceSerializedClassPattern)) {
+ if (mirrorC != null) AsmUtils.traceClass(mirrorC.jclassBytes)
+ AsmUtils.traceClass(plainC.jclassBytes)
+ if (beanC != null) AsmUtils.traceClass(beanC.jclassBytes)
+ }
+
+ q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder)
+
+ }
+
+ } // end of class BCodePhase.Worker2
+
+ var arrivalPos = 0
+
+ /*
+ * A run of the BCodePhase phase comprises:
+ *
+ * (a) set-up steps (most notably supporting maps in `BCodeTypes`,
+ * but also "the" writer where class files in byte-array form go)
+ *
+ * (b) building of ASM ClassNodes, their optimization and serialization.
+ *
+ * (c) tear down (closing the classfile-writer and clearing maps)
+ *
+ */
+ def run() {
+ // val bcodeStart = Statistics.startTimer(BackendStats.bcodeTimer)
+
+ // val initStart = Statistics.startTimer(BackendStats.bcodeInitTimer)
+ arrivalPos = 0 // just in case
+ // scalaPrimitives.init()
+ bTypes.intializeCoreBTypes()
+ // Statistics.stopTimer(BackendStats.bcodeInitTimer, initStart)
+
+ // initBytecodeWriter invokes fullName, thus we have to run it before the typer-dependent thread is activated.
+ bytecodeWriter = initBytecodeWriter(entryPoints)
+ mirrorCodeGen = new JMirrorBuilder
+ beanInfoCodeGen = new JBeanInfoBuilder
+
+ val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter]
+ buildAndSendToDisk(needsOutfileForSymbol)
+
+ // closing output files.
+ bytecodeWriter.close()
+ // Statistics.stopTimer(BackendStats.bcodeTimer, bcodeStart)
+
+ /* TODO Bytecode can be verified (now that all classfiles have been written to disk)
+ *
+ * (1) asm.util.CheckAdapter.verify()
+ * public static void verify(ClassReader cr, ClassLoader loader, boolean dump, PrintWriter pw)
+ * passing a custom ClassLoader to verify inter-dependent classes.
+ * Alternatively,
+ * - an offline-bytecode verifier could be used (e.g. Maxine brings one as separate tool).
+ * - -Xverify:all
+ *
+ * (2) if requested, check-java-signatures, over and beyond the syntactic checks in `getGenericSignature()`
+ *
+ */
+ }
+
+ /*
+ * Sequentially:
+ * (a) place all ClassDefs in queue-1
+ * (b) dequeue one at a time from queue-1, convert it to ASM ClassNode, place in queue-2
+ * (c) dequeue one at a time from queue-2, convert it to byte-array, place in queue-3
+ * (d) serialize to disk by draining queue-3.
+ */
+ private def buildAndSendToDisk(needsOutFolder: Boolean) {
+
+ feedPipeline1()
+ // val genStart = Statistics.startTimer(BackendStats.bcodeGenStat)
+ (new Worker1(needsOutFolder)).run()
+ // Statistics.stopTimer(BackendStats.bcodeGenStat, genStart)
+
+ (new Worker2).run()
+
+ // val writeStart = Statistics.startTimer(BackendStats.bcodeWriteTimer)
+ drainQ3()
+ // Statistics.stopTimer(BackendStats.bcodeWriteTimer, writeStart)
+
+ }
+
+ /* Feed pipeline-1: place all ClassDefs on q1, recording their arrival position. */
+ private def feedPipeline1() {
+ def gen(tree: Tree) {
+ tree match {
+ case EmptyTree => ()
+ case PackageDef(_, stats) => stats foreach gen
+ case cd: TypeDef =>
+ q1 add Item1(arrivalPos, cd, int.currentUnit)
+ arrivalPos += 1
+ }
+ }
+ gen(tree)
+ q1 add poison1
+ }
+
+ /* Pipeline that writes classfile representations to disk. */
+ private def drainQ3() {
+
+ def sendToDisk(cfr: SubItem3, outFolder: scala.tools.nsc.io.AbstractFile) {
+ if (cfr != null){
+ val SubItem3(jclassName, jclassBytes) = cfr
+ try {
+ val outFile =
+ if (outFolder == null) null
+ else getFileForClassfile(outFolder, jclassName, ".class")
+ bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, outFile)
+ }
+ catch {
+ case e: FileConflictException =>
+ error(s"error writing $jclassName: ${e.getMessage}")
+ }
+ }
+ }
+
+ var moreComing = true
+ // `expected` denotes the arrivalPos whose Item3 should be serialized next
+ var expected = 0
+
+ while (moreComing) {
+ val incoming = q3.poll
+ moreComing = !incoming.isPoison
+ if (moreComing) {
+ val item = incoming
+ val outFolder = item.outFolder
+ sendToDisk(item.mirror, outFolder)
+ sendToDisk(item.plain, outFolder)
+ sendToDisk(item.bean, outFolder)
+ expected += 1
+ }
+ }
+
+ // we're done
+ assert(q1.isEmpty, s"Some ClassDefs remained in the first queue: $q1")
+ assert(q2.isEmpty, s"Some classfiles remained in the second queue: $q2")
+ assert(q3.isEmpty, s"Some classfiles weren't written to disk: $q3")
+
+ }
+ } // end of class BCodePhase
+}
diff --git a/src/dotty/tools/backend/jvm/scalaPrimitives.scala b/src/dotty/tools/backend/jvm/scalaPrimitives.scala
new file mode 100755
index 000000000..ef8318d0b
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/scalaPrimitives.scala
@@ -0,0 +1,399 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2012 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package dotty.tools.dotc
+package backend.jvm
+
+import dotty.tools.backend.jvm.GenBCode
+import dotty.tools.dotc.core.Names.TermName
+import dotty.tools.dotc.core.Types.{ErrorType, Type}
+
+import scala.collection.{ mutable, immutable }
+
+import core.Contexts.Context
+import core.Symbols.{Symbol, NoSymbol}
+
+/** Scala primitive operations are represented as methods in `Any` and
+ * `AnyVal` subclasses. Here we demultiplex them by providing a mapping
+ * from their symbols to integers. Different methods exist for
+ * different value types, but with the same meaning (like plus, minus,
+ * etc.). They will all be mapped to the same int.
+ *
+ * Note: The three equal methods have the following semantics:
+ * - `"=="` checks for `null`, and if non-null, calls
+ * `java.lang.Object.equals`
+ * `(class: Any; modifier: final)`. Primitive: `EQ`
+ * - `"eq"` usual reference comparison
+ * `(class: AnyRef; modifier: final)`. Primitive: `ID`
+ * - `"equals"` user-defined equality (Java semantics)
+ * `(class: Object; modifier: none)`. Primitive: `EQUALS`
+ *
+ * Inspired from the `scalac` compiler.
+ */
+class DottyPrimitives(ctx: Context, genBcode: GenBCode) {
+ import scala.tools.nsc.backend.ScalaPrimitives._
+
+ private lazy val primitives: immutable.Map[Symbol, Int] = init
+
+ /** Return the code for the given symbol. */
+ def getPrimitive(sym: Symbol): Int = {
+ assert(isPrimitive(sym), "Unknown primitive " + sym)
+ primitives(sym)
+ }
+
+ /**
+ * Return the primitive code of the given operation. If the
+ * operation is an array get/set, we inspect the type of the receiver
+ * to demux the operation.
+ *
+ * @param fun The method symbol
+ * @param tpe The type of the receiver object. It is used only for array
+ * operations
+ */
+ def getPrimitive(fun: Symbol, tpe: Type)(implicit ctx: Context): Int = {
+ val defn = ctx.definitions
+ val code = getPrimitive(fun)
+ import genBcode.bTypes._
+
+ def elementType = tpe.widenDealias match {
+ case defn.ArrayType(el) => el
+ case _ =>
+ ctx.error(s"expected Array $tpe")
+ ErrorType
+ }
+
+ code match {
+
+ case APPLY =>
+ genBcode.toTypeKind(elementType) match {
+ case BOOL => ZARRAY_GET
+ case BYTE => BARRAY_GET
+ case SHORT => SARRAY_GET
+ case CHAR => CARRAY_GET
+ case INT => IARRAY_GET
+ case LONG => LARRAY_GET
+ case FLOAT => FARRAY_GET
+ case DOUBLE => DARRAY_GET
+ case _ => OARRAY_GET
+ }
+
+ case UPDATE =>
+ genBcode.toTypeKind(elementType) match {
+ case BOOL => ZARRAY_SET
+ case BYTE => BARRAY_SET
+ case SHORT => SARRAY_SET
+ case CHAR => CARRAY_SET
+ case INT => IARRAY_SET
+ case LONG => LARRAY_SET
+ case FLOAT => FARRAY_SET
+ case DOUBLE => DARRAY_SET
+ case _ => OARRAY_SET
+
+ }
+
+ case LENGTH =>
+ genBcode.toTypeKind(elementType) match {
+ case BOOL => ZARRAY_LENGTH
+ case BYTE => BARRAY_LENGTH
+ case SHORT => SARRAY_LENGTH
+ case CHAR => CARRAY_LENGTH
+ case INT => IARRAY_LENGTH
+ case LONG => LARRAY_LENGTH
+ case FLOAT => FARRAY_LENGTH
+ case DOUBLE => DARRAY_LENGTH
+ case _ => OARRAY_LENGTH
+ }
+
+ case _ =>
+ code
+ }
+ }
+
+ /** Initialize the primitive map */
+ private def init: immutable.Map[Symbol, Int] = {
+
+ implicit val ctx = this.ctx
+
+ import core.Symbols.defn
+ val primitives = new mutable.HashMap[Symbol, Int]()
+
+ /** Add a primitive operation to the map */
+ def addPrimitive(s: Symbol, code: Int): Unit = {
+ assert(!(primitives contains s), "Duplicate primitive " + s)
+ primitives(s) = code
+ }
+
+ def addPrimitives(cls: Symbol, method: TermName, code: Int)(implicit ctx: Context): Unit = {
+ val alts = cls.info.member(method).alternatives.map(_.symbol)
+ if (alts.isEmpty)
+ ctx.error(s"Unknown primitive method $cls.$method")
+ else alts foreach (s =>
+ addPrimitive(s,
+ s.info.paramTypess match {
+ case List(tp :: _) if code == ADD && tp =:= ctx.definitions.StringType => CONCAT
+ case _ => code
+ }
+ )
+ )
+ }
+
+ // scala.Any
+ addPrimitive(defn.Any_==, EQ)
+ addPrimitive(defn.Any_!=, NE)
+ addPrimitive(defn.Any_isInstanceOf, IS)
+ addPrimitive(defn.Any_asInstanceOf, AS)
+ addPrimitive(defn.Any_##, HASH)
+
+ // java.lang.Object
+ addPrimitive(defn.Object_eq, ID)
+ addPrimitive(defn.Object_ne, NI)
+ addPrimitive(defn.Any_==, EQ)
+ addPrimitive(defn.Any_!=, NE)
+ addPrimitive(defn.Object_synchronized, SYNCHRONIZED)
+ addPrimitive(defn.Any_isInstanceOf, IS)
+ addPrimitive(defn.Any_asInstanceOf, AS)
+
+ // java.lang.String
+ addPrimitive(defn.String_+, CONCAT)
+
+ import core.StdNames.nme
+
+ // scala.Array
+ lazy val ArrayClass = defn.ArrayClass
+ addPrimitives(ArrayClass, nme.length, LENGTH)
+ addPrimitives(ArrayClass, nme.apply, APPLY)
+ addPrimitives(ArrayClass, nme.update, UPDATE)
+
+ // scala.Boolean
+ lazy val BooleanClass = defn.BooleanClass
+ addPrimitives(BooleanClass, nme.EQ, EQ)
+ addPrimitives(BooleanClass, nme.NE, NE)
+ addPrimitives(BooleanClass, nme.UNARY_!, ZNOT)
+ addPrimitives(BooleanClass, nme.ZOR, ZOR)
+ addPrimitives(BooleanClass, nme.ZAND, ZAND)
+ addPrimitives(BooleanClass, nme.OR, OR)
+ addPrimitives(BooleanClass, nme.AND, AND)
+ addPrimitives(BooleanClass, nme.XOR, XOR)
+
+ // scala.Byte
+ lazy val ByteClass = defn.ByteClass
+ addPrimitives(ByteClass, nme.EQ, EQ)
+ addPrimitives(ByteClass, nme.NE, NE)
+ addPrimitives(ByteClass, nme.ADD, ADD)
+ addPrimitives(ByteClass, nme.SUB, SUB)
+ addPrimitives(ByteClass, nme.MUL, MUL)
+ addPrimitives(ByteClass, nme.DIV, DIV)
+ addPrimitives(ByteClass, nme.MOD, MOD)
+ addPrimitives(ByteClass, nme.LT, LT)
+ addPrimitives(ByteClass, nme.LE, LE)
+ addPrimitives(ByteClass, nme.GT, GT)
+ addPrimitives(ByteClass, nme.GE, GE)
+ addPrimitives(ByteClass, nme.XOR, XOR)
+ addPrimitives(ByteClass, nme.OR, OR)
+ addPrimitives(ByteClass, nme.AND, AND)
+ addPrimitives(ByteClass, nme.LSL, LSL)
+ addPrimitives(ByteClass, nme.LSR, LSR)
+ addPrimitives(ByteClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(ByteClass, nme.toByte, B2B)
+ addPrimitives(ByteClass, nme.toShort, B2S)
+ addPrimitives(ByteClass, nme.toChar, B2C)
+ addPrimitives(ByteClass, nme.toInt, B2I)
+ addPrimitives(ByteClass, nme.toLong, B2L)
+ // unary methods
+ addPrimitives(ByteClass, nme.UNARY_+, POS)
+ addPrimitives(ByteClass, nme.UNARY_-, NEG)
+ addPrimitives(ByteClass, nme.UNARY_~, NOT)
+
+ addPrimitives(ByteClass, nme.toFloat, B2F)
+ addPrimitives(ByteClass, nme.toDouble, B2D)
+
+ // scala.Short
+ lazy val ShortClass = defn.ShortClass
+ addPrimitives(ShortClass, nme.EQ, EQ)
+ addPrimitives(ShortClass, nme.NE, NE)
+ addPrimitives(ShortClass, nme.ADD, ADD)
+ addPrimitives(ShortClass, nme.SUB, SUB)
+ addPrimitives(ShortClass, nme.MUL, MUL)
+ addPrimitives(ShortClass, nme.DIV, DIV)
+ addPrimitives(ShortClass, nme.MOD, MOD)
+ addPrimitives(ShortClass, nme.LT, LT)
+ addPrimitives(ShortClass, nme.LE, LE)
+ addPrimitives(ShortClass, nme.GT, GT)
+ addPrimitives(ShortClass, nme.GE, GE)
+ addPrimitives(ShortClass, nme.XOR, XOR)
+ addPrimitives(ShortClass, nme.OR, OR)
+ addPrimitives(ShortClass, nme.AND, AND)
+ addPrimitives(ShortClass, nme.LSL, LSL)
+ addPrimitives(ShortClass, nme.LSR, LSR)
+ addPrimitives(ShortClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(ShortClass, nme.toByte, S2B)
+ addPrimitives(ShortClass, nme.toShort, S2S)
+ addPrimitives(ShortClass, nme.toChar, S2C)
+ addPrimitives(ShortClass, nme.toInt, S2I)
+ addPrimitives(ShortClass, nme.toLong, S2L)
+ // unary methods
+ addPrimitives(ShortClass, nme.UNARY_+, POS)
+ addPrimitives(ShortClass, nme.UNARY_-, NEG)
+ addPrimitives(ShortClass, nme.UNARY_~, NOT)
+
+ addPrimitives(ShortClass, nme.toFloat, S2F)
+ addPrimitives(ShortClass, nme.toDouble, S2D)
+
+ // scala.Char
+ lazy val CharClass = defn.CharClass
+ addPrimitives(CharClass, nme.EQ, EQ)
+ addPrimitives(CharClass, nme.NE, NE)
+ addPrimitives(CharClass, nme.ADD, ADD)
+ addPrimitives(CharClass, nme.SUB, SUB)
+ addPrimitives(CharClass, nme.MUL, MUL)
+ addPrimitives(CharClass, nme.DIV, DIV)
+ addPrimitives(CharClass, nme.MOD, MOD)
+ addPrimitives(CharClass, nme.LT, LT)
+ addPrimitives(CharClass, nme.LE, LE)
+ addPrimitives(CharClass, nme.GT, GT)
+ addPrimitives(CharClass, nme.GE, GE)
+ addPrimitives(CharClass, nme.XOR, XOR)
+ addPrimitives(CharClass, nme.OR, OR)
+ addPrimitives(CharClass, nme.AND, AND)
+ addPrimitives(CharClass, nme.LSL, LSL)
+ addPrimitives(CharClass, nme.LSR, LSR)
+ addPrimitives(CharClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(CharClass, nme.toByte, C2B)
+ addPrimitives(CharClass, nme.toShort, C2S)
+ addPrimitives(CharClass, nme.toChar, C2C)
+ addPrimitives(CharClass, nme.toInt, C2I)
+ addPrimitives(CharClass, nme.toLong, C2L)
+ // unary methods
+ addPrimitives(CharClass, nme.UNARY_+, POS)
+ addPrimitives(CharClass, nme.UNARY_-, NEG)
+ addPrimitives(CharClass, nme.UNARY_~, NOT)
+ addPrimitives(CharClass, nme.toFloat, C2F)
+ addPrimitives(CharClass, nme.toDouble, C2D)
+
+ // scala.Int
+ lazy val IntClass = defn.IntClass
+ addPrimitives(IntClass, nme.EQ, EQ)
+ addPrimitives(IntClass, nme.NE, NE)
+ addPrimitives(IntClass, nme.ADD, ADD)
+ addPrimitives(IntClass, nme.SUB, SUB)
+ addPrimitives(IntClass, nme.MUL, MUL)
+ addPrimitives(IntClass, nme.DIV, DIV)
+ addPrimitives(IntClass, nme.MOD, MOD)
+ addPrimitives(IntClass, nme.LT, LT)
+ addPrimitives(IntClass, nme.LE, LE)
+ addPrimitives(IntClass, nme.GT, GT)
+ addPrimitives(IntClass, nme.GE, GE)
+ addPrimitives(IntClass, nme.XOR, XOR)
+ addPrimitives(IntClass, nme.OR, OR)
+ addPrimitives(IntClass, nme.AND, AND)
+ addPrimitives(IntClass, nme.LSL, LSL)
+ addPrimitives(IntClass, nme.LSR, LSR)
+ addPrimitives(IntClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(IntClass, nme.toByte, I2B)
+ addPrimitives(IntClass, nme.toShort, I2S)
+ addPrimitives(IntClass, nme.toChar, I2C)
+ addPrimitives(IntClass, nme.toInt, I2I)
+ addPrimitives(IntClass, nme.toLong, I2L)
+ // unary methods
+ addPrimitives(IntClass, nme.UNARY_+, POS)
+ addPrimitives(IntClass, nme.UNARY_-, NEG)
+ addPrimitives(IntClass, nme.UNARY_~, NOT)
+ addPrimitives(IntClass, nme.toFloat, I2F)
+ addPrimitives(IntClass, nme.toDouble, I2D)
+
+ // scala.Long
+ lazy val LongClass = defn.LongClass
+ addPrimitives(LongClass, nme.EQ, EQ)
+ addPrimitives(LongClass, nme.NE, NE)
+ addPrimitives(LongClass, nme.ADD, ADD)
+ addPrimitives(LongClass, nme.SUB, SUB)
+ addPrimitives(LongClass, nme.MUL, MUL)
+ addPrimitives(LongClass, nme.DIV, DIV)
+ addPrimitives(LongClass, nme.MOD, MOD)
+ addPrimitives(LongClass, nme.LT, LT)
+ addPrimitives(LongClass, nme.LE, LE)
+ addPrimitives(LongClass, nme.GT, GT)
+ addPrimitives(LongClass, nme.GE, GE)
+ addPrimitives(LongClass, nme.XOR, XOR)
+ addPrimitives(LongClass, nme.OR, OR)
+ addPrimitives(LongClass, nme.AND, AND)
+ addPrimitives(LongClass, nme.LSL, LSL)
+ addPrimitives(LongClass, nme.LSR, LSR)
+ addPrimitives(LongClass, nme.ASR, ASR)
+ // conversions
+ addPrimitives(LongClass, nme.toByte, L2B)
+ addPrimitives(LongClass, nme.toShort, L2S)
+ addPrimitives(LongClass, nme.toChar, L2C)
+ addPrimitives(LongClass, nme.toInt, L2I)
+ addPrimitives(LongClass, nme.toLong, L2L)
+ // unary methods
+ addPrimitives(LongClass, nme.UNARY_+, POS)
+ addPrimitives(LongClass, nme.UNARY_-, NEG)
+ addPrimitives(LongClass, nme.UNARY_~, NOT)
+ addPrimitives(LongClass, nme.toFloat, L2F)
+ addPrimitives(LongClass, nme.toDouble, L2D)
+
+ // scala.Float
+ lazy val FloatClass = defn.FloatClass
+ addPrimitives(FloatClass, nme.EQ, EQ)
+ addPrimitives(FloatClass, nme.NE, NE)
+ addPrimitives(FloatClass, nme.ADD, ADD)
+ addPrimitives(FloatClass, nme.SUB, SUB)
+ addPrimitives(FloatClass, nme.MUL, MUL)
+ addPrimitives(FloatClass, nme.DIV, DIV)
+ addPrimitives(FloatClass, nme.MOD, MOD)
+ addPrimitives(FloatClass, nme.LT, LT)
+ addPrimitives(FloatClass, nme.LE, LE)
+ addPrimitives(FloatClass, nme.GT, GT)
+ addPrimitives(FloatClass, nme.GE, GE)
+ // conversions
+ addPrimitives(FloatClass, nme.toByte, F2B)
+ addPrimitives(FloatClass, nme.toShort, F2S)
+ addPrimitives(FloatClass, nme.toChar, F2C)
+ addPrimitives(FloatClass, nme.toInt, F2I)
+ addPrimitives(FloatClass, nme.toLong, F2L)
+ addPrimitives(FloatClass, nme.toFloat, F2F)
+ addPrimitives(FloatClass, nme.toDouble, F2D)
+ // unary methods
+ addPrimitives(FloatClass, nme.UNARY_+, POS)
+ addPrimitives(FloatClass, nme.UNARY_-, NEG)
+
+ // scala.Double
+ lazy val DoubleClass = defn.DoubleClass
+ addPrimitives(DoubleClass, nme.EQ, EQ)
+ addPrimitives(DoubleClass, nme.NE, NE)
+ addPrimitives(DoubleClass, nme.ADD, ADD)
+ addPrimitives(DoubleClass, nme.SUB, SUB)
+ addPrimitives(DoubleClass, nme.MUL, MUL)
+ addPrimitives(DoubleClass, nme.DIV, DIV)
+ addPrimitives(DoubleClass, nme.MOD, MOD)
+ addPrimitives(DoubleClass, nme.LT, LT)
+ addPrimitives(DoubleClass, nme.LE, LE)
+ addPrimitives(DoubleClass, nme.GT, GT)
+ addPrimitives(DoubleClass, nme.GE, GE)
+ // conversions
+ addPrimitives(DoubleClass, nme.toByte, D2B)
+ addPrimitives(DoubleClass, nme.toShort, D2S)
+ addPrimitives(DoubleClass, nme.toChar, D2C)
+ addPrimitives(DoubleClass, nme.toInt, D2I)
+ addPrimitives(DoubleClass, nme.toLong, D2L)
+ addPrimitives(DoubleClass, nme.toFloat, D2F)
+ addPrimitives(DoubleClass, nme.toDouble, D2D)
+ // unary methods
+ addPrimitives(DoubleClass, nme.UNARY_+, POS)
+ addPrimitives(DoubleClass, nme.UNARY_-, NEG)
+
+
+ primitives.toMap
+ }
+
+ def isPrimitive(sym: Symbol): Boolean = primitives contains sym
+
+}
+
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 19d175088..41cbc05d2 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -398,7 +398,7 @@ class Definitions {
def apply(elem: Type)(implicit ctx: Context) =
if (ctx.erasedTypes) JavaArrayType(elem)
else ArrayClass.typeRef.appliedTo(elem :: Nil)
- def unapply(tp: Type)(implicit ctx: Context) = tp.dealias match {
+ def unapply(tp: Type)(implicit ctx: Context): Option[Type] = tp.dealias match {
case at: RefinedType if (at isRef ArrayClass) && at.argInfos.length == 1 => Some(at.argInfos.head)
case _ => None
}
diff --git a/src/dotty/tools/dotc/core/Names.scala b/src/dotty/tools/dotc/core/Names.scala
index cf53d0445..f0d3f02eb 100644
--- a/src/dotty/tools/dotc/core/Names.scala
+++ b/src/dotty/tools/dotc/core/Names.scala
@@ -200,7 +200,7 @@ object Names {
private final val fillFactor = 0.7
/** Memory to store all names sequentially. */
- private var chrs: Array[Char] = new Array[Char](InitialNameSize)
+ private[dotty] var chrs: Array[Char] = new Array[Char](InitialNameSize)
/** The number of characters filled. */
private var nc = 0
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index 5777c0f5b..70dd4296a 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -3,6 +3,7 @@ package core
import Periods._
import Contexts._
+import dotty.tools.backend.jvm.GenBCode
import util.DotClass
import DenotTransformers._
import Denotations._
@@ -171,6 +172,7 @@ object Phases {
private val flattenCache = new PhaseCache(classOf[Flatten])
private val explicitOuterCache = new PhaseCache(classOf[ExplicitOuter])
private val gettersCache = new PhaseCache(classOf[Getters])
+ private val genBCodeCache = new PhaseCache(classOf[GenBCode])
def typerPhase = typerCache.phase
def refchecksPhase = refChecksCache.phase
@@ -179,6 +181,7 @@ object Phases {
def flattenPhase = flattenCache.phase
def explicitOuterPhase = explicitOuterCache.phase
def gettersPhase = gettersCache.phase
+ def genBCodePhase = genBCodeCache.phase
def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id
}
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 841d94b74..e1707c4b2 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -324,6 +324,9 @@ object SymDenotations {
final def isAnonymousClass(implicit ctx: Context): Boolean =
isClass && (initial.asSymDenotation.name startsWith tpnme.ANON_CLASS)
+ final def isAnonymousFunction(implicit ctx: Context) =
+ this.isInstanceOf[SymDenotation] && (flags is Synthetic) && (initial.asSymDenotation.name startsWith tpnme.ANON_FUN)
+
/** Is symbol a primitive value class? */
def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains symbol