From 0e197e89ac96ec0dd8b136de8e07ad2e15f94371 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 9 May 2012 15:01:26 -0700 Subject: Custom hashCode methods for case classes. No boxing, no MODULE$ indirection. --- .../scala/reflect/internal/Definitions.scala | 1 + .../tools/nsc/typechecker/SyntheticMethods.scala | 35 +++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) (limited to 'src/compiler') 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) ) -- cgit v1.2.3