summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 =