diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2014-01-15 21:07:15 +0300 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2014-01-21 14:12:39 +0300 |
commit | 2bd304404ac00939a18a678aa982da9cbb3471a2 (patch) | |
tree | 3cbd2f12522953a0cd9945aca7fae02f44ec1b94 /test/files | |
parent | f142d854d3401728546ae6822662b7a3ad655a58 (diff) | |
download | scala-2bd304404ac00939a18a678aa982da9cbb3471a2.tar.gz scala-2bd304404ac00939a18a678aa982da9cbb3471a2.tar.bz2 scala-2bd304404ac00939a18a678aa982da9cbb3471a2.zip |
SI-8131 fixes residual race condition in runtime reflection
Apparently some completers can call setInfo while they’re not yet done,
which resets the LOCKED flag, and makes anything that uses LOCKED to
track completion unreliable. Unfortunately, that’s exactly the mechanism
that was used by runtime reflection to elide locking for symbols that are
known to be initialized.
This commit fixes the problematic lock elision strategy by introducing
an explicit communication channel between SynchronizedSymbol’s and their
completers. Now instead of trying hard to infer whether it’s already
initialized or not, every symbol gets a volatile field that can be queried
to provide necessary information.
Diffstat (limited to 'test/files')
-rw-r--r-- | test/files/run/reflection-sync-potpourri.scala | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/test/files/run/reflection-sync-potpourri.scala b/test/files/run/reflection-sync-potpourri.scala new file mode 100644 index 0000000000..0c96974df7 --- /dev/null +++ b/test/files/run/reflection-sync-potpourri.scala @@ -0,0 +1,32 @@ +import scala.reflect.runtime.universe._ + +// this test checks that under heavily multithreaded conditions: +// 1) scala.reflect.runtime.universe, its rootMirror and definitions are initialized correctly +// 2) symbols are correctly materialized into PackageScopes (no dupes) +// 3) unpickling works okay even we unpickle the same symbol a lot of times + +object Test extends App { + def foo[T: TypeTag](x: T) = typeOf[T].toString + val n = 1000 + val rng = new scala.util.Random() + val types = List( + () => typeOf[java.lang.reflect.Method], + () => typeOf[java.lang.annotation.Annotation], + () => typeOf[scala.io.BufferedSource], + () => typeOf[scala.io.Codec]) + val perms = types.permutations.toList + def force(lazytpe: () => Type): String = { + lazytpe().typeSymbol.typeSignature + lazytpe().toString + } + val diceRolls = List.fill(n)(rng.nextInt(perms.length)) + val threads = (1 to n) map (i => new Thread(s"Reflector-$i") { + override def run(): Unit = { + val s1 = foo("42") + val s2 = perms(diceRolls(i - 1)).map(x => force(x)).sorted.mkString(", ") + assert(s1 == "String" || s1 == "java.lang.String") + assert(s2 == "java.lang.annotation.Annotation, java.lang.reflect.Method, scala.io.BufferedSource, scala.io.Codec") + } + }) + threads foreach (_.start) +}
\ No newline at end of file |