summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-06-23 00:08:33 +0000
committerPaul Phillips <paulp@improving.org>2011-06-23 00:08:33 +0000
commitdbf4bf263ad6e809330a1720c2757f6e62b2bf42 (patch)
tree5532635de743ec8de5723b039b41b8c7ee3168c2
parent444ab5548134b4ad69809285a2ddc30791bef361 (diff)
downloadscala-dbf4bf263ad6e809330a1720c2757f6e62b2bf42.tar.gz
scala-dbf4bf263ad6e809330a1720c2757f6e62b2bf42.tar.bz2
scala-dbf4bf263ad6e809330a1720c2757f6e62b2bf42.zip
Noticed while working on getClass that most of the
implementations for $hash$hash can be inlined directly, with this kind of beautiful change: // source def hash(x1: Int, x2: Int) = x1.## + x2.## // before 0: getstatic #11; //Field scala/runtime/ScalaRunTime$.MODULE$:Lscala/runtime/ScalaRunTime$; 3: iload_1 4: invokevirtual #27; //Method scala/runtime/ScalaRunTime$.hash:(I)I 7: getstatic #11; //Field scala/runtime/ScalaRunTime$.MODULE$:Lscala/runtime/ScalaRunTime$; 10: iload_2 11: invokevirtual #27; //Method scala/runtime/ScalaRunTime$.hash:(I)I 14: iadd 15: ireturn // after 0: iload_1 1: iload_2 2: iadd 3: ireturn No review.
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala34
-rw-r--r--src/library/scala/runtime/ScalaRunTime.scala12
2 files changed, 25 insertions, 21 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 2500c84f98..c86a7b5867 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -99,6 +99,15 @@ abstract class Erasure extends AddInterfaces
}
}
+ // convert a numeric with a toXXX method
+ def numericConversion(tree: Tree, numericSym: Symbol): Tree = {
+ val mname = newTermName("to" + numericSym.name)
+ val conversion = tree.tpe member mname
+
+ assert(conversion != NoSymbol, tree + " => " + numericSym)
+ atPos(tree.pos)(Apply(Select(tree, conversion), Nil))
+ }
+
private def unboundedGenericArrayLevel(tp: Type): Int = tp match {
case GenericArray(level, core) if !(core <:< AnyRefClass.tpe) => level
case _ => 0
@@ -1021,12 +1030,14 @@ abstract class Erasure extends AddInterfaces
// erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int.
// This must be because some earlier transformation is being skipped on ##, but so
// far I don't know what. For null we now define null.## == 0.
- val arg = qual.tpe.typeSymbolDirect match {
- case UnitClass => BLOCK(qual, REF(BoxedUnit_UNIT)) // ({ expr; UNIT }).##
- case NullClass => LIT(0) // (null: Object).##
- case _ => qual
+ qual.tpe.typeSymbol match {
+ case UnitClass | NullClass => LIT(0)
+ case IntClass => qual
+ case s @ (ShortClass | ByteClass | CharClass) => numericConversion(qual, s)
+ case BooleanClass => If(qual, LIT(true.##), LIT(false.##))
+ case _ =>
+ Apply(gen.mkAttributedRef(scalaRuntimeHash), List(qual))
}
- Apply(gen.mkAttributedRef(scalaRuntimeHash), List(arg))
}
// Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
else if (isValueClass(qual.tpe.typeSymbol))
@@ -1038,16 +1049,11 @@ abstract class Erasure extends AddInterfaces
if (fn.symbol == Any_asInstanceOf)
(fn: @unchecked) match {
case TypeApply(Select(qual, _), List(targ)) =>
- if (qual.tpe <:< targ.tpe) {
+ if (qual.tpe <:< targ.tpe)
atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) }
- } else if (isNumericValueClass(qual.tpe.typeSymbol) &&
- isNumericValueClass(targ.tpe.typeSymbol)) {
- // convert numeric type casts
- val cname = newTermName("to" + targ.tpe.typeSymbol.name)
- val csym = qual.tpe.member(cname)
- assert(csym != NoSymbol)
- atPos(tree.pos) { Apply(Select(qual, csym), List()) }
- } else
+ else if (isNumericValueClass(qual.tpe.typeSymbol) && isNumericValueClass(targ.tpe.typeSymbol))
+ atPos(tree.pos)(numericConversion(qual, targ.tpe.typeSymbol))
+ else
tree
}
// todo: also handle the case where the singleton type is buried in a compound
diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala
index 031f15f10a..5a20b72fcd 100644
--- a/src/library/scala/runtime/ScalaRunTime.scala
+++ b/src/library/scala/runtime/ScalaRunTime.scala
@@ -239,18 +239,16 @@ object ScalaRunTime {
val high = (lv >>> 32).toInt
low ^ (high + lowSign)
}
+ @inline def hash(x: Number): Int = runtime.BoxesRunTime.hashFromNumber(x)
+
+ // The remaining overloads are here for completeness, but the compiler
+ // inlines these definitions directly so they're not generally used.
@inline def hash(x: Int): Int = x
@inline def hash(x: Short): Int = x.toInt
@inline def hash(x: Byte): Int = x.toInt
@inline def hash(x: Char): Int = x.toInt
- @inline def hash(x: Boolean): Int = if (x) trueHashcode else falseHashcode
+ @inline def hash(x: Boolean): Int = if (x) true.hashCode else false.hashCode
@inline def hash(x: Unit): Int = 0
- @inline def hash(x: Number): Int = runtime.BoxesRunTime.hashFromNumber(x)
-
- // These are so these values are constant folded into def hash(Boolean)
- // rather than being recalculated all the time.
- private final val trueHashcode = true.hashCode
- private final val falseHashcode = false.hashCode
/** A helper method for constructing case class equality methods,
* because existential types get in the way of a clean outcome and