diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/reflect/internal/Definitions.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala | 35 | ||||
-rw-r--r-- | src/library/scala/runtime/Statics.java | 89 |
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(); + } +} |