From a4597c4e2e664f744eeb68541ddbab997afc03cc Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 11 Mar 2016 16:59:16 +0100 Subject: [PATCH] Fix incorrect hashing leading to cache pollution Before this commit, Hashable#addDelta did not work correctly when the input hash was the special value NotCached, instead of returning NotCached, it returned NotCached + delta. This means that many different values ended up being cached with the same hash when they should not be cached at all, this is especially bad since our HashSet implementation uses open addressing. I noticed this bug while working on a phase to collect API information for sbt (this phase needs to collect every member of a class, including inherited members), after enabling it, the compileStdLib test took ~500 seconds to complete, this commit reduces this to ~100 seconds. --- src/dotty/tools/dotc/core/Hashable.scala | 4 +++- src/dotty/tools/dotc/core/Types.scala | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/core/Hashable.scala b/src/dotty/tools/dotc/core/Hashable.scala index 6a64f865558b..12a408fbd537 100644 --- a/src/dotty/tools/dotc/core/Hashable.scala +++ b/src/dotty/tools/dotc/core/Hashable.scala @@ -92,7 +92,9 @@ trait Hashable { protected final def doHash(x1: Int, x2: Int): Int = finishHash(hashing.mix(hashing.mix(hashSeed, x1), x2), 1) - protected final def addDelta(hc: Int, delta: Int) = avoidNotCached(hc + delta) + protected final def addDelta(elemHash: Int, delta: Int) = + if (elemHash == NotCached) NotCached + else avoidNotCached(elemHash + delta) private def avoidNotCached(h: Int) = if (h == NotCached) NotCachedAlt else h } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index dd12a0188941..17c2ec4ca82d 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2479,7 +2479,7 @@ object Types { def copyBoundType(bt: BT) = new MethodParamImpl(bt, paramNum) // need to customize hashCode and equals to prevent infinite recursion for dep meth types. - override def computeHash = addDelta(System.identityHashCode(binder), paramNum) + override def computeHash = addDelta(binder.identityHash, paramNum) override def equals(that: Any) = that match { case that: MethodParam => (this.binder eq that.binder) && this.paramNum == that.paramNum