From 53a78276769fed368b552ef72de370a24a68acb8 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Fri, 7 Feb 2014 15:57:19 +0100 Subject: [PATCH 1/8] package renaming --- src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala | 4 ++-- src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala | 4 ++-- src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala | 4 ++-- src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala | 4 ++-- src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala | 4 ++-- src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala | 4 ++-- src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala | 4 ++-- src/dotty/tools/dotc/backend/jvm/GenBCode.scala | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) mode change 100644 => 100755 src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala mode change 100644 => 100755 src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala mode change 100644 => 100755 src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala mode change 100644 => 100755 src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala mode change 100644 => 100755 src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala mode change 100644 => 100755 src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala mode change 100644 => 100755 src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala mode change 100644 => 100755 src/dotty/tools/dotc/backend/jvm/GenBCode.scala diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala b/src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala old mode 100644 new mode 100755 index c8845344e996..a35445e6dabf --- a/src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala @@ -4,8 +4,8 @@ */ -package scala -package tools.nsc +package dotty.tools +package dotc package backend package jvm diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala b/src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala old mode 100644 new mode 100755 index cc3265c5f9fb..d99275919225 --- a/src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala @@ -3,8 +3,8 @@ * @author Martin Odersky */ -package scala -package tools.nsc +package dotty.tools +package dotc package backend.jvm import scala.tools.asm diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala b/src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala old mode 100644 new mode 100755 index 18ccced75ebc..54882d7ef053 --- a/src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala @@ -3,8 +3,8 @@ * @author Martin Odersky */ -package scala -package tools.nsc +package dotty.tools +package dotc package backend.jvm import scala.tools.asm diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala b/src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala old mode 100644 new mode 100755 index c3492b79a9e6..5090716db32c --- a/src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala @@ -3,8 +3,8 @@ * @author Martin Odersky */ -package scala -package tools.nsc +package dotty.tools +package dotc package backend.jvm import scala.tools.asm diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala b/src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala old mode 100644 new mode 100755 index 360ce58ecc57..95823dbfd010 --- a/src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala @@ -4,8 +4,8 @@ */ -package scala -package tools.nsc +package dotty.tools +package dotc package backend package jvm diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala b/src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala old mode 100644 new mode 100755 index 9ddb7a3ce832..f50a70c83773 --- a/src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala @@ -4,8 +4,8 @@ */ -package scala -package tools.nsc +package dotty.tools +package dotc package backend package jvm diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala b/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala old mode 100644 new mode 100755 index 1eca69936a30..516c09139f77 --- a/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala @@ -3,8 +3,8 @@ * @author Martin Odersky */ -package scala -package tools.nsc +package dotty.tools +package dotc package backend.jvm import scala.tools.asm diff --git a/src/dotty/tools/dotc/backend/jvm/GenBCode.scala b/src/dotty/tools/dotc/backend/jvm/GenBCode.scala old mode 100644 new mode 100755 index 193100474ccb..0090e6a78d75 --- a/src/dotty/tools/dotc/backend/jvm/GenBCode.scala +++ b/src/dotty/tools/dotc/backend/jvm/GenBCode.scala @@ -4,8 +4,8 @@ */ -package scala -package tools.nsc +package dotty.tools +package dotc package backend package jvm From 367ce512693710a74a253c38ed15c595ab9055f5 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Fri, 7 Feb 2014 16:03:01 +0100 Subject: [PATCH 2/8] adding icodes and scalaPrimitives --- src/dotty/tools/dotc/backend/jvm/icodes.scala | 162 ++++++ .../dotc/backend/jvm/scalaPrimitives.scala | 541 ++++++++++++++++++ 2 files changed, 703 insertions(+) create mode 100755 src/dotty/tools/dotc/backend/jvm/icodes.scala create mode 100755 src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala diff --git a/src/dotty/tools/dotc/backend/jvm/icodes.scala b/src/dotty/tools/dotc/backend/jvm/icodes.scala new file mode 100755 index 000000000000..8adb4e1aee4c --- /dev/null +++ b/src/dotty/tools/dotc/backend/jvm/icodes.scala @@ -0,0 +1,162 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Martin Odersky + */ + + +package dotty.tools +package dotc +package backend +package jvm + +object icodes { + + /** This class represents a test operation. */ + sealed abstract class TestOp { + + /** Returns the negation of this operation. */ + def negate(): TestOp + + /** Returns a string representation of this operation. */ + override def toString(): String + + /** used only from GenASM */ + def opcodeIF(): Int + + /** used only from GenASM */ + def opcodeIFICMP(): Int + + } + + /** An equality test */ + case object EQ extends TestOp { + def negate() = NE + override def toString() = "EQ" + override def opcodeIF() = scala.tools.asm.Opcodes.IFEQ + override def opcodeIFICMP() = scala.tools.asm.Opcodes.IF_ICMPEQ + } + + /** A non-equality test */ + case object NE extends TestOp { + def negate() = EQ + override def toString() = "NE" + override def opcodeIF() = scala.tools.asm.Opcodes.IFNE + override def opcodeIFICMP() = scala.tools.asm.Opcodes.IF_ICMPNE + } + + /** A less-than test */ + case object LT extends TestOp { + def negate() = GE + override def toString() = "LT" + override def opcodeIF() = scala.tools.asm.Opcodes.IFLT + override def opcodeIFICMP() = scala.tools.asm.Opcodes.IF_ICMPLT + } + + /** A greater-than-or-equal test */ + case object GE extends TestOp { + def negate() = LT + override def toString() = "GE" + override def opcodeIF() = scala.tools.asm.Opcodes.IFGE + override def opcodeIFICMP() = scala.tools.asm.Opcodes.IF_ICMPGE + } + + /** A less-than-or-equal test */ + case object LE extends TestOp { + def negate() = GT + override def toString() = "LE" + override def opcodeIF() = scala.tools.asm.Opcodes.IFLE + override def opcodeIFICMP() = scala.tools.asm.Opcodes.IF_ICMPLE + } + + /** A greater-than test */ + case object GT extends TestOp { + def negate() = LE + override def toString() = "GT" + override def opcodeIF() = scala.tools.asm.Opcodes.IFGT + override def opcodeIFICMP() = scala.tools.asm.Opcodes.IF_ICMPGT + } + + /** This class represents an arithmetic operation. */ + class ArithmeticOp { + + /** Returns a string representation of this operation. */ + override def toString(): String = this match { + case ADD => "ADD" + case SUB => "SUB" + case MUL => "MUL" + case DIV => "DIV" + case REM => "REM" + case NOT => "NOT" + case _ => throw new RuntimeException("ArithmeticOp unknown case") + } + } + + /** An arithmetic addition operation */ + case object ADD extends ArithmeticOp + + /** An arithmetic subtraction operation */ + case object SUB extends ArithmeticOp + + /** An arithmetic multiplication operation */ + case object MUL extends ArithmeticOp + + /** An arithmetic division operation */ + case object DIV extends ArithmeticOp + + /** An arithmetic remainder operation */ + case object REM extends ArithmeticOp + + /** Bitwise negation. */ + case object NOT extends ArithmeticOp + + object opcodes { + + /** This class represents a method invocation style. */ + sealed abstract class InvokeStyle { + /** Is this a dynamic method call? */ + def isDynamic: Boolean = false + + /** Is this a static method call? */ + def isStatic: Boolean = false + + def isSuper: Boolean = false + + /** Is this an instance method call? */ + def hasInstance: Boolean = true + + /** Returns a string representation of this style. */ + override def toString(): String + } + + /** Virtual calls. + * On JVM, translated to either `invokeinterface` or `invokevirtual`. + */ + case object Dynamic extends InvokeStyle { + override def isDynamic = true + override def toString(): String = "dynamic" + } + + /** + * Special invoke: + * Static(true) is used for calls to private members, ie `invokespecial` on JVM. + * Static(false) is used for calls to class-level instance-less static methods, ie `invokestatic` on JVM. + */ + case class Static(onInstance: Boolean) extends InvokeStyle { + override def isStatic = true + override def hasInstance = onInstance + override def toString(): String = { + if(onInstance) "static-instance" + else "static-class" + } + } + + /** Call through super[mix]. + * On JVM, translated to `invokespecial`. + */ + case class SuperCall(mix: dotc.core.Names.TermName) extends InvokeStyle { + override def isSuper = true + override def toString(): String = { "super(" + mix + ")" } + } + } + +} diff --git a/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala b/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala new file mode 100755 index 000000000000..bf7f70eb72e3 --- /dev/null +++ b/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala @@ -0,0 +1,541 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Martin Odersky + */ + +package dotty.tools +package dotc +package backend.jvm + +import scala.collection.{ mutable, immutable } + +/** 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. + */ +object scalaPrimitives { + + // Arithmetic unary operations + final val POS = 1 // +x + final val NEG = 2 // -x + final val NOT = 3 // ~x + + // Arithmetic binary operations + final val ADD = 10 // x + y + final val SUB = 11 // x - y + final val MUL = 12 // x * y + final val DIV = 13 // x / y + final val MOD = 14 // x % y + + // Bitwise operations + final val OR = 20 // x | y + final val XOR = 21 // x ^ y + final val AND = 22 // x & y + + // Shift operations + final val LSL = 30 // x << y + final val LSR = 31 // x >>> y + final val ASR = 32 // x >> y + + // Comparison operations + final val ID = 40 // x eq y + final val NI = 41 // x ne y + final val EQ = 42 // x == y + final val NE = 43 // x != y + final val LT = 44 // x < y + final val LE = 45 // x <= y + final val GE = 46 // x > y + final val GT = 47 // x >= y + + // Boolean unary operations + final val ZNOT = 50 // !x + + // Boolean binary operations + final val ZOR = 60 // x || y + final val ZAND = 61 // x && y + + // Array operations + final val LENGTH = 70 // x.length + final val APPLY = 71 // x(y) + final val UPDATE = 72 // x(y) = z + + // Any operations + final val IS = 80 // x.is[y] + final val AS = 81 // x.as[y] + final val HASH = 87 // x.## + + // AnyRef operations + final val SYNCHRONIZED = 90 // x.synchronized(y) + + // String operations + final val CONCAT = 100 // String.valueOf(x)+String.valueOf(y) + + // coercions + final val COERCE = 101 + + // RunTime operations + final val BOX = 110 // RunTime.box_(x) + final val UNBOX = 111 // RunTime.unbox_(x) + final val NEW_ZARRAY = 112 // RunTime.zarray(x) + final val NEW_BARRAY = 113 // RunTime.barray(x) + final val NEW_SARRAY = 114 // RunTime.sarray(x) + final val NEW_CARRAY = 115 // RunTime.carray(x) + final val NEW_IARRAY = 116 // RunTime.iarray(x) + final val NEW_LARRAY = 117 // RunTime.larray(x) + final val NEW_FARRAY = 118 // RunTime.farray(x) + final val NEW_DARRAY = 119 // RunTime.darray(x) + final val NEW_OARRAY = 120 // RunTime.oarray(x) + + final val ZARRAY_LENGTH = 131 // RunTime.zarray_length(x) + final val BARRAY_LENGTH = 132 // RunTime.barray_length(x) + final val SARRAY_LENGTH = 133 // RunTime.sarray_length(x) + final val CARRAY_LENGTH = 134 // RunTime.carray_length(x) + final val IARRAY_LENGTH = 135 // RunTime.iarray_length(x) + final val LARRAY_LENGTH = 136 // RunTime.larray_length(x) + final val FARRAY_LENGTH = 137 // RunTime.farray_length(x) + final val DARRAY_LENGTH = 138 // RunTime.darray_length(x) + final val OARRAY_LENGTH = 139 // RunTime.oarray_length(x) + + final val ZARRAY_GET = 140 // RunTime.zarray_get(x,y) + final val BARRAY_GET = 141 // RunTime.barray_get(x,y) + final val SARRAY_GET = 142 // RunTime.sarray_get(x,y) + final val CARRAY_GET = 143 // RunTime.carray_get(x,y) + final val IARRAY_GET = 144 // RunTime.iarray_get(x,y) + final val LARRAY_GET = 145 // RunTime.larray_get(x,y) + final val FARRAY_GET = 146 // RunTime.farray_get(x,y) + final val DARRAY_GET = 147 // RunTime.darray_get(x,y) + final val OARRAY_GET = 148 // RunTime.oarray_get(x,y) + + final val ZARRAY_SET = 150 // RunTime.zarray(x,y,z) + final val BARRAY_SET = 151 // RunTime.barray(x,y,z) + final val SARRAY_SET = 152 // RunTime.sarray(x,y,z) + final val CARRAY_SET = 153 // RunTime.carray(x,y,z) + final val IARRAY_SET = 154 // RunTime.iarray(x,y,z) + final val LARRAY_SET = 155 // RunTime.larray(x,y,z) + final val FARRAY_SET = 156 // RunTime.farray(x,y,z) + final val DARRAY_SET = 157 // RunTime.darray(x,y,z) + final val OARRAY_SET = 158 // RunTime.oarray(x,y,z) + + final val B2B = 200 // RunTime.b2b(x) + final val B2S = 201 // RunTime.b2s(x) + final val B2C = 202 // RunTime.b2c(x) + final val B2I = 203 // RunTime.b2i(x) + final val B2L = 204 // RunTime.b2l(x) + final val B2F = 205 // RunTime.b2f(x) + final val B2D = 206 // RunTime.b2d(x) + + final val S2B = 210 // RunTime.s2b(x) + final val S2S = 211 // RunTime.s2s(x) + final val S2C = 212 // RunTime.s2c(x) + final val S2I = 213 // RunTime.s2i(x) + final val S2L = 214 // RunTime.s2l(x) + final val S2F = 215 // RunTime.s2f(x) + final val S2D = 216 // RunTime.s2d(x) + + final val C2B = 220 // RunTime.c2b(x) + final val C2S = 221 // RunTime.c2s(x) + final val C2C = 222 // RunTime.c2c(x) + final val C2I = 223 // RunTime.c2i(x) + final val C2L = 224 // RunTime.c2l(x) + final val C2F = 225 // RunTime.c2f(x) + final val C2D = 226 // RunTime.c2d(x) + + final val I2B = 230 // RunTime.i2b(x) + final val I2S = 231 // RunTime.i2s(x) + final val I2C = 232 // RunTime.i2c(x) + final val I2I = 233 // RunTime.i2i(x) + final val I2L = 234 // RunTime.i2l(x) + final val I2F = 235 // RunTime.i2f(x) + final val I2D = 236 // RunTime.i2d(x) + + final val L2B = 240 // RunTime.l2b(x) + final val L2S = 241 // RunTime.l2s(x) + final val L2C = 242 // RunTime.l2c(x) + final val L2I = 243 // RunTime.l2i(x) + final val L2L = 244 // RunTime.l2l(x) + final val L2F = 245 // RunTime.l2f(x) + final val L2D = 246 // RunTime.l2d(x) + + final val F2B = 250 // RunTime.f2b(x) + final val F2S = 251 // RunTime.f2s(x) + final val F2C = 252 // RunTime.f2c(x) + final val F2I = 253 // RunTime.f2i(x) + final val F2L = 254 // RunTime.f2l(x) + final val F2F = 255 // RunTime.f2f(x) + final val F2D = 256 // RunTime.f2d(x) + + final val D2B = 260 // RunTime.d2b(x) + final val D2S = 261 // RunTime.d2s(x) + final val D2C = 262 // RunTime.d2c(x) + final val D2I = 263 // RunTime.d2i(x) + final val D2L = 264 // RunTime.d2l(x) + final val D2F = 265 // RunTime.d2f(x) + final val D2D = 266 // RunTime.d2d(x) + + private val primitives: mutable.Map[Symbol, Int] = new mutable.HashMap() + + /** Return the code for the given symbol. */ + def getPrimitive(sym: Symbol): Int = { + assert(isPrimitive(sym), "Unknown primitive " + sym) + primitives(sym) + } + + /** Initialize the primitive map */ + def init() { + primitives.clear() + // scala.Any + addPrimitive(Any_==, EQ) + addPrimitive(Any_!=, NE) + addPrimitive(Any_isInstanceOf, IS) + addPrimitive(Any_asInstanceOf, AS) + addPrimitive(Any_##, HASH) + + // java.lang.Object + addPrimitive(Object_eq, ID) + addPrimitive(Object_ne, NI) + addPrimitive(Object_==, EQ) + addPrimitive(Object_!=, NE) + addPrimitive(Object_synchronized, SYNCHRONIZED) + addPrimitive(Object_isInstanceOf, IS) + addPrimitive(Object_asInstanceOf, AS) + + // java.lang.String + addPrimitive(String_+, CONCAT) + + // scala.Array + addPrimitives(ArrayClass, nme.length, LENGTH) + addPrimitives(ArrayClass, nme.apply, APPLY) + addPrimitives(ArrayClass, nme.update, UPDATE) + + // scala.Boolean + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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) + } + + /** Add a primitive operation to the map */ + def addPrimitive(s: Symbol, code: Int) { + assert(!(primitives contains s), "Duplicate primitive " + s) + primitives(s) = code + } + + def addPrimitives(cls: Symbol, method: dotc.core.Names.TermName, code: Int) { + val alts = (cls.info member method).alternatives + if (alts.isEmpty) + inform(s"Unknown primitive method $cls.$method") + else alts foreach (s => + addPrimitive(s, + s.info.paramTypes match { + case tp :: _ if code == ADD && tp =:= StringTpe => CONCAT + case _ => code + } + ) + ) + } + + def isCoercion(code: Int): Boolean = (code >= B2B) && (code <= D2D) + + /** Check whether the given operation code is an array operation. */ + def isArrayOp(code: Int): Boolean = + isArrayNew(code) | isArrayLength(code) | isArrayGet(code) | isArraySet(code) + + def isArrayNew(code: Int): Boolean = code match { + case NEW_ZARRAY | NEW_BARRAY | NEW_SARRAY | NEW_CARRAY | + NEW_IARRAY | NEW_LARRAY | NEW_FARRAY | NEW_DARRAY | + NEW_OARRAY => true + case _ => false + } + + def isArrayLength(code: Int): Boolean = code match { + case ZARRAY_LENGTH | BARRAY_LENGTH | SARRAY_LENGTH | CARRAY_LENGTH | + IARRAY_LENGTH | LARRAY_LENGTH | FARRAY_LENGTH | DARRAY_LENGTH | + OARRAY_LENGTH | LENGTH => true + case _ => false + } + + def isArrayGet(code: Int): Boolean = code match { + case ZARRAY_GET | BARRAY_GET | SARRAY_GET | CARRAY_GET | + IARRAY_GET | LARRAY_GET | FARRAY_GET | DARRAY_GET | + OARRAY_GET | APPLY => true + case _ => false + } + + def isArraySet(code: Int): Boolean = code match { + case ZARRAY_SET | BARRAY_SET | SARRAY_SET | CARRAY_SET | + IARRAY_SET | LARRAY_SET | FARRAY_SET | DARRAY_SET | + OARRAY_SET | UPDATE => true + case _ => false + } + + /** Check whether the given code is a comparison operator */ + def isComparisonOp(code: Int): Boolean = code match { + case ID | NI | EQ | NE | + LT | LE | GT | GE => true + + case _ => false + } + def isUniversalEqualityOp(code: Int): Boolean = (code == EQ) || (code == NE) + def isReferenceEqualityOp(code: Int): Boolean = (code == ID) || (code == NI) + + def isArithmeticOp(code: Int): Boolean = code match { + case POS | NEG | NOT => true; // unary + case ADD | SUB | MUL | + DIV | MOD => true; // binary + case OR | XOR | AND | + LSL | LSR | ASR => true; // bitwise + case _ => false + } + + def isLogicalOp(code: Int): Boolean = code match { + case ZNOT | ZAND | ZOR => true + case _ => false + } + + def isShiftOp(code: Int): Boolean = code match { + case LSL | LSR | ASR => true + case _ => false + } + + def isBitwiseOp(code: Int): Boolean = code match { + case OR | XOR | AND => true + case _ => false + } + + /** If code is a coercion primitive, the result type */ + def generatedKind(code: Int): BType = code match { + case B2B | C2B | S2B | I2B | L2B | F2B | D2B => BType.BYTE + case B2C | C2C | S2C | I2C | L2C | F2C | D2C => BType.CHAR + case B2S | C2S | S2S | I2S | L2S | F2S | D2S => BType.SHORT + case B2I | C2I | S2I | I2I | L2I | F2I | D2I => BType.INT + case B2L | C2L | S2L | I2L | L2L | F2L | D2L => BType.LONG + case B2F | C2F | S2F | I2F | L2F | F2F | D2F => BType.FLOAT + case B2D | C2D | S2D | I2D | L2D | F2D | D2D => BType.DOUBLE + } + + def isPrimitive(sym: Symbol): Boolean = primitives contains sym + +} + From 3b96392ed5e20364e108817dd7ae73dd36c34726 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Fri, 7 Feb 2014 16:09:40 +0100 Subject: [PATCH 3/8] adding BytecodeWriters --- .../dotc/backend/jvm/BytecodeWriters.scala | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100755 src/dotty/tools/dotc/backend/jvm/BytecodeWriters.scala diff --git a/src/dotty/tools/dotc/backend/jvm/BytecodeWriters.scala b/src/dotty/tools/dotc/backend/jvm/BytecodeWriters.scala new file mode 100755 index 000000000000..6aea13233773 --- /dev/null +++ b/src/dotty/tools/dotc/backend/jvm/BytecodeWriters.scala @@ -0,0 +1,144 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Martin Odersky + */ + +package dotty.tools +package dotc +package backend.jvm + +import java.io.{ DataOutputStream, FileOutputStream, IOException, OutputStream, File => JFile } +import scala.tools.nsc.io._ +import java.util.jar.Attributes.Name +import scala.language.postfixOps + +/** Can't output a file due to the state of the file system. */ +class FileConflictException(msg: String, val file: AbstractFile) extends IOException(msg) + +/** For the last mile: turning generated bytecode in memory into + * something you can use. Has implementations for writing to class + * files, jars, and disassembled/javap output. + */ +trait BytecodeWriters { + + def outputDirectory(sym: Symbol): AbstractFile = + settings.outputDirs outputDirFor enteringFlatten(sym.sourceFile) + + /** + * @param clsName cls.getName + */ + def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { + def ensureDirectory(dir: AbstractFile): AbstractFile = + if (dir.isDirectory) dir + else throw new FileConflictException(s"${base.path}/$clsName$suffix: ${dir.path} is not a directory", dir) + var dir = base + val pathParts = clsName.split("[./]").toList + for (part <- pathParts.init) dir = ensureDirectory(dir) subdirectoryNamed part + ensureDirectory(dir) fileNamed pathParts.last + suffix + } + def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = + getFile(outputDirectory(sym), clsName, suffix) + + def factoryNonJarBytecodeWriter(): BytecodeWriter = { + val emitAsmp = settings.Ygenasmp.isSetByUser + val doDump = settings.Ydumpclasses.isSetByUser + (emitAsmp, doDump) match { + case (false, false) => new ClassBytecodeWriter { } + case (false, true ) => new ClassBytecodeWriter with DumpBytecodeWriter { } + case (true, false) => new ClassBytecodeWriter with AsmpBytecodeWriter + case (true, true ) => new ClassBytecodeWriter with AsmpBytecodeWriter with DumpBytecodeWriter { } + } + } + + trait BytecodeWriter { + def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile): Unit + def close(): Unit = () + } + + class DirectToJarfileWriter(jfile: JFile) extends BytecodeWriter { + val jarMainAttrs = ( + if (settings.mainClass.isDefault) Nil + else List(Name.MAIN_CLASS -> settings.mainClass.value) + ) + val writer = new Jar(jfile).jarWriter(jarMainAttrs: _*) + + def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) { + assert(outfile == null, + "The outfile formal param is there just because ClassBytecodeWriter overrides this method and uses it.") + val path = jclassName + ".class" + val out = writer.newOutputStream(path) + + try out.write(jclassBytes, 0, jclassBytes.length) + finally out.flush() + + informProgress("added " + label + path + " to jar") + } + override def close() = writer.close() + } + + /* + * The ASM textual representation for bytecode overcomes disadvantages of javap ouput in three areas: + * (a) pickle dingbats undecipherable to the naked eye; + * (b) two constant pools, while having identical contents, are displayed differently due to physical layout. + * (c) stack maps (classfile version 50 and up) are displayed in encoded form by javap, + * their expansion by ASM is more readable. + * + * */ + trait AsmpBytecodeWriter extends BytecodeWriter { + import scala.tools.asm + + private val baseDir = Directory(settings.Ygenasmp.value).createDirectory() + + private def emitAsmp(jclassBytes: Array[Byte], asmpFile: io.File) { + val pw = asmpFile.printWriter() + try { + val cnode = new asm.tree.ClassNode() + val cr = new asm.ClassReader(jclassBytes) + cr.accept(cnode, 0) + val trace = new scala.tools.asm.util.TraceClassVisitor(new java.io.PrintWriter(new java.io.StringWriter())) + cnode.accept(trace) + trace.p.print(pw) + } + finally pw.close() + } + + abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) { + super.writeClass(label, jclassName, jclassBytes, outfile) + + val segments = jclassName.split("[./]") + val asmpFile = segments.foldLeft(baseDir: Path)(_ / _) changeExtension "asmp" toFile; + + asmpFile.parent.createDirectory() + emitAsmp(jclassBytes, asmpFile) + } + } + + trait ClassBytecodeWriter extends BytecodeWriter { + def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) { + assert(outfile != null, + "Precisely this override requires its invoker to hand out a non-null AbstractFile.") + val outstream = new DataOutputStream(outfile.bufferedOutput) + + try outstream.write(jclassBytes, 0, jclassBytes.length) + finally outstream.close() + informProgress("wrote '" + label + "' to " + outfile) + } + } + + trait DumpBytecodeWriter extends BytecodeWriter { + val baseDir = Directory(settings.Ydumpclasses.value).createDirectory() + + abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) { + super.writeClass(label, jclassName, jclassBytes, outfile) + + val pathName = jclassName + val dumpFile = pathName.split("[./]").foldLeft(baseDir: Path) (_ / _) changeExtension "class" toFile; + dumpFile.parent.createDirectory() + val outstream = new DataOutputStream(new FileOutputStream(dumpFile.path)) + + try outstream.write(jclassBytes, 0, jclassBytes.length) + finally outstream.close() + } + } +} + From 8d53f95200b75ebf17efac02a9ecb0acd4b76868 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Fri, 7 Feb 2014 16:16:38 +0100 Subject: [PATCH 4/8] addendum to scalaPrimitives --- src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala b/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala index bf7f70eb72e3..f8a6d06e3792 100755 --- a/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala +++ b/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala @@ -8,6 +8,7 @@ package dotc package backend.jvm import scala.collection.{ mutable, immutable } +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 4bacb4f338b2e192c9b05543be858ce2ea3f2a07 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Fri, 7 Feb 2014 09:12:06 +0100 Subject: [PATCH 5/8] typo on ClassfileParser --- src/dotty/tools/dotc/core/pickling/ClassfileParser.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 src/dotty/tools/dotc/core/pickling/ClassfileParser.scala diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala old mode 100644 new mode 100755 index f87d91597e53..4c45b68040ea --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -52,7 +52,7 @@ class ClassfileParser( case e: RuntimeException => if (debug) e.printStackTrace() throw new IOException( - s"""class file $classfile is broken, reading aborted with $e.getClass + s"""class file $classfile is broken, reading aborted with ${e.getClass} |${Option(e.getMessage).getOrElse("")}""".stripMargin) } From af75a7cb4acb03ca4ffac7124e8f090c6663ee78 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Fri, 7 Feb 2014 16:18:43 +0100 Subject: [PATCH 6/8] reusing TypeNames interning for GenBCode --- src/dotty/tools/dotc/core/Names.scala | 32 ++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/dotty/tools/dotc/core/Names.scala diff --git a/src/dotty/tools/dotc/core/Names.scala b/src/dotty/tools/dotc/core/Names.scala old mode 100644 new mode 100755 index 30f82e05e1a3..943f545614a6 --- a/src/dotty/tools/dotc/core/Names.scala +++ b/src/dotty/tools/dotc/core/Names.scala @@ -197,7 +197,7 @@ object Names { private final val fillFactor = 0.7 /** Memory to store all names sequentially. */ - private var chrs: Array[Char] = new Array[Char](InitialNameSize) + var chrs: Array[Char] = new Array[Char](InitialNameSize) /** The number of characters filled. */ private var nc = 0 @@ -287,6 +287,36 @@ object Names { } } + /** + * Used only by the GenBCode backend, to represent bytecode-level types in a way that makes equals() and hashCode() efficient. + * For bytecode-level types of OBJECT sort, its internal name (not its descriptor) is stored. + * For those of ARRAY sort, its descriptor is stored ie has a leading '[' + * For those of METHOD sort, its descriptor is stored ie has a leading '(' + * + * can-multi-thread + * TODO SI-6240 !!! JZ Really? the constructors TermName and TypeName publish unconstructed `this` references + * into the hash tables; we could observe them here before the subclass constructor completes. + */ + final def lookupTypeName(cs: Array[Char]): TypeName = lookupTypeNameIfExisting(cs, true) + + final def lookupTypeNameIfExisting(cs: Array[Char], failOnNotFound: Boolean): TypeName = { + val h = hashValue(cs, 0, cs.length) & (table.size - 1) + synchronized { + val next = table(h) + var name = next + while (name ne null) { + if (name.length == len && equals(name.start, cs, 0, cs.length)) + return name.toTypeName + name = name.next + } + if (failOnNotFound) { + throw new RuntimeException(s"lookup of non-existing TypeName: ${new String(cs)}") + } else { + return null + } + } + } + /** Create a type name from the characters in cs[offset..offset+len-1]. * Assume they are already encoded. */ From b6d658091a19518f6028ed510dc69460883195c3 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Fri, 7 Feb 2014 19:48:44 +0100 Subject: [PATCH 7/8] part 1 of N, making GenBCode compilable --- src/dotty/tools/dotc/Compiler.scala | 2 +- .../dotc/backend/jvm/BCodeBodyBuilder.scala | 113 ++++++++++++++++-- .../tools/dotc/backend/jvm/BCodeGlue.scala | 23 ++-- .../tools/dotc/backend/jvm/BCodeHelpers.scala | 43 +++---- .../dotc/backend/jvm/BCodeIdiomatic.scala | 39 +----- .../dotc/backend/jvm/BCodeSkelBuilder.scala | 11 +- .../dotc/backend/jvm/BCodeSyncAndTry.scala | 13 +- .../tools/dotc/backend/jvm/BCodeTypes.scala | 12 +- .../tools/dotc/backend/jvm/GenBCode.scala | 53 ++++---- 9 files changed, 197 insertions(+), 112 deletions(-) mode change 100644 => 100755 src/dotty/tools/dotc/Compiler.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala old mode 100644 new mode 100755 index a4226eec24bb..2b13c72b586d --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -10,7 +10,7 @@ import reporting.ConsoleReporter class Compiler { - def phases = List(new FrontEnd) + def phases = List(new FrontEnd, new backend.jvm.GenBCode.BCodePhase) def rootContext(implicit ctx: Context): Context = { ctx.definitions.init() diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala b/src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala index a35445e6dabf..257cda03992a 100755 --- a/src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala @@ -14,6 +14,12 @@ import scala.annotation.switch import scala.tools.asm +import dotc.ast.Trees._ +import core.Types.Type +import core.StdNames +import core.Symbols.{Symbol, NoSymbol} +import core.Constants.Constant + /* * * @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/ @@ -21,16 +27,18 @@ import scala.tools.asm * */ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { - import global._ - import definitions._ + + import ast.tpd._ /* * Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions. */ - abstract class PlainBodyBuilder(cunit: CompilationUnit) extends PlainSkelBuilder(cunit) { + abstract class PlainBodyBuilder(cunit: CompilationUnit, + implicit val ctx: dotc.core.Contexts.Context) extends PlainSkelBuilder(cunit) { import icodes.TestOp import icodes.opcodes.InvokeStyle + import StdNames.nme /* If the selector type has a member with the right name, * it is the host class; otherwise the symbol's owner. @@ -218,10 +226,83 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { resKind } + /** + * 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): Int = { + val code = scalaPrimitives.getPrimitive(fun) + + def elementType = enteringTyper { + val arrayParent = tpe :: tpe.parents collectFirst { + case dotc.core.Types.TypeRef(_, ArrayClass, elem :: Nil) => elem + } + arrayParent getOrElse sys.error(fun.fullName + " : " + (tpe :: tpe.baseTypeSeq.toList).mkString(", ")) + } + + import scalaPrimitives._ + + code match { + + case APPLY => + toTypeKind(elementType) match { + case BType.BOOLEAN_TYPE => ZARRAY_GET + case BType.BYTE_TYPE => BARRAY_GET + case BType.SHORT_TYPE => SARRAY_GET + case BType.CHAR_TYPE => CARRAY_GET + case BType.INT_TYPE => IARRAY_GET + case BType.LONG_TYPE => LARRAY_GET + case BType.FLOAT_TYPE => FARRAY_GET + case BType.DOUBLE_TYPE => DARRAY_GET + case r => + assert(r.isRefOrArrayType) + OARRAY_GET + } + + case UPDATE => + toTypeKind(elementType) match { + case BType.BOOLEAN_TYPE => ZARRAY_SET + case BType.BYTE_TYPE => BARRAY_SET + case BType.SHORT_TYPE => SARRAY_SET + case BType.CHAR_TYPE => CARRAY_SET + case BType.INT_TYPE => IARRAY_SET + case BType.LONG_TYPE => LARRAY_SET + case BType.FLOAT_TYPE => FARRAY_SET + case BType.DOUBLE_TYPE => DARRAY_SET + case r => + assert(r.isRefOrArrayType) + OARRAY_SET + } + + case LENGTH => + toTypeKind(elementType) match { + case BType.BOOLEAN_TYPE => ZARRAY_LENGTH + case BType.BYTE_TYPE => BARRAY_LENGTH + case BType.SHORT_TYPE => SARRAY_LENGTH + case BType.CHAR_TYPE => CARRAY_LENGTH + case BType.INT_TYPE => IARRAY_LENGTH + case BType.LONG_TYPE => LARRAY_LENGTH + case BType.FLOAT_TYPE => FARRAY_LENGTH + case BType.DOUBLE_TYPE => DARRAY_LENGTH + case r => + assert(r.isRefOrArrayType) + OARRAY_LENGTH + } + + case _ => + code + } + } + def genPrimitiveOp(tree: Apply, expectedType: BType): BType = { val sym = tree.symbol val Apply(fun @ Select(receiver, _), _) = tree - val code = scalaPrimitives.getPrimitive(sym, receiver.tpe) + val code = getPrimitive(sym, receiver.tpe) import scalaPrimitives.{isArithmeticOp, isArrayOp, isLogicalOp, isComparisonOp} @@ -306,7 +387,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { case app : Apply => generatedType = genApply(app, expectedType) - case ApplyDynamic(qual, args) => sys.error("No invokedynamic support yet.") + // case ApplyDynamic(qual, args) => sys.error("No invokedynamic support yet.") case This(qual) => val symIsModuleClass = tree.symbol.isModuleClass @@ -359,10 +440,10 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { case Literal(value) => if (value.tag != UnitTag) (value.tag, expectedType) match { - case (IntTag, LONG ) => bc.lconst(value.longValue); generatedType = LONG - case (FloatTag, DOUBLE) => bc.dconst(value.doubleValue); generatedType = DOUBLE - case (NullTag, _ ) => bc.emit(asm.Opcodes.ACONST_NULL); generatedType = RT_NULL - case _ => genConstant(value); generatedType = tpeTK(tree) + case (dotc.core.Constants.IntTag, LONG ) => bc.lconst(value.longValue); generatedType = LONG + case (dotc.core.Constants.FloatTag, DOUBLE) => bc.dconst(value.doubleValue); generatedType = DOUBLE + case (dotc.core.Constants.NullTag, _ ) => bc.emit(asm.Opcodes.ACONST_NULL); generatedType = RT_NULL + case _ => genConstant(value); generatedType = tpeTK(tree) } case blck : Block => genBlock(blck, expectedType) @@ -434,6 +515,9 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { * Otherwise it's safe to call from multiple threads. */ def genConstant(const: Constant) { + + import dotc.core.Constants._ + (const.tag: @switch) match { case BooleanTag => bc.boolconst(const.booleanValue) @@ -825,7 +909,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { } /* Generate code that loads args into label parameters. */ - def genLoadLabelArguments(args: List[Tree], lblDef: LabelDef, gotoPos: Position) { + def genLoadLabelArguments(args: List[Tree], lblDef: LabelDef, gotoPos: dotc.util.Positions.Position) { val aps = { val params: List[Symbol] = lblDef.params.map(_.symbol) @@ -936,7 +1020,10 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { StringReference } - def genCallMethod(method: Symbol, style: InvokeStyle, hostClass0: Symbol = null, pos: Position = NoPosition) { + def genCallMethod(method: Symbol, + style: InvokeStyle, + hostClass0: Symbol = null, + pos: dotc.util.Positions.Position = dotc.util.Positions.NoPosition) { val siteSymbol = claszSymbol val hostSymbol = if (hostClass0 == null) method.owner else hostClass0; @@ -1118,7 +1205,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { tree match { case Apply(fun, args) if isPrimitive(fun.symbol) => - import scalaPrimitives.{ ZNOT, ZAND, ZOR, EQ, getPrimitive } + import scalaPrimitives.{ ZNOT, ZAND, ZOR, EQ } // lhs and rhs of test lazy val Select(lhs, _) = fun @@ -1135,7 +1222,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { genCond(rhs, success, failure) } - getPrimitive(fun.symbol) match { + scalaPrimitives.getPrimitive(fun.symbol) match { case ZNOT => genCond(lhs, failure, success) case ZAND => genZandOrZor(and = true) case ZOR => genZandOrZor(and = false) diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala b/src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala index d99275919225..2e1102d2d307 100755 --- a/src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala @@ -11,6 +11,10 @@ import scala.tools.asm import scala.annotation.switch import scala.collection.{ immutable, mutable } +import dotc.ast.Trees.Tree +import dotc.core.Types.Type +import dotc.core.Symbols.{Symbol, NoSymbol} + /* * Immutable representations of bytecode-level types. * @@ -18,13 +22,12 @@ import scala.collection.{ immutable, mutable } * @version 1.0 * */ -abstract class BCodeGlue extends SubComponent { - - import global._ +abstract class BCodeGlue { object BType { - import global.chrs + import core.Names + import Names.chrs // ------------- sorts ------------- @@ -124,7 +127,7 @@ abstract class BCodeGlue extends SubComponent { * must-single-thread */ def getMethodType(methodDescriptor: String): BType = { - val n = global.newTypeName(methodDescriptor) + val n = Names.typeName(methodDescriptor) new BType(BType.METHOD, n.start, n.length) // TODO assert isValidMethodDescriptor } @@ -138,7 +141,7 @@ abstract class BCodeGlue extends SubComponent { * must-single-thread */ def getMethodType(returnType: BType, argumentTypes: Array[BType]): BType = { - val n = global.newTypeName(getMethodDescriptor(returnType, argumentTypes)) + val n = Names.typeName(getMethodDescriptor(returnType, argumentTypes)) new BType(BType.METHOD, n.start, n.length) } @@ -206,7 +209,7 @@ abstract class BCodeGlue extends SubComponent { * must-single-thread */ def getReturnType(methodDescriptor: String): BType = { - val n = global.newTypeName(methodDescriptor) + val n = Names.typeName(methodDescriptor) val delta = n.pos(')') // `delta` is relative to the Name's zero-based start position, not a valid index into chrs. assert(delta < n.length, s"not a valid method descriptor: $methodDescriptor") getType(n.start + delta + 1) @@ -248,7 +251,7 @@ abstract class BCodeGlue extends SubComponent { */ final class BType(val sort: Int, val off: Int, val len: Int) { - import global.chrs + import core.Names.chrs /* * can-multi-thread @@ -619,7 +622,7 @@ abstract class BCodeGlue extends SubComponent { * * must-single-thread */ - def brefType(iname: String): BType = { brefType(newTypeName(iname.toCharArray(), 0, iname.length())) } + def brefType(iname: String): BType = { brefType(dotc.core.Names.typeName(iname.toCharArray(), 0, iname.length())) } /* * Creates a BType token for the TypeName received as argument. @@ -627,7 +630,7 @@ abstract class BCodeGlue extends SubComponent { * * can-multi-thread */ - def brefType(iname: TypeName): BType = { BType.getObjectType(iname.start, iname.length) } + def brefType(iname: core.Names.TypeName): BType = { BType.getObjectType(iname.start, iname.length) } // due to keyboard economy only val UNIT = BType.VOID_TYPE diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala b/src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala index 54882d7ef053..b81c64928c35 100755 --- a/src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeHelpers.scala @@ -12,6 +12,12 @@ import scala.annotation.switch import scala.collection.{ immutable, mutable } import scala.tools.nsc.io.AbstractFile +import dotc.ast.Trees._ + +import dotc.core.StdNames +import dotc.core.Types.Type +import dotc.core.Symbols.{Symbol, NoSymbol} + /* * Traits encapsulating functionality to convert Scala AST Trees into ASM ClassNodes. * @@ -21,7 +27,7 @@ import scala.tools.nsc.io.AbstractFile */ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { - import global._ + import ast.tpd._ /* * must-single-thread @@ -79,13 +85,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { /* * This method is thread re-entrant because chrs never grows during its operation (that's because all TypeNames being looked up have already been entered). - * To stress this point, rather than using `newTypeName()` we use `lookupTypeName()` + * To stress this point, rather than using `Names.typeName()` we use `lookupTypeName()` * * can-multi-thread */ override def getCommonSuperClass(inameA: String, inameB: String): String = { - val a = brefType(lookupTypeName(inameA.toCharArray)) - val b = brefType(lookupTypeName(inameB.toCharArray)) + val a = brefType(core.Names.lookupTypeName(inameA.toCharArray)) + val b = brefType(core.Names.lookupTypeName(inameB.toCharArray)) val lca = jvmWiseLUB(a, b) val lcaName = lca.getInternalName // don't call javaName because that side-effects innerClassBuffer. assert(lcaName != "scala/Any") @@ -134,11 +140,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { */ object isJavaEntryPoint { + import dotc.core.Types.{MethodType, PolyType} + /* * must-single-thread */ def apply(sym: Symbol, csymCompUnit: CompilationUnit): Boolean = { - def fail(msg: String, pos: Position = sym.pos) = { + def fail(msg: String, pos: dotc.util.Positions.Position = sym.pos) = { csymCompUnit.warning(sym.pos, sym.name + s" has a main method with parameter type Array[String], but ${sym.fullName('.')} will not be a runnable program.\n Reason: $msg" @@ -225,7 +233,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { /* * must-single-thread */ - def fieldSymbols(cls: Symbol): List[Symbol] = { + def fieldSymbols(cls: Symbol)(implicit ctx: core.Contexts.Context): List[Symbol] = { for (f <- cls.info.decls.toList ; if !f.isMethod && f.isTerm && !f.isModule ) yield f; @@ -234,7 +242,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { /* * can-multi-thread */ - def methodSymbols(cd: ClassDef): List[Symbol] = { + def methodSymbols(cd: TypeDef): List[Symbol] = { cd.impl.body collect { case dd: DefDef => dd.symbol } } @@ -323,14 +331,14 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { * can-multi-thread */ def pickleMarkerLocal = { - createJAttribute(tpnme.ScalaSignatureATTR.toString, versionPickle.bytes, 0, versionPickle.writeIndex) + createJAttribute(StdNames.tpnme.ScalaSignatureATTR.toString, versionPickle.bytes, 0, versionPickle.writeIndex) } /* * can-multi-thread */ def pickleMarkerForeign = { - createJAttribute(tpnme.ScalaATTR.toString, new Array[Byte](0), 0, 0) + createJAttribute(StdNames.tpnme.ScalaATTR.toString, new Array[Byte](0), 0, 0) } /* Returns a ScalaSignature annotation if it must be added to this class, none otherwise. @@ -493,10 +501,10 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { } } - import definitions.ArrayClass + import dotc.core.Types.{ThisType, ConstantType, TypeRef, ClassInfo} // Call to .normalize fixes #3003 (follow type aliases). Otherwise, primitiveOrArrayOrRefType() would return ObjectReference. - t.normalize match { + t match { case ThisType(sym) => if (sym == ArrayClass) ObjectReference @@ -510,17 +518,10 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { if (sym == ArrayClass) arrayOf(toTypeKind(args.head)) else primitiveOrRefType2(sym) - case ClassInfoType(_, _, sym) => + case ClassInfo(_, _, sym) => assert(sym != ArrayClass, "ClassInfoType to ArrayClass!") primitiveOrRefType(sym) - // !!! Iulian says types which make no sense after erasure should not reach here, which includes the ExistentialType, AnnotatedType, RefinedType. - case ExistentialType(_, t) => toTypeKind(t) // TODO shouldn't get here but the following does: akka-actor/src/main/scala/akka/util/WildcardTree.scala - case AnnotatedType(_, w) => toTypeKind(w) // TODO test/files/jvm/annotations.scala causes an AnnotatedType to reach here. - case RefinedType(parents, _) => parents map toTypeKind reduceLeft jvmWiseLUB - - // For sure WildcardTypes shouldn't reach here either, but when debugging such situations this may come in handy. - // case WildcardType => REFERENCE(ObjectClass) case norm => abort( s"Unknown type: $t, $norm [${t.getClass}, ${norm.getClass}] TypeRef? ${t.isInstanceOf[TypeRef]}" ) @@ -879,7 +880,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { ) && !(meth.throwsAnnotations contains definitions.RemoteExceptionClass) ) if (needsAnnotation) { - val c = Constant(definitions.RemoteExceptionClass.tpe) + val c = core.Constants.Constant(definitions.RemoteExceptionClass.tpe) val arg = Literal(c) setType c.tpe meth.addAnnotation(appliedType(definitions.ThrowsClass, c.tpe), arg) } @@ -956,7 +957,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { debuglog(s"Dumping mirror class for object: $moduleClass") val linkedClass = moduleClass.companionClass - lazy val conflictingNames: Set[Name] = { + lazy val conflictingNames: Set[core.Names.Name] = { (linkedClass.info.members collect { case sym if sym.name.isTermName => sym.name }).toSet } debuglog(s"Potentially conflicting names for forwarders: $conflictingNames") diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala b/src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala index 5090716db32c..3e5c0d2ce169 100755 --- a/src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeIdiomatic.scala @@ -12,6 +12,10 @@ import scala.annotation.switch import scala.collection.{ immutable, mutable } import collection.convert.Wrappers.JListWrapper +import dotc.ast.Trees.Tree +import dotc.core.Types.Type +import dotc.core.Symbols.{Symbol, NoSymbol} + /* * A high-level facade to the ASM API for bytecode generation. * @@ -21,8 +25,6 @@ import collection.convert.Wrappers.JListWrapper */ abstract class BCodeIdiomatic extends BCodeGlue { - import global._ - val classfileVersion: Int = settings.target.value match { case "jvm-1.5" => asm.Opcodes.V1_5 case "jvm-1.6" => asm.Opcodes.V1_6 @@ -676,39 +678,6 @@ abstract class BCodeIdiomatic extends BCodeGlue { ) } - /* - * Collects (in `result`) all LabelDef nodes enclosed (directly or not) by each node it visits. - * - * In other words, this traverser prepares a map giving - * all labelDefs (the entry-value) having a Tree node (the entry-key) as ancestor. - * The entry-value for a LabelDef entry-key always contains the entry-key. - * - */ - class LabelDefsFinder extends Traverser { - val result = mutable.Map.empty[Tree, List[LabelDef]] - var acc: List[LabelDef] = Nil - - /* - * can-multi-thread - */ - override def traverse(tree: Tree) { - val saved = acc - acc = Nil - super.traverse(tree) - // acc contains all LabelDefs found under (but not at) `tree` - tree match { - case lblDf: LabelDef => acc ::= lblDf - case _ => () - } - if (acc.isEmpty) { - acc = saved - } else { - result += (tree -> acc) - acc = acc ::: saved - } - } - } - implicit class InsnIterMethodNode(mnode: asm.tree.MethodNode) { @inline final def foreachInsn(f: (asm.tree.AbstractInsnNode) => Unit) { mnode.instructions.foreachInsn(f) } } diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala b/src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala index 95823dbfd010..c0e04cc5e0b9 100755 --- a/src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeSkelBuilder.scala @@ -15,6 +15,10 @@ import scala.annotation.switch import scala.tools.asm +import dotc.ast.Trees._ +import dotc.core.Types.Type +import dotc.core.Symbols.{Symbol, NoSymbol} + /* * * @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/ @@ -22,7 +26,6 @@ import scala.tools.asm * */ abstract class BCodeSkelBuilder extends BCodeHelpers { - import global._ /* * There's a dedicated PlainClassBuilder for each CompilationUnit, @@ -52,6 +55,8 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { with BCPickles with BCJGenSigGen { + import ast.tpd._ + // Strangely I can't find this in the asm code 255, but reserving 1 for "this" final val MaximumJvmParameters = 254 @@ -86,7 +91,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { /* ---------------- helper utils for generating classes and fiels ---------------- */ - def genPlainClass(cd: ClassDef) { + def genPlainClass(cd: TypeDef) { assert(cnode == null, "GenBCode detected nested methods.") innerClassBufferASM.clear() @@ -372,7 +377,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { * The invoker must make sure inner classes are tracked for the sym's tpe. */ def makeLocal(tk: BType, name: String): Symbol = { - val locSym = methSymbol.newVariable(cunit.freshTermName(name), NoPosition, Flags.SYNTHETIC) // setInfo tpe + val locSym = methSymbol.newVariable(cunit.freshTermName(name), dotc.util.Positions.NoPosition, Flags.SYNTHETIC) // setInfo tpe makeLocal(locSym, tk) locSym } diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala b/src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala index f50a70c83773..0b8ff7a578e0 100755 --- a/src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeSyncAndTry.scala @@ -14,6 +14,10 @@ import scala.annotation.switch import scala.tools.asm +import dotc.ast.Trees._ +import dotc.core.Types.Type +import dotc.core.Symbols.{Symbol, NoSymbol} + /* * * @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/ @@ -21,13 +25,14 @@ import scala.tools.asm * */ abstract class BCodeSyncAndTry extends BCodeBodyBuilder { - import global._ - /* * Functionality to lower `synchronized` and `try` expressions. */ - abstract class SyncAndTryBuilder(cunit: CompilationUnit) extends PlainBodyBuilder(cunit) { + abstract class SyncAndTryBuilder(cunit: CompilationUnit, + ctx: dotc.core.Contexts.Context) extends PlainBodyBuilder(cunit, ctx) { + + import ast.tpd._ def genSynchronized(tree: Apply, expectedType: BType): BType = { val Apply(fun, args) = tree @@ -181,6 +186,8 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder { val Try(block, catches, finalizer) = tree val kind = tpeTK(tree) + import ast.Trees.{Typed, Ident, Bind} + val caseHandlers: List[EHClause] = for (CaseDef(pat, _, caseBody) <- catches) yield { pat match { diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala b/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala index 516c09139f77..90e1d72e95ee 100755 --- a/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala @@ -10,6 +10,13 @@ package backend.jvm import scala.tools.asm import scala.collection.{ immutable, mutable } +import dotc.ast.Trees.Tree +import dotc.core.Types.Type +import dotc.core.StdNames +import dotc.core.Symbols.{Symbol, NoSymbol} + +import StdNames.nme + /* * Utilities to mediate between types as represented in Scala ASTs and ASM trees. * @@ -19,8 +26,6 @@ import scala.collection.{ immutable, mutable } */ abstract class BCodeTypes extends BCodeIdiomatic { - import global._ - // when compiling the Scala library, some assertions don't hold (e.g., scala.Boolean has null superClass although it's not an interface) val isCompilingStdLib = !(settings.sourcepath.isDefault) @@ -72,7 +77,6 @@ abstract class BCodeTypes extends BCodeIdiomatic { * must-single-thread */ def initBCodeTypes() { - import definitions._ primitiveTypeMap = Map( @@ -743,7 +747,7 @@ abstract class BCodeTypes extends BCodeIdiomatic { * when the inner class should not get an index in the constant pool. * That means non-member classes (anonymous). See Section 4.7.5 in the JVMS. */ - def outerName(innerSym: Symbol): Name = { + def outerName(innerSym: Symbol): core.Names.Name = { if (innerSym.originalEnclosingMethod != NoSymbol) null else { diff --git a/src/dotty/tools/dotc/backend/jvm/GenBCode.scala b/src/dotty/tools/dotc/backend/jvm/GenBCode.scala index 0090e6a78d75..fb281830f79c 100755 --- a/src/dotty/tools/dotc/backend/jvm/GenBCode.scala +++ b/src/dotty/tools/dotc/backend/jvm/GenBCode.scala @@ -14,6 +14,10 @@ import scala.annotation.switch import scala.tools.asm +import dotc.ast.Trees +import dotc.core.Types.Type +import dotc.core.Symbols.{Symbol, NoSymbol} + /* * Prepare in-memory representations of classfiles using the ASM Tree API, and serialize them to disk. * @@ -43,18 +47,14 @@ import scala.tools.asm * @version 1.0 * */ -abstract class GenBCode extends BCodeSyncAndTry { - import global._ - - val phaseName = "jvm" - - override def newPhase(prev: Phase) = new BCodePhase(prev) +object GenBCode extends BCodeSyncAndTry { - final class PlainClassBuilder(cunit: CompilationUnit) extends SyncAndTryBuilder(cunit) + final class PlainClassBuilder(cunit: CompilationUnit, + ctx: dotc.core.Contexts.Context) extends SyncAndTryBuilder(cunit) - class BCodePhase(prev: Phase) extends StdPhase(prev) { + class BCodePhase extends dotc.core.Phases.Phase { - override def name = phaseName + override def name = "jvm" override def description = "Generate bytecode from ASTs using the ASM library" override def erasedTypes = true @@ -64,7 +64,7 @@ abstract class GenBCode extends BCodeSyncAndTry { /* ---------------- q1 ---------------- */ - case class Item1(arrivalPos: Int, cd: ClassDef, cunit: CompilationUnit) { + case class Item1(arrivalPos: Int, cd: ast.Trees.TypeDef, cunit: CompilationUnit) { def isPoison = { arrivalPos == Int.MaxValue } } private val poison1 = Item1(Int.MaxValue, null, null) @@ -118,7 +118,8 @@ abstract class GenBCode extends BCodeSyncAndTry { /* * Pipeline that takes ClassDefs from queue-1, lowers them into an intermediate form, placing them on queue-2 */ - class Worker1(needsOutFolder: Boolean) { + class Worker1(needsOutFolder: Boolean, + implicit val ctx: dotc.core.Contexts.Context) { val caseInsensitively = mutable.Map.empty[String, Symbol] @@ -175,7 +176,7 @@ abstract class GenBCode extends BCodeSyncAndTry { } else null // -------------- "plain" class -------------- - val pcb = new PlainClassBuilder(cunit) + val pcb = new PlainClassBuilder(cunit, ctx) pcb.genPlainClass(cd) val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName, cunit) else null; val plainC = pcb.cnode @@ -262,7 +263,7 @@ abstract class GenBCode extends BCodeSyncAndTry { * (c) tear down (closing the classfile-writer and clearing maps) * */ - override def run() { + def runOn(units: List[CompilationUnit])(implicit ctx: dotc.core.Contexts.Context): Unit = { arrivalPos = 0 // just in case scalaPrimitives.init @@ -274,7 +275,7 @@ abstract class GenBCode extends BCodeSyncAndTry { beanInfoCodeGen = new JBeanInfoBuilder val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter] - buildAndSendToDisk(needsOutfileForSymbol) + buildAndSendToDisk(needsOutfileForSymbol, units, ctx) // closing output files. bytecodeWriter.close() @@ -296,6 +297,8 @@ abstract class GenBCode extends BCodeSyncAndTry { clearBCodeTypes() } + override def run(implicit ctx: dotc.core.Contexts.Context): Unit = unsupported("run()") + /* * Sequentially: * (a) place all ClassDefs in queue-1 @@ -303,18 +306,20 @@ abstract class GenBCode extends BCodeSyncAndTry { * (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) { + private def buildAndSendToDisk(needsOutFolder: Boolean, + units: List[CompilationUnit], + ctx: dotc.core.Contexts.Context) { - feedPipeline1() - (new Worker1(needsOutFolder)).run() + feedPipeline1(units) + (new Worker1(needsOutFolder, ctx)).run() (new Worker2).run() drainQ3() } /* Feed pipeline-1: place all ClassDefs on q1, recording their arrival position. */ - private def feedPipeline1() { - super.run() + private def feedPipeline1(units: List[CompilationUnit]) { + units forech apply q1 add poison1 } @@ -363,11 +368,15 @@ abstract class GenBCode extends BCodeSyncAndTry { override def apply(cunit: CompilationUnit): Unit = { - def gen(tree: Tree) { + def gen(tree: Trees.Tree) { + + import Trees.{PackageDef, TypeDef} + tree match { - case EmptyTree => () + case ast.untpd.EmptyTree => () + case ast.tpd.EmptyTree => () case PackageDef(_, stats) => stats foreach gen - case cd: ClassDef => + case cd: TypeDef => q1 add Item1(arrivalPos, cd, cunit) arrivalPos += 1 } From 051ad46f6e94bbc53a16d64e858e1e3732a7bca5 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Fri, 7 Feb 2014 20:43:01 +0100 Subject: [PATCH 8/8] making definitions flow into where it's needed --- .../tools/dotc/backend/jvm/BCodeTypes.scala | 49 ++++++++++------ .../tools/dotc/backend/jvm/GenBCode.scala | 2 +- .../dotc/backend/jvm/scalaPrimitives.scala | 58 ++++++++++++------- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala b/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala index 90e1d72e95ee..498788a23b73 100755 --- a/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala +++ b/src/dotty/tools/dotc/backend/jvm/BCodeTypes.scala @@ -76,27 +76,29 @@ abstract class BCodeTypes extends BCodeIdiomatic { /* * must-single-thread */ - def initBCodeTypes() { + def initBCodeTypes(implicit ctx: core.Contexts.Context) { + + import core.Symbols.defn primitiveTypeMap = Map( - UnitClass -> UNIT, - BooleanClass -> BOOL, - CharClass -> CHAR, - ByteClass -> BYTE, - ShortClass -> SHORT, - IntClass -> INT, - LongClass -> LONG, - FloatClass -> FLOAT, - DoubleClass -> DOUBLE + defn.UnitClass -> UNIT, + defn.BooleanClass -> BOOL, + defn.CharClass -> CHAR, + defn.ByteClass -> BYTE, + defn.ShortClass -> SHORT, + defn.IntClass -> INT, + defn.LongClass -> LONG, + defn.FloatClass -> FLOAT, + defn.DoubleClass -> DOUBLE ) phantomTypeMap = Map( - NothingClass -> RT_NOTHING, - NullClass -> RT_NULL, - NothingClass -> RT_NOTHING, // we map on purpose to RT_NOTHING, getting rid of the distinction compile-time vs. runtime for NullClass. - NullClass -> RT_NULL // ditto. + defn.NothingClass -> RT_NOTHING, + defn.NullClass -> RT_NULL, + defn.NothingClass -> RT_NOTHING, // we map on purpose to RT_NOTHING, getting rid of the distinction compile-time vs. runtime for NullClass. + defn.NullClass -> RT_NULL // ditto. ) boxResultType = @@ -109,7 +111,16 @@ abstract class BCodeTypes extends BCodeIdiomatic { // boxed classes are looked up in the `exemplars` map by jvmWiseLUB(). // Other than that, they aren't needed there (e.g., `isSubtypeOf()` special-cases boxed classes, similarly for others). - val boxedClasses = List(BoxedBooleanClass, BoxedCharacterClass, BoxedByteClass, BoxedShortClass, BoxedIntClass, BoxedLongClass, BoxedFloatClass, BoxedDoubleClass) + val boxedClasses = List( + defn.BoxedBooleanClass, + defn.BoxedCharClass, + defn.BoxedByteClass, + defn.BoxedShortClass, + defn.BoxedIntClass, + defn.BoxedLongClass, + defn.BoxedFloatClass, + defn.BoxedDoubleClass + ) for(csym <- boxedClasses) { val key = brefType(csym.javaBinaryName.toTypeName) val tr = buildExemplar(key, csym) @@ -161,12 +172,12 @@ abstract class BCodeTypes extends BCodeIdiomatic { BType.getMethodType("()V") // necessary for JCodeMethodN.genStartConcat BType.getMethodType("()Ljava/lang/String;") // necessary for JCodeMethodN.genEndConcat - PartialFunctionReference = exemplar(PartialFunctionClass).c + PartialFunctionReference = exemplar(defn.PartialFunctionClass).c for(idx <- 0 to definitions.MaxFunctionArity) { - FunctionReference(idx) = exemplar(FunctionClass(idx)) - AbstractFunctionReference(idx) = exemplar(AbstractFunctionClass(idx)) + FunctionReference(idx) = exemplar(defn.FunctionClass(idx)) + AbstractFunctionReference(idx) = exemplar(defn.AbstractFunctionClass(idx)) abstractFunctionArityMap += (AbstractFunctionReference(idx).c -> idx) - AbstractPartialFunctionReference = exemplar(AbstractPartialFunctionClass).c + AbstractPartialFunctionReference = exemplar(defn.AbstractPartialFunctionClass).c } // later a few analyses (e.g. refreshInnerClasses) will look up BTypes based on descriptors in instructions diff --git a/src/dotty/tools/dotc/backend/jvm/GenBCode.scala b/src/dotty/tools/dotc/backend/jvm/GenBCode.scala index fb281830f79c..e581919fcefc 100755 --- a/src/dotty/tools/dotc/backend/jvm/GenBCode.scala +++ b/src/dotty/tools/dotc/backend/jvm/GenBCode.scala @@ -267,7 +267,7 @@ object GenBCode extends BCodeSyncAndTry { arrivalPos = 0 // just in case scalaPrimitives.init - initBCodeTypes() + initBCodeTypes // initBytecodeWriter invokes fullName, thus we have to run it before the typer-dependent thread is activated. bytecodeWriter = initBytecodeWriter(cleanup.getEntryPoints) diff --git a/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala b/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala index f8a6d06e3792..63448aabb648 100755 --- a/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala +++ b/src/dotty/tools/dotc/backend/jvm/scalaPrimitives.scala @@ -195,33 +195,40 @@ object scalaPrimitives { } /** Initialize the primitive map */ - def init() { + def init(implicit ctx: core.Contexts.Context) { + + import core.Symbols.defn + primitives.clear() // scala.Any - addPrimitive(Any_==, EQ) - addPrimitive(Any_!=, NE) - addPrimitive(Any_isInstanceOf, IS) - addPrimitive(Any_asInstanceOf, AS) - addPrimitive(Any_##, HASH) + 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(Object_eq, ID) - addPrimitive(Object_ne, NI) - addPrimitive(Object_==, EQ) - addPrimitive(Object_!=, NE) - addPrimitive(Object_synchronized, SYNCHRONIZED) - addPrimitive(Object_isInstanceOf, IS) - addPrimitive(Object_asInstanceOf, AS) + addPrimitive(defn.Object_eq, ID) + addPrimitive(defn.Object_ne, NI) + addPrimitive(defn.Object_==, EQ) + addPrimitive(defn.Object_!=, NE) + addPrimitive(defn.Object_synchronized, SYNCHRONIZED) + addPrimitive(defn.Object_isInstanceOf, IS) + addPrimitive(defn.Object_asInstanceOf, AS) // java.lang.String - addPrimitive(String_+, CONCAT) + addPrimitive(defn.String_+, CONCAT) + + import core.StdNames.nme // scala.Array + val ArrayClass = defn.ArrayClass addPrimitives(ArrayClass, nme.length, LENGTH) addPrimitives(ArrayClass, nme.apply, APPLY) addPrimitives(ArrayClass, nme.update, UPDATE) // scala.Boolean + val BooleanClass = defn.BooleanClass addPrimitives(BooleanClass, nme.EQ, EQ) addPrimitives(BooleanClass, nme.NE, NE) addPrimitives(BooleanClass, nme.UNARY_!, ZNOT) @@ -232,6 +239,7 @@ object scalaPrimitives { addPrimitives(BooleanClass, nme.XOR, XOR) // scala.Byte + val ByteClass = defn.ByteClass addPrimitives(ByteClass, nme.EQ, EQ) addPrimitives(ByteClass, nme.NE, NE) addPrimitives(ByteClass, nme.ADD, ADD) @@ -264,6 +272,7 @@ object scalaPrimitives { addPrimitives(ByteClass, nme.toDouble, B2D) // scala.Short + val ShortClass = defn.ShortClass addPrimitives(ShortClass, nme.EQ, EQ) addPrimitives(ShortClass, nme.NE, NE) addPrimitives(ShortClass, nme.ADD, ADD) @@ -296,6 +305,7 @@ object scalaPrimitives { addPrimitives(ShortClass, nme.toDouble, S2D) // scala.Char + val CharClass = defn.CharClass addPrimitives(CharClass, nme.EQ, EQ) addPrimitives(CharClass, nme.NE, NE) addPrimitives(CharClass, nme.ADD, ADD) @@ -327,6 +337,7 @@ object scalaPrimitives { addPrimitives(CharClass, nme.toDouble, C2D) // scala.Int + val IntClass = defn.IntClass addPrimitives(IntClass, nme.EQ, EQ) addPrimitives(IntClass, nme.NE, NE) addPrimitives(IntClass, nme.ADD, ADD) @@ -358,6 +369,7 @@ object scalaPrimitives { addPrimitives(IntClass, nme.toDouble, I2D) // scala.Long + val LongClass = defn.LongClass addPrimitives(LongClass, nme.EQ, EQ) addPrimitives(LongClass, nme.NE, NE) addPrimitives(LongClass, nme.ADD, ADD) @@ -389,6 +401,7 @@ object scalaPrimitives { addPrimitives(LongClass, nme.toDouble, L2D) // scala.Float + val FloatClass = defn.FloatClass addPrimitives(FloatClass, nme.EQ, EQ) addPrimitives(FloatClass, nme.NE, NE) addPrimitives(FloatClass, nme.ADD, ADD) @@ -413,6 +426,7 @@ object scalaPrimitives { addPrimitives(FloatClass, nme.UNARY_-, NEG) // scala.Double + val DoubleClass = defn.DoubleClass addPrimitives(DoubleClass, nme.EQ, EQ) addPrimitives(DoubleClass, nme.NE, NE) addPrimitives(DoubleClass, nme.ADD, ADD) @@ -526,14 +540,14 @@ object scalaPrimitives { } /** If code is a coercion primitive, the result type */ - def generatedKind(code: Int): BType = code match { - case B2B | C2B | S2B | I2B | L2B | F2B | D2B => BType.BYTE - case B2C | C2C | S2C | I2C | L2C | F2C | D2C => BType.CHAR - case B2S | C2S | S2S | I2S | L2S | F2S | D2S => BType.SHORT - case B2I | C2I | S2I | I2I | L2I | F2I | D2I => BType.INT - case B2L | C2L | S2L | I2L | L2L | F2L | D2L => BType.LONG - case B2F | C2F | S2F | I2F | L2F | F2F | D2F => BType.FLOAT - case B2D | C2D | S2D | I2D | L2D | F2D | D2D => BType.DOUBLE + def generatedKind(code: Int): GenBCode.BType = code match { + case B2B | C2B | S2B | I2B | L2B | F2B | D2B => GenBCode.BType.BYTE + case B2C | C2C | S2C | I2C | L2C | F2C | D2C => GenBCode.BType.CHAR + case B2S | C2S | S2S | I2S | L2S | F2S | D2S => GenBCode.BType.SHORT + case B2I | C2I | S2I | I2I | L2I | F2I | D2I => GenBCode.BType.INT + case B2L | C2L | S2L | I2L | L2L | F2L | D2L => GenBCode.BType.LONG + case B2F | C2F | S2F | I2F | L2F | F2F | D2F => GenBCode.BType.FLOAT + case B2D | C2D | S2D | I2D | L2D | F2D | D2D => GenBCode.BType.DOUBLE } def isPrimitive(sym: Symbol): Boolean = primitives contains sym