Skip to content

SI-9824 SI-9814 proper locking scope for lazy vals in lambdas #133

Closed
@adriaanm

Description

@adriaanm

Consolidating comments from #161 and #177:

  • SI-9824 deadlock using parallel collections with delambdafy:method
  • SI-9814 Function0 doesn't synchronize properly

solution

Let users opt-in to old encoding + feature in release notes.

a look at the byte code

lazy val in closure has different locking scope due to delambdafy:method. It used to be the anonymous function class:

Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_71).
Type in expressions for evaluation. Or try :help.

scala> :paste -raw
// Entering paste mode (ctrl-D to finish)

package p; class C { def foo = () => { lazy val x = 42; x } }

// Exiting paste mode, now interpreting.


scala> new p.C().foo
res0: () => Int = <function0>

scala> new p.C().foo.getClass
res1: Class[_ <: () => Int] = class p.C$$anonfun$foo$1

scala> :javap -private -c p.C$$anonfun$foo$1
Compiled from "<pastie>"
public final class p.C$$anonfun$foo$1 extends scala.runtime.AbstractFunction0$mcI$sp implements scala.Serializable {
  public static final long serialVersionUID;

  public final int apply();
    Code:
       0: aload_0
       1: invokevirtual #21                 // Method apply$mcI$sp:()I
       4: ireturn

  public int apply$mcI$sp();
    Code:
       0: invokestatic  #29                 // Method scala/runtime/IntRef.zero:()Lscala/runtime/IntRef;
       3: astore_1
       4: iconst_0
       5: invokestatic  #35                 // Method scala/runtime/VolatileByteRef.create:(B)Lscala/runtime/VolatileByteRef;
       8: astore_2
       9: aload_0
      10: aload_1
      11: aload_2
      12: invokespecial #39                 // Method x$1:(Lscala/runtime/IntRef;Lscala/runtime/VolatileByteRef;)I
      15: ireturn

  public final java.lang.Object apply();
    Code:
       0: aload_0
       1: invokevirtual #46                 // Method apply:()I
       4: invokestatic  #52                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
       7: areturn

  private final int x$lzycompute$1(scala.runtime.IntRef, scala.runtime.VolatileByteRef);
    Code:
       0: aload_0
       1: dup
       2: astore_3
       3: monitorenter
       4: aload_2
       5: getfield      #57                 // Field scala/runtime/VolatileByteRef.elem:B
       8: iconst_1
       9: iand
      10: i2b
      11: iconst_0
      12: if_icmpne     32
      15: aload_1
      16: bipush        42
      18: putfield      #60                 // Field scala/runtime/IntRef.elem:I
      21: aload_2
      22: aload_2
      23: getfield      #57                 // Field scala/runtime/VolatileByteRef.elem:B
      26: iconst_1
      27: ior
      28: i2b
      29: putfield      #57                 // Field scala/runtime/VolatileByteRef.elem:B
      32: getstatic     #66                 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
      35: pop
      36: aload_3
      37: monitorexit
      38: aload_1
      39: getfield      #60                 // Field scala/runtime/IntRef.elem:I
      42: ireturn
      43: aload_3
      44: monitorexit
      45: athrow
    Exception table:
       from    to  target type
           4    38    43   any

But is now the enclosing class of the lambda:

⚡ ~/scala/2.12/bin/scala
Welcome to Scala 2.12.0-M4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_71).
Type in expressions for evaluation. Or try :help.

scala> :paste -raw
// Entering paste mode (ctrl-D to finish)

package p; class C { def foo = () => { lazy val x = 42; x } }

// Exiting paste mode, now interpreting.


scala> :javap -private -c p.C
Compiled from "<pastie>"
public class p.C {
  public scala.Function0<java.lang.Object> foo();
    Code:
       0: aload_0
       1: invokedynamic #37,  0             // InvokeDynamic #0:apply$mcI$sp:(Lp/C;)Lscala/runtime/java8/JFunction0$mcI$sp;
       6: areturn

  private final int x$lzycompute$1(scala.runtime.IntRef, scala.runtime.VolatileByteRef);
    Code:
       0: aload_0
       1: dup
       2: astore_3
       3: monitorenter
       4: aload_2
       5: getfield      #51                 // Field scala/runtime/VolatileByteRef.elem:B
       8: iconst_1
       9: iand
      10: i2b
      11: iconst_0
      12: if_icmpne     32
      15: aload_1
      16: bipush        42
      18: putfield      #56                 // Field scala/runtime/IntRef.elem:I
      21: aload_2
      22: aload_2
      23: getfield      #51                 // Field scala/runtime/VolatileByteRef.elem:B
      26: iconst_1
      27: ior
      28: i2b
      29: putfield      #51                 // Field scala/runtime/VolatileByteRef.elem:B
      32: getstatic     #62                 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
      35: pop
      36: aload_3
      37: monitorexit
      38: goto          44
      41: aload_3
      42: monitorexit
      43: athrow
      44: aload_1
      45: getfield      #56                 // Field scala/runtime/IntRef.elem:I
      48: ireturn
    Exception table:
       from    to  target type
           4    36    41   Class java/lang/Throwable

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions