diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-02-01 11:10:02 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-02-01 11:10:02 -0800 |
commit | 58961c7455ede33fbf86f25ac6cd2a7c0a413ea2 (patch) | |
tree | cc6fb360b3e6a5076bb1191329488d5c91ca32ff | |
parent | f7b5b312ca5dd1333245d8174a8dbadc89bd40fc (diff) | |
parent | 4c627b715e196a90de1030e641cf4e3e015e772d (diff) | |
download | scala-58961c7455ede33fbf86f25ac6cd2a7c0a413ea2.tar.gz scala-58961c7455ede33fbf86f25ac6cd2a7c0a413ea2.tar.bz2 scala-58961c7455ede33fbf86f25ac6cd2a7c0a413ea2.zip |
Merge pull request #1972 from soc/SI-6969-2.9.x
[backport] SI-6969, mishandling of SoftReferences in method cache.
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/CleanUp.scala | 25 | ||||
-rw-r--r-- | test/files/run/t6969.check | 1 | ||||
-rw-r--r-- | test/files/run/t6969.scala | 28 |
3 files changed, 47 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index aa829d61ab..64aecada83 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -227,12 +227,17 @@ abstract class CleanUp extends Transform with ast.TreeDSL { var reflPoly$Cache: SoftReference[scala.runtime.MethodCache] = new SoftReference(new EmptyMethodCache()) def reflMethod$Method(forReceiver: JClass[_]): JMethod = { - var method: JMethod = reflPoly$Cache.find(forReceiver) - if (method != null) + var methodCache: MethodCache = reflPoly$Cache.find(forReceiver) + if (methodCache eq null) { + methodCache = new EmptyMethodCache + reflPoly$Cache = new SoftReference(methodCache) + } + var method: JMethod = methodCache.find(forReceiver) + if (method ne null) return method else { method = ScalaRunTime.ensureAccessible(forReceiver.getMethod("xyz", reflParams$Cache)) - reflPoly$Cache = new SoftReference(reflPoly$Cache.get.add(forReceiver, method)) + reflPoly$Cache = new SoftReference(methodCache.add(forReceiver, method)) return method } } @@ -248,16 +253,22 @@ abstract class CleanUp extends Transform with ast.TreeDSL { addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => + val methodCache = reflMethodSym.newVariable(ad.pos, mkTerm("methodCache")) setInfo MethodCacheClass.tpe val methodSym = reflMethodSym.newVariable(ad.pos, mkTerm("method")) setInfo MethodClass.tpe BLOCK( - IF (getPolyCache OBJ_EQ NULL) THEN (safeREF(reflPolyCacheSym) === mkNewPolyCache) ENDIF, - VAL(methodSym) === ((getPolyCache DOT methodCache_find)(REF(forReceiverSym))) , - IF (REF(methodSym) OBJ_!= NULL) . + VAR(methodCache) === getPolyCache, + IF (REF(methodCache) OBJ_EQ NULL) THEN BLOCK( + REF(methodCache) === NEW(TypeTree(EmptyMethodCacheClass.tpe)), + REF(reflPolyCacheSym) === gen.mkSoftRef(REF(methodCache)) + ) ENDIF, + + VAR(methodSym) === (REF(methodCache) DOT methodCache_find)(REF(forReceiverSym)), + IF (REF(methodSym) OBJ_NE NULL) . THEN (Return(REF(methodSym))) ELSE { def methodSymRHS = ((REF(forReceiverSym) DOT Class_getMethod)(LIT(method), safeREF(reflParamsCacheSym))) - def cacheRHS = ((getPolyCache DOT methodCache_add)(REF(forReceiverSym), REF(methodSym))) + def cacheRHS = ((REF(methodCache) DOT methodCache_add)(REF(forReceiverSym), REF(methodSym))) BLOCK( REF(methodSym) === (REF(ensureAccessibleMethod) APPLY (methodSymRHS)), safeREF(reflPolyCacheSym) === gen.mkSoftRef(cacheRHS), diff --git a/test/files/run/t6969.check b/test/files/run/t6969.check new file mode 100644 index 0000000000..78297812c9 --- /dev/null +++ b/test/files/run/t6969.check @@ -0,0 +1 @@ +All threads completed. diff --git a/test/files/run/t6969.scala b/test/files/run/t6969.scala new file mode 100644 index 0000000000..50b252c8c8 --- /dev/null +++ b/test/files/run/t6969.scala @@ -0,0 +1,28 @@ +object Test { + private type Clearable = { def clear(): Unit } + private def choke() = { + try new Array[Object]((Runtime.getRuntime().maxMemory min Int.MaxValue).toInt) + catch { + case _: OutOfMemoryError => // what do you mean, out of memory? + case t: Throwable => println(t) + } + } + private def f(x: Clearable) = x.clear() + class Choker(id: Int) extends Thread { + private def g(iteration: Int) = { + val map = scala.collection.mutable.Map[Int, Int](1 -> 2) + try f(map) catch { case t: NullPointerException => println("Failed at "+id+"/"+iteration) ; throw t } + choke() + } + override def run() { + 1 to 50 foreach g + } + } + + def main(args: Array[String]): Unit = { + val threads = 1 to 3 map (id => new Choker(id)) + threads foreach (_.start()) + threads foreach (_.join()) + println("All threads completed.") + } +} |