summaryrefslogtreecommitdiff
path: root/test/junit/scala/collection/mutable/OpenHashMapTest.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-08-08 11:19:34 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-08-18 10:52:02 +1000
commitbb882e7249d4b9aa0b0c92ec9058d58464f6ed7a (patch)
treee632ee5a1436e93471802229c59fd341e698ca57 /test/junit/scala/collection/mutable/OpenHashMapTest.scala
parent804133f60dd3c78909dc9e557e91b5c9923240ff (diff)
downloadscala-bb882e7249d4b9aa0b0c92ec9058d58464f6ed7a.tar.gz
scala-bb882e7249d4b9aa0b0c92ec9058d58464f6ed7a.tar.bz2
scala-bb882e7249d4b9aa0b0c92ec9058d58464f6ed7a.zip
SD-194 Tweak module initialization to comply with JVM spec
Top level modules in Scala currently desugar as: ``` class C; object O extends C { toString } ``` ``` public final class O$ extends C { public static final O$ MODULE$; public static {}; Code: 0: new #2 // class O$ 3: invokespecial #12 // Method "<init>":()V 6: return private O$(); Code: 0: aload_0 1: invokespecial #13 // Method C."<init>":()V 4: aload_0 5: putstatic #15 // Field MODULE$:LO$; 8: aload_0 9: invokevirtual #21 // Method java/lang/Object.toString:()Ljava/lang/String; 12: pop 13: return } ``` The static initalizer `<clinit>` calls the constructor `<init>`, which invokes superclass constructor, assigns `MODULE$= this`, and then runs the remainder of the object's constructor (`toString` in the example above.) It turns out that this relies on a bug in the JVM's verifier: assignment to a static final must occur lexically within the <clinit>, not from within `<init>` (even if the latter is happens to be called by the former). I'd like to move the assignment to <clinit> but that would change behaviour of "benign" cyclic references between modules. Example: ``` package p1; class CC { def foo = O.bar}; object O {new CC().foo; def bar = println(1)}; // Exiting paste mode, now interpreting. scala> p1.O 1 ``` This relies on the way that we assign MODULE$ field after the super class constructors are finished, but before the rest of the module constructor is called. Instead, this commit removes the ACC_FINAL bit from the field. It actually wasn't behaving as final at all, precisely the issue that the stricter verifier now alerts us to. ``` scala> :paste -raw // Entering paste mode (ctrl-D to finish) package p1; object O // Exiting paste mode, now interpreting. scala> val O1 = p1.O O1: p1.O.type = p1.O$@ee7d9f1 scala> scala.reflect.ensureAccessible(p1.O.getClass.getDeclaredConstructor()).newInstance() res0: p1.O.type = p1.O$@64cee07 scala> O1 eq p1.O res1: Boolean = false ``` We will still achieve safe publication of the assignment to other threads by virtue of the fact that `<clinit>` is executed within the scope of an initlization lock, as specified by: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.5 Fixes scala/scala-dev#SD-194
Diffstat (limited to 'test/junit/scala/collection/mutable/OpenHashMapTest.scala')
0 files changed, 0 insertions, 0 deletions