summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala35
-rw-r--r--src/library/scala/runtime/Statics.java89
3 files changed, 124 insertions, 1 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 1c3e11b040..edafde1346 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -896,6 +896,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
// boxed classes
lazy val ObjectRefClass = requiredClass[scala.runtime.ObjectRef[_]]
lazy val VolatileObjectRefClass = requiredClass[scala.runtime.VolatileObjectRef[_]]
+ lazy val RuntimeStaticsModule = getRequiredModule("scala.runtime.Statics")
lazy val BoxesRunTimeModule = getRequiredModule("scala.runtime.BoxesRunTime")
lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass
lazy val BoxedNumberClass = getClass(sn.BoxedNumber)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 57e82ed706..484c8beb1b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -89,6 +89,11 @@ trait SyntheticMethods extends ast.TreeDSL {
def forwardToRuntime(method: Symbol): Tree =
forwardMethod(method, getMember(ScalaRunTimeModule, method.name prepend "_"))(mkThis :: _)
+ def callStaticsMethod(name: String)(args: Tree*): Tree = {
+ val method = termMember(RuntimeStaticsModule, name)
+ Apply(gen.mkAttributedRef(method), args.toList)
+ }
+
// Any member, including private
def hasConcreteImpl(name: Name) =
clazz.info.member(name).alternatives exists (m => !m.isDeferred && !m.isSynthetic)
@@ -222,13 +227,41 @@ trait SyntheticMethods extends ast.TreeDSL {
)
}
+ def hashcodeImplementation(sym: Symbol): Tree = {
+ sym.tpe.finalResultType.typeSymbol match {
+ case UnitClass | NullClass => Literal(Constant(0))
+ case BooleanClass => If(Ident(sym), Literal(Constant(1231)), Literal(Constant(1237)))
+ case IntClass | ShortClass | ByteClass | CharClass => Ident(sym)
+ case LongClass => callStaticsMethod("longHash")(Ident(sym))
+ case DoubleClass => callStaticsMethod("doubleHash")(Ident(sym))
+ case FloatClass => callStaticsMethod("floatHash")(Ident(sym))
+ case _ => callStaticsMethod("anyHash")(Ident(sym))
+ }
+ }
+
+ def specializedHashcode = {
+ createMethod(nme.hashCode_, Nil, IntClass.tpe) { m =>
+ val accumulator = m.newVariable(newTermName("acc"), m.pos, SYNTHETIC) setInfo IntClass.tpe
+ val valdef = ValDef(accumulator, Literal(Constant(0xcafebabe)))
+ val mixes = accessors map (acc =>
+ Assign(
+ Ident(accumulator),
+ callStaticsMethod("mix")(Ident(accumulator), hashcodeImplementation(acc))
+ )
+ )
+ val finish = callStaticsMethod("finalizeHash")(Ident(accumulator), Literal(Constant(arity)))
+
+ Block(valdef :: mixes, finish)
+ }
+ }
+
def valueClassMethods = List(
Any_hashCode -> (() => hashCodeDerivedValueClassMethod),
Any_equals -> (() => equalsDerivedValueClassMethod)
)
def caseClassMethods = productMethods ++ productNMethods ++ Seq(
- Object_hashCode -> (() => forwardToRuntime(Object_hashCode)),
+ Object_hashCode -> (() => specializedHashcode),
Object_toString -> (() => forwardToRuntime(Object_toString)),
Object_equals -> (() => equalsCaseClassMethod)
)
diff --git a/src/library/scala/runtime/Statics.java b/src/library/scala/runtime/Statics.java
new file mode 100644
index 0000000000..485511ecbb
--- /dev/null
+++ b/src/library/scala/runtime/Statics.java
@@ -0,0 +1,89 @@
+package scala.runtime;
+
+/** Not for public consumption. Usage by the runtime only.
+ */
+
+public final class Statics {
+ public static int mix(int hash, int data) {
+ int h = mixLast(hash, data);
+ h = Integer.rotateLeft(h, 13);
+ return h * 5 + 0xe6546b64;
+ }
+
+ public static int mixLast(int hash, int data) {
+ int k = data;
+
+ k *= 0xcc9e2d51;
+ k = Integer.rotateLeft(k, 15);
+ k *= 0x1b873593;
+
+ return hash ^ k;
+ }
+
+ public static int finalizeHash(int hash, int length) {
+ return avalanche(hash ^ length);
+ }
+
+ /** Force all bits of the hash to avalanche. Used for finalizing the hash. */
+ public static int avalanche(int h) {
+ h ^= h >>> 16;
+ h *= 0x85ebca6b;
+ h ^= h >>> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >>> 16;
+
+ return h;
+ }
+
+ public static int longHash(long lv) {
+ if ((int)lv == lv)
+ return (int)lv;
+ else
+ return (int)(lv ^ (lv >>> 32));
+ }
+
+ public static int doubleHash(double dv) {
+ int iv = (int)dv;
+ if (iv == dv)
+ return iv;
+
+ float fv = (float)dv;
+ if (fv == dv)
+ return java.lang.Float.floatToIntBits(fv);
+
+ long lv = (long)dv;
+ if (lv == dv)
+ return (int)lv;
+
+ lv = Double.doubleToLongBits(dv);
+ return (int)(lv ^ (lv >>> 32));
+ }
+
+ public static int floatHash(float fv) {
+ int iv = (int)fv;
+ if (iv == fv)
+ return iv;
+
+ long lv = (long)fv;
+ if (lv == fv)
+ return (int)(lv^(lv>>>32));
+
+ return java.lang.Float.floatToIntBits(fv);
+ }
+
+ public static int anyHash(Object x) {
+ if (x == null)
+ return 0;
+
+ if (x instanceof java.lang.Long)
+ return longHash(((java.lang.Long)x).longValue());
+
+ if (x instanceof java.lang.Double)
+ return doubleHash(((java.lang.Double)x).doubleValue());
+
+ if (x instanceof java.lang.Float)
+ return floatHash(((java.lang.Float)x).floatValue());
+
+ return x.hashCode();
+ }
+}