Skip to content

Commit 33393c7

Browse files
committed
SI-8933 Disable static Symbol literal cache in traits
In Scala 2.8.2, an optimization was added to create a static cache for Symbol literals (ie, the results of `Symbol.apply("foo"))`. This saves the map lookup on the second pass through code. This actually was broken somewhere during the Scala 2.10 series, after the addition of an overloaded `apply` method to `Symbol`. The cache synthesis code was made aware of the overload and brought back to working condition recently, in scala#3149. However, this has uncovered a latent bug when the Symbol literals are defined with traits. One of the enclosed tests failed with: jvm > t8933b-run.log java.lang.IllegalAccessError: tried to access field MotherClass.symbol$1 from class MixinWithSymbol$class at MixinWithSymbol$class.symbolFromTrait(A.scala:3) at MotherClass.symbolFromTrait(Test.scala:1) This commit simply disables the optimization if we are in a trait. Alternative fixes might be: a) make the static Symbol cache field public / b) "mixin" the static symbol cache. Neither of these seem worth the effort and risk for an already fairly situational optimization. Here's how the optimization looks in a class: % cat sandbox/test.scala; qscalac sandbox/test.scala && echo ":javap C" | qscala; class C { 'a; 'b } Welcome to Scala version 2.11.5-20141106-145558-aa558dce6d (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_20). Type in expressions to have them evaluated. Type :help for more information. scala> :javap C Size 722 bytes MD5 checksum 6bb00189166917254e8d40499ee7c887 Compiled from "test.scala" public class C { public static {}; descriptor: ()V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=0, args_size=0 0: getstatic adriaanm#16 // Field scala/Symbol$.MODULE$:Lscala/Symbol$; 3: ldc adriaanm#18 // String a 5: invokevirtual adriaanm#22 // Method scala/Symbol$.apply:(Ljava/lang/String;)Lscala/Symbol; 8: putstatic adriaanm#26 // Field symbol$1:Lscala/Symbol; 11: getstatic adriaanm#16 // Field scala/Symbol$.MODULE$:Lscala/Symbol$; 14: ldc scala#28 // String b 16: invokevirtual adriaanm#22 // Method scala/Symbol$.apply:(Ljava/lang/String;)Lscala/Symbol; 19: putstatic scala#31 // Field symbol$2:Lscala/Symbol; 22: return public C(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial scala#34 // Method java/lang/Object."<init>":()V 4: getstatic adriaanm#26 // Field symbol$1:Lscala/Symbol; 7: pop 8: getstatic scala#31 // Field symbol$2:Lscala/Symbol; 11: pop 12: return } fixup
1 parent ced9e16 commit 33393c7

File tree

6 files changed

+31
-1
lines changed

6 files changed

+31
-1
lines changed

src/compiler/scala/tools/nsc/transform/CleanUp.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
520520
* And, finally, be advised - Scala's Symbol literal (scala.Symbol) and the Symbol class of the compiler
521521
* have little in common.
522522
*/
523-
case Apply(fn, (arg @ Literal(Constant(symname: String))) :: Nil) if fn.symbol == Symbol_apply =>
523+
case Apply(fn, (arg @ Literal(Constant(symname: String))) :: Nil) if fn.symbol == Symbol_apply && !currentClass.isTrait =>
524524
def transformApply = {
525525
// add the symbol name to a map if it's not there already
526526
val rhs = gen.mkMethodCall(Symbol_apply, arg :: Nil)

test/files/run/t8933.check

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
'traitSymbol

test/files/run/t8933/A_1.scala

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class MotherClass
2+
3+
trait MixinWithSymbol {
4+
self: MotherClass =>
5+
def symbolFromTrait: Symbol = 'traitSymbol
6+
}

test/files/run/t8933/Test_2.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class MotherClass extends MixinWithSymbol {
2+
val classSymbol = 'classSymbol
3+
}
4+
5+
object Test {
6+
def main(args: Array[String]) {
7+
val symbol = (new MotherClass).symbolFromTrait
8+
println(symbol)
9+
}
10+
}

test/files/run/t8933b/A.scala

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
trait MixinWithSymbol {
2+
self: MotherClass =>
3+
def symbolFromTrait: Any = 'traitSymbol
4+
}

test/files/run/t8933b/Test.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class MotherClass extends MixinWithSymbol {
2+
def foo = 'sym1
3+
}
4+
5+
object Test {
6+
def main(args: Array[String]) {
7+
(new MotherClass).symbolFromTrait
8+
}
9+
}

0 commit comments

Comments
 (0)