summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-12-04 16:54:03 +0000
committerPaul Phillips <paulp@improving.org>2010-12-04 16:54:03 +0000
commit3d97123034a9d82e6e6961d589ccd3a1afde4390 (patch)
tree5bab1c93302261a91df9be88432d9ba5c456119a /src
parent4e3a930c04c9680be0e8d5d1114d0f0a3f8ea4a1 (diff)
downloadscala-3d97123034a9d82e6e6961d589ccd3a1afde4390.tar.gz
scala-3d97123034a9d82e6e6961d589ccd3a1afde4390.tar.bz2
scala-3d97123034a9d82e6e6961d589ccd3a1afde4390.zip
Some refactoring of genjvm trying to separate o...
Some refactoring of genjvm trying to separate out some of the relatively immutable logic from the parts more in flux, and slightly ease the process of keeping separable things separate. Review by dragos.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala143
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala166
-rwxr-xr-xsrc/library/scala/reflect/generic/Constants.scala104
3 files changed, 218 insertions, 195 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index dfd9feafc2..1a0cb4f197 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -26,8 +26,7 @@ import reflect.generic.{ PickleFormat, PickleBuffer }
* @version 1.0
*
*/
-abstract class GenJVM extends SubComponent with GenAndroid {
- val global: Global
+abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid {
import global._
import icodes._
import icodes.opcodes._
@@ -80,7 +79,7 @@ abstract class GenJVM extends SubComponent with GenAndroid {
* Java bytecode generator.
*
*/
- class BytecodeGenerator {
+ class BytecodeGenerator extends BytecodeUtil {
def debugLevel = settings.debuginfo.indexOfChoice
val MIN_SWITCH_DENSITY = 0.7
@@ -979,37 +978,6 @@ abstract class GenJVM extends SubComponent with GenAndroid {
var linearization: List[BasicBlock] = Nil
var isModuleInitialized = false
- private def genConstant(jcode: JExtendedCode, const: Constant) {
- const.tag match {
- case UnitTag => ()
- case BooleanTag => jcode emitPUSH const.booleanValue
- case ByteTag => jcode emitPUSH const.byteValue
- case ShortTag => jcode emitPUSH const.shortValue
- case CharTag => jcode emitPUSH const.charValue
- case IntTag => jcode emitPUSH const.intValue
- case LongTag => jcode emitPUSH const.longValue
- case FloatTag => jcode emitPUSH const.floatValue
- case DoubleTag => jcode emitPUSH const.doubleValue
- case StringTag => jcode emitPUSH const.stringValue
- case NullTag => jcode.emitACONST_NULL()
- case ClassTag =>
- val kind = toTypeKind(const.typeValue)
- val toPush =
- if (kind.isValueType) classLiteral(kind)
- else javaType(kind).asInstanceOf[JReferenceType]
-
- jcode emitPUSH toPush
-
- case EnumTag =>
- val sym = const.symbolValue
- jcode.emitGETSTATIC(javaName(sym.owner),
- javaName(sym),
- javaType(sym.tpe.underlying))
- case _ =>
- abort("Unknown constant value: " + const)
- }
- }
-
/**
* @param m ...
*/
@@ -1709,37 +1677,6 @@ abstract class GenJVM extends SubComponent with GenAndroid {
/** For each basic block, the first PC address following it. */
val endPC = new mutable.HashMap[BasicBlock, Int]
- val conds = new mutable.HashMap[TestOp, Int]
-
- conds += (EQ -> JExtendedCode.COND_EQ)
- conds += (NE -> JExtendedCode.COND_NE)
- conds += (LT -> JExtendedCode.COND_LT)
- conds += (GT -> JExtendedCode.COND_GT)
- conds += (LE -> JExtendedCode.COND_LE)
- conds += (GE -> JExtendedCode.COND_GE)
-
- val negate = new mutable.HashMap[TestOp, TestOp]
-
- negate += (EQ -> NE)
- negate += (NE -> EQ)
- negate += (LT -> GE)
- negate += (GT -> LE)
- negate += (LE -> GT)
- negate += (GE -> LT)
-
- /** Map from type kinds to the Java reference types. It is used for
- * loading class constants. @see Predef.classOf. */
- val classLiteral = immutable.Map[TypeKind, JObjectType](
- UNIT -> new JObjectType("java.lang.Void"),
- BOOL -> new JObjectType("java.lang.Boolean"),
- BYTE -> new JObjectType("java.lang.Byte"),
- SHORT -> new JObjectType("java.lang.Short"),
- CHAR -> new JObjectType("java.lang.Character"),
- INT -> new JObjectType("java.lang.Integer"),
- LONG -> new JObjectType("java.lang.Long"),
- FLOAT -> new JObjectType("java.lang.Float"),
- DOUBLE -> new JObjectType("java.lang.Double")
- )
////////////////////// local vars ///////////////////////
@@ -1781,50 +1718,6 @@ abstract class GenJVM extends SubComponent with GenAndroid {
////////////////////// Utilities ////////////////////////
/**
- * <p>
- * Return the a name of this symbol that can be used on the Java
- * platform. It removes spaces from names.
- * </p>
- * <p>
- * Special handling: scala.Nothing and <code>scala.Null</code> are
- * <em>erased</em> to <code>scala.runtime.Nothing$</code> and
- * </code>scala.runtime.Null$</code>. This is needed because they are
- * not real classes, and they mean 'abrupt termination upon evaluation
- * of that expression' or <code>null</code> respectively. This handling is
- * done already in <a href="../icode/GenIcode.html" target="contentFrame">
- * <code>GenICode</code></a>, but here we need to remove references
- * from method signatures to these types, because such classes can
- * not exist in the classpath: the type checker will be very confused.
- * </p>
- */
- def javaName(sym: Symbol): String = {
- val suffix = moduleSuffix(sym)
-
- if (sym == NothingClass) javaName(RuntimeNothingClass)
- else if (sym == NullClass) javaName(RuntimeNullClass)
- else getPrimitiveCompanion(sym.companionModule) match {
- case Some(sym) => javaName(sym)
- case _ =>
- if (sym.isClass && !sym.rawowner.isPackageClass && !sym.isModuleClass)
- innerClasses = innerClasses + sym
-
- val prefix =
- if (sym.isClass || (sym.isModule && !sym.isMethod)) sym.fullName('/')
- else sym.simpleName.toString.trim()
-
- prefix + suffix
- }
- }
-
- def javaNames(syms: List[Symbol]): Array[String] = {
- val res = new Array[String](syms.length)
- var i = 0
- syms foreach (s => { res(i) = javaName(s); i += 1 })
- res
- }
- private def mkFlags(args: Int*) = args.foldLeft(0)(_ | _)
-
- /**
* Return the Java modifiers for the given symbol.
* Java modifiers for classes:
* - public, abstract, final, strictfp (not used)
@@ -1841,6 +1734,7 @@ abstract class GenJVM extends SubComponent with GenAndroid {
* and they would fail verification after lifted.
*/
def javaFlags(sym: Symbol): Int = {
+ def mkFlags(args: Int*) = args.foldLeft(0)(_ | _)
// constructors of module classes should be private
// PP: why are they only being marked private at this stage and not earlier?
val isConsideredPrivate =
@@ -1872,37 +1766,6 @@ abstract class GenJVM extends SubComponent with GenAndroid {
(sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass))
}
- def javaType(t: TypeKind): JType = (t: @unchecked) match {
- case UNIT => JType.VOID
- case BOOL => JType.BOOLEAN
- case BYTE => JType.BYTE
- case SHORT => JType.SHORT
- case CHAR => JType.CHAR
- case INT => JType.INT
- case LONG => JType.LONG
- case FLOAT => JType.FLOAT
- case DOUBLE => JType.DOUBLE
- case REFERENCE(cls) => new JObjectType(javaName(cls))
- case ARRAY(elem) => new JArrayType(javaType(elem))
- }
-
- def javaType(t: Type): JType = javaType(toTypeKind(t))
-
- def javaType(s: Symbol): JType =
- if (s.isMethod)
- new JMethodType(
- if (s.isClassConstructor) JType.VOID else javaType(s.tpe.resultType),
- s.tpe.paramTypes.map(javaType).toArray)
- else
- javaType(s.tpe)
-
- def javaTypes(ts: List[TypeKind]): Array[JType] = {
- val res = new Array[JType](ts.length)
- var i = 0
- ts foreach ( t => { res(i) = javaType(t); i += 1 } );
- res
- }
-
/** Return an abstract file for the given class symbol, with the desired suffix.
* Create all necessary subdirectories on the way.
*/
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala
new file mode 100644
index 0000000000..cd0d253954
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala
@@ -0,0 +1,166 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Iulian Dragos
+ */
+
+
+package scala.tools.nsc
+package backend.jvm
+
+import java.nio.ByteBuffer
+
+import scala.collection.{ mutable, immutable }
+import scala.tools.nsc.io.AbstractFile
+import scala.tools.nsc.symtab._
+import scala.tools.nsc.symtab.classfile.ClassfileConstants._
+
+import ch.epfl.lamp.fjbg._
+import JAccessFlags._
+import JObjectType.{ JAVA_LANG_STRING, JAVA_LANG_OBJECT }
+import java.io.{ DataOutputStream }
+import reflect.generic.{ PickleFormat, PickleBuffer }
+
+trait GenJVMUtil {
+ self: GenJVM =>
+
+ import global._
+ import icodes._
+ import icodes.opcodes._
+ import definitions._
+
+ /** Map from type kinds to the Java reference types. It is used for
+ * loading class constants. @see Predef.classOf.
+ */
+ val classLiteral = immutable.Map[TypeKind, JObjectType](
+ UNIT -> new JObjectType("java.lang.Void"),
+ BOOL -> new JObjectType("java.lang.Boolean"),
+ BYTE -> new JObjectType("java.lang.Byte"),
+ SHORT -> new JObjectType("java.lang.Short"),
+ CHAR -> new JObjectType("java.lang.Character"),
+ INT -> new JObjectType("java.lang.Integer"),
+ LONG -> new JObjectType("java.lang.Long"),
+ FLOAT -> new JObjectType("java.lang.Float"),
+ DOUBLE -> new JObjectType("java.lang.Double")
+ )
+
+ trait BytecodeUtil {
+ self: BytecodeGenerator =>
+
+ val conds = immutable.Map[TestOp, Int](
+ EQ -> JExtendedCode.COND_EQ,
+ NE -> JExtendedCode.COND_NE,
+ LT -> JExtendedCode.COND_LT,
+ GT -> JExtendedCode.COND_GT,
+ LE -> JExtendedCode.COND_LE,
+ GE -> JExtendedCode.COND_GE
+ )
+ val negate = immutable.Map[TestOp, TestOp](
+ EQ -> NE,
+ NE -> EQ,
+ LT -> GE,
+ GT -> LE,
+ LE -> GT,
+ GE -> LT
+ )
+
+ /** Return the a name of this symbol that can be used on the Java
+ * platform. It removes spaces from names.
+ *
+ * Special handling:
+ * scala.Nothing erases to scala.runtime.Nothing$
+ * scala.Null erases to scala.runtime.Null$
+ *
+ * This is needed because they are not real classes, and they mean
+ * 'abrupt termination upon evaluation of that expression' or null respectively.
+ * This handling is done already in GenICode, but here we need to remove
+ * references from method signatures to these types, because such classes can
+ * not exist in the classpath: the type checker will be very confused.
+ */
+ def javaName(sym: Symbol): String = {
+ val suffix = moduleSuffix(sym)
+
+ if (sym == NothingClass) javaName(RuntimeNothingClass)
+ else if (sym == NullClass) javaName(RuntimeNullClass)
+ else getPrimitiveCompanion(sym.companionModule) match {
+ case Some(sym) => javaName(sym)
+ case _ =>
+ if (sym.isClass && !sym.rawowner.isPackageClass && !sym.isModuleClass)
+ innerClasses = innerClasses + sym
+
+ val prefix =
+ if (sym.isClass || (sym.isModule && !sym.isMethod)) sym.fullName('/')
+ else sym.simpleName.toString.trim()
+
+ prefix + suffix
+ }
+ }
+
+ def javaNames(syms: List[Symbol]): Array[String] = {
+ val res = new Array[String](syms.length)
+ var i = 0
+ syms foreach (s => { res(i) = javaName(s); i += 1 })
+ res
+ }
+
+ def javaType(t: TypeKind): JType = (t: @unchecked) match {
+ case UNIT => JType.VOID
+ case BOOL => JType.BOOLEAN
+ case BYTE => JType.BYTE
+ case SHORT => JType.SHORT
+ case CHAR => JType.CHAR
+ case INT => JType.INT
+ case LONG => JType.LONG
+ case FLOAT => JType.FLOAT
+ case DOUBLE => JType.DOUBLE
+ case REFERENCE(cls) => new JObjectType(javaName(cls))
+ case ARRAY(elem) => new JArrayType(javaType(elem))
+ }
+
+ def javaType(t: Type): JType = javaType(toTypeKind(t))
+
+ def javaType(s: Symbol): JType =
+ if (s.isMethod)
+ new JMethodType(
+ if (s.isClassConstructor) JType.VOID else javaType(s.tpe.resultType),
+ s.tpe.paramTypes.map(javaType).toArray)
+ else
+ javaType(s.tpe)
+
+ def javaTypes(ts: List[TypeKind]): Array[JType] = {
+ val res = new Array[JType](ts.length)
+ var i = 0
+ ts foreach ( t => { res(i) = javaType(t); i += 1 } );
+ res
+ }
+ protected def genConstant(jcode: JExtendedCode, const: Constant) {
+ const.tag match {
+ case UnitTag => ()
+ case BooleanTag => jcode emitPUSH const.booleanValue
+ case ByteTag => jcode emitPUSH const.byteValue
+ case ShortTag => jcode emitPUSH const.shortValue
+ case CharTag => jcode emitPUSH const.charValue
+ case IntTag => jcode emitPUSH const.intValue
+ case LongTag => jcode emitPUSH const.longValue
+ case FloatTag => jcode emitPUSH const.floatValue
+ case DoubleTag => jcode emitPUSH const.doubleValue
+ case StringTag => jcode emitPUSH const.stringValue
+ case NullTag => jcode.emitACONST_NULL()
+ case ClassTag =>
+ val kind = toTypeKind(const.typeValue)
+ val toPush =
+ if (kind.isValueType) classLiteral(kind)
+ else javaType(kind).asInstanceOf[JReferenceType]
+
+ jcode emitPUSH toPush
+
+ case EnumTag =>
+ val sym = const.symbolValue
+ jcode.emitGETSTATIC(javaName(sym.owner),
+ javaName(sym),
+ javaType(sym.tpe.underlying))
+ case _ =>
+ abort("Unknown constant value: " + const)
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/library/scala/reflect/generic/Constants.scala b/src/library/scala/reflect/generic/Constants.scala
index bf963a1aae..d845129a2c 100755
--- a/src/library/scala/reflect/generic/Constants.scala
+++ b/src/library/scala/reflect/generic/Constants.scala
@@ -7,47 +7,53 @@ package scala.reflect
package generic
import java.lang.Integer.toOctalString
-import PickleFormat._
-trait Constants { self: Universe =>
+trait Constants {
+ self: Universe =>
import definitions._
- final val NoTag = LITERAL - LITERAL
- final val UnitTag = LITERALunit - LITERAL
- final val BooleanTag = LITERALboolean - LITERAL
- final val ByteTag = LITERALbyte - LITERAL
- final val ShortTag = LITERALshort - LITERAL
- final val CharTag = LITERALchar - LITERAL
- final val IntTag = LITERALint - LITERAL
- final val LongTag = LITERALlong - LITERAL
- final val FloatTag = LITERALfloat - LITERAL
- final val DoubleTag = LITERALdouble - LITERAL
- final val StringTag = LITERALstring - LITERAL
- final val NullTag = LITERALnull - LITERAL
- final val ClassTag = LITERALclass - LITERAL
+ final val NoTag = 0
+ final val UnitTag = 1
+ final val BooleanTag = 2
+ final val ByteTag = 3
+ final val ShortTag = 4
+ final val CharTag = 5
+ final val IntTag = 6
+ final val LongTag = 7
+ final val FloatTag = 8
+ final val DoubleTag = 9
+ final val StringTag = 10
+ final val NullTag = 11
+ final val ClassTag = 12
// For supporting java enumerations inside java annotations (see ClassfileParser)
- final val EnumTag = LITERALenum - LITERAL
+ final val EnumTag = 13
case class Constant(value: Any) {
+ val tag: Int = value match {
+ case null => NullTag
+ case x: Unit => UnitTag
+ case x: Boolean => BooleanTag
+ case x: Byte => ByteTag
+ case x: Short => ShortTag
+ case x: Int => IntTag
+ case x: Long => LongTag
+ case x: Float => FloatTag
+ case x: Double => DoubleTag
+ case x: String => StringTag
+ case x: Char => CharTag
+ case x: AbsType => ClassTag
+ case x: AbsSymbol => EnumTag
+ case _ => throw new Error("bad constant value: " + value)
+ }
- val tag: Int =
- if (value.isInstanceOf[Unit]) UnitTag
- else if (value.isInstanceOf[Boolean]) BooleanTag
- else if (value.isInstanceOf[Byte]) ByteTag
- else if (value.isInstanceOf[Short]) ShortTag
- else if (value.isInstanceOf[Char]) CharTag
- else if (value.isInstanceOf[Int]) IntTag
- else if (value.isInstanceOf[Long]) LongTag
- else if (value.isInstanceOf[Float]) FloatTag
- else if (value.isInstanceOf[Double]) DoubleTag
- else if (value.isInstanceOf[String]) StringTag
- else if (value.isInstanceOf[AbsType]) ClassTag
- else if (value.isInstanceOf[AbsSymbol]) EnumTag
- else if (value == null) NullTag
- else throw new Error("bad constant value: " + value)
-
- def isNumeric: Boolean = ByteTag <= tag && tag <= DoubleTag
+ def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue
+ def isShortRange: Boolean = isIntRange && Short.MinValue <= intValue && intValue <= Short.MaxValue
+ def isCharRange: Boolean = isIntRange && Char.MinValue <= intValue && intValue <= Char.MaxValue
+ def isIntRange: Boolean = ByteTag <= tag && tag <= IntTag
+ def isLongRange: Boolean = ByteTag <= tag && tag <= LongTag
+ def isFloatRange: Boolean = ByteTag <= tag && tag <= FloatTag
+ def isNumeric: Boolean = ByteTag <= tag && tag <= DoubleTag
def tpe: Type = tag match {
case UnitTag => UnitClass.tpe
@@ -71,9 +77,6 @@ trait Constants { self: Universe =>
}
/** We need the equals method to take account of tags as well as values.
- *
- * @param other ...
- * @return ...
*/
override def equals(other: Any): Boolean = other match {
case that: Constant =>
@@ -83,7 +86,7 @@ trait Constants { self: Universe =>
}
def isNaN = value match {
- case f: Float => f.isNaN
+ case f: Float => f.isNaN
case d: Double => d.isNaN
case _ => false
}
@@ -170,34 +173,27 @@ trait Constants { self: Universe =>
}
/** Convert constant value to conform to given type.
- *
- * @param pt ...
- * @return ...
*/
def convertTo(pt: Type): Constant = {
val target = pt.typeSymbol
if (target == tpe.typeSymbol)
this
- else if (target == ByteClass && ByteTag <= tag && tag <= IntTag &&
- -128 <= intValue && intValue <= 127)
+ else if (target == ByteClass && isByteRange)
Constant(byteValue)
- else if (target == ShortClass && ByteTag <= tag && tag <= IntTag &&
- -32768 <= intValue && intValue <= 32767)
+ else if (target == ShortClass && isShortRange)
Constant(shortValue)
- else if (target == CharClass && ByteTag <= tag && tag <= IntTag &&
- 0 <= intValue && intValue <= 65635)
+ else if (target == CharClass && isCharRange)
Constant(charValue)
- else if (target == IntClass && ByteTag <= tag && tag <= IntTag)
+ else if (target == IntClass && isIntRange)
Constant(intValue)
- else if (target == LongClass && ByteTag <= tag && tag <= LongTag)
+ else if (target == LongClass && isLongRange)
Constant(longValue)
- else if (target == FloatClass && ByteTag <= tag && tag <= FloatTag)
+ else if (target == FloatClass && isFloatRange)
Constant(floatValue)
- else if (target == DoubleClass && ByteTag <= tag && tag <= DoubleTag)
+ else if (target == DoubleClass && isNumeric)
Constant(doubleValue)
- else {
+ else
null
- }
}
def stringValue: String =
@@ -224,9 +220,7 @@ trait Constants { self: Universe =>
case _ => value.toString()
}
}
-
- def typeValue: Type = value.asInstanceOf[Type]
-
+ def typeValue: Type = value.asInstanceOf[Type]
def symbolValue: Symbol = value.asInstanceOf[Symbol]
override def hashCode: Int =