Created
April 17, 2016 10:14
-
-
Save tkellogg/59d29579e33f30b42092f7855f3e1e65 to your computer and use it in GitHub Desktop.
Scala's lazy val is not thread safe. See line 65, I don't see anything related to synchronization.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
~> scala | |
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66). | |
Type in expressions to have them evaluated. | |
Type :help for more information. | |
scala> class Foo { lazy val bar = 2 } | |
defined class Foo | |
scala> :javap Foo | |
Size 831 bytes | |
MD5 checksum 14727318592c9c4a86120db0d8e942af | |
Compiled from "<console>" | |
public class Foo | |
minor version: 0 | |
major version: 50 | |
flags: ACC_PUBLIC, ACC_SUPER | |
Constant pool: | |
#1 = Utf8 Foo | |
#2 = Class #1 // Foo | |
#3 = Utf8 java/lang/Object | |
#4 = Class #3 // java/lang/Object | |
#5 = Utf8 <console> | |
#6 = Utf8 bar | |
#7 = Utf8 I | |
#8 = Utf8 bitmap$0 | |
#9 = Utf8 Z | |
#10 = Utf8 bar$lzycompute | |
#11 = Utf8 ()I | |
#12 = NameAndType #8:#9 // bitmap$0:Z | |
#13 = Fieldref #2.#12 // Foo.bitmap$0:Z | |
#14 = NameAndType #6:#7 // bar:I | |
#15 = Fieldref #2.#14 // Foo.bar:I | |
#16 = Utf8 scala/runtime/BoxedUnit | |
#17 = Class #16 // scala/runtime/BoxedUnit | |
#18 = Utf8 UNIT | |
#19 = Utf8 Lscala/runtime/BoxedUnit; | |
#20 = NameAndType #18:#19 // UNIT:Lscala/runtime/BoxedUnit; | |
#21 = Fieldref #17.#20 // scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit; | |
#22 = Utf8 this | |
#23 = Utf8 LFoo; | |
#24 = Utf8 java/lang/Throwable | |
#25 = Class #24 // java/lang/Throwable | |
#26 = NameAndType #10:#11 // bar$lzycompute:()I | |
#27 = Methodref #2.#26 // Foo.bar$lzycompute:()I | |
#28 = Utf8 <init> | |
#29 = Utf8 ()V | |
#30 = NameAndType #28:#29 // "<init>":()V | |
#31 = Methodref #4.#30 // java/lang/Object."<init>":()V | |
#32 = Utf8 | |
#33 = Class #32 // | |
#34 = Utf8 $line3/$read | |
#35 = Class #34 // $line3/$read | |
#36 = Utf8 | |
#37 = Utf8 | |
#38 = Class #37 // | |
#39 = Utf8 Foo | |
#40 = Utf8 Code | |
#41 = Utf8 LocalVariableTable | |
#42 = Utf8 LineNumberTable | |
#43 = Utf8 StackMapTable | |
#44 = Utf8 SourceFile | |
#45 = Utf8 InnerClasses | |
#46 = Utf8 Scala | |
{ | |
public int bar(); | |
descriptor: ()I | |
flags: ACC_PUBLIC | |
Code: | |
stack=1, locals=1, args_size=1 | |
0: aload_0 | |
1: getfield #13 // Field bitmap$0:Z | |
4: ifeq 14 | |
7: aload_0 | |
8: getfield #15 // Field bar:I | |
11: goto 18 | |
14: aload_0 | |
15: invokespecial #27 // Method bar$lzycompute:()I | |
18: ireturn | |
LocalVariableTable: | |
Start Length Slot Name Signature | |
0 19 0 this LFoo; | |
LineNumberTable: | |
line 7: 0 | |
StackMapTable: number_of_entries = 2 | |
frame_type = 14 /* same */ | |
frame_type = 67 /* same_locals_1_stack_item */ | |
stack = [ int ] | |
public Foo(); | |
descriptor: ()V | |
flags: ACC_PUBLIC | |
Code: | |
stack=1, locals=1, args_size=1 | |
0: aload_0 | |
1: invokespecial #31 // Method java/lang/Object."<init>":()V | |
4: return | |
LocalVariableTable: | |
Start Length Slot Name Signature | |
0 5 0 this LFoo; | |
LineNumberTable: | |
line 11: 0 | |
} | |
SourceFile: "<console>" | |
InnerClasses: | |
public static #36= #33 of #35; //=class of class $line3/$read | |
public static #36= #38 of #33; //=class of class | |
public static #39= #2 of #38; //Foo=class Foo of class | |
Error: unknown attribute | |
Scala: length = 0x0 | |
class Something {
lazy val foo = getFoo
def getFoo = "foo!"
}
Using procyon-decompiler
, this produces the following:
import scala.reflect.*;
import scala.runtime.*;
//
// Decompiled by Procyon v0.5.30
//
@ScalaSignature(bytes = "\u0006\u0001\u00012A!\u0001\u0002\u0001\u000b\tI1k\\7fi\"Lgn\u001a\u0006\u0002\u0007\u00059A(Z7qift4\u0001A\n\u0003\u0001\u0019\u0001\"a\u0002\u0006\u000e\u0003!Q\u0011!C\u0001\u0006g\u000e\fG.Y\u0005\u0003\u0017!\u0011a!\u00118z%\u00164\u0007\"B\u0007\u0001\t\u0003q\u0011A\u0002\u001fj]&$h\bF\u0001\u0010!\t\u0001\u0002!D\u0001\u0003\u0011!\u0011\u0002\u0001#b\u0001\n\u0003\u0019\u0012a\u00014p_V\tA\u0003\u0005\u0002\u001655\taC\u0003\u0002\u00181\u0005!A.\u00198h\u0015\u0005I\u0012\u0001\u00026bm\u0006L!a\u0007\f\u0003\rM#(/\u001b8h\u0011!i\u0002\u0001#A!B\u0013!\u0012\u0001\u00024p_\u0002BQa\b\u0001\u0005\u0002M\taaZ3u\r>|\u0007")
public class Something
{
private String foo;
private volatile boolean bitmap$0;
private String foo$lzycompute() {
synchronized (this) {
if (!this.bitmap$0) {
this.foo = this.getFoo();
this.bitmap$0 = true;
}
final BoxedUnit unit = BoxedUnit.UNIT;
return this.foo;
}
}
public String foo() {
return this.bitmap$0 ? this.foo : this.foo$lzycompute();
}
public String getFoo() {
return "foo!";
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In line 77 it's calling
lzyCompute
. If you look at the body of that, I'm sure you'll find that it opens with amonitorenter
.