Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci scripts backport to 2.11.4 #16

Closed
wants to merge 2 commits into from
Closed

ci scripts backport to 2.11.4 #16

wants to merge 2 commits into from

Conversation

adriaanm
Copy link
Owner

No description provided.

@adriaanm adriaanm closed this Jan 12, 2015
@adriaanm adriaanm reopened this Jan 12, 2015
@adriaanm adriaanm closed this Jan 12, 2015
@adriaanm adriaanm reopened this Jan 12, 2015
@adriaanm adriaanm closed this Jan 12, 2015
@adriaanm adriaanm reopened this Jan 12, 2015
@adriaanm adriaanm closed this Jan 12, 2015
@adriaanm adriaanm reopened this Jan 12, 2015
@adriaanm adriaanm closed this Jan 12, 2015
@adriaanm adriaanm reopened this Jan 12, 2015
@adriaanm
Copy link
Owner Author

ping

@adriaanm
Copy link
Owner Author

a

8 similar comments
@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm adriaanm closed this Jan 16, 2015
@adriaanm adriaanm reopened this Jan 16, 2015
@adriaanm
Copy link
Owner Author

a

5 similar comments
@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm
Copy link
Owner Author

a

@adriaanm adriaanm closed this Jan 16, 2015
cunei pushed a commit to cunei/scala that referenced this pull request May 19, 2015
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
adriaanm pushed a commit that referenced this pull request Aug 3, 2015
And do the same for the specialized variants.

Tested by a Java source file that uses lambda syntax to create
instances of generic and specialized `Function{0,1}`.

Here's how the interfaces look now:

```
% javap -c -classpath /tmp/function 'scala.Function1'
Compiled from "Function1.scala"
public interface scala.Function1<T1, R> {
  public abstract R apply(T1);

  public <A> scala.Function1<A, R> compose(scala.Function1<A, T1>);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #18                 // Method scala/Function1$class.compose:(Lscala/Function1;Lscala/Function1;)Lscala/Function1;
       5: areturn

  public <A> scala.Function1<T1, A> andThen(scala.Function1<R, A>);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #24                 // Method scala/Function1$class.andThen:(Lscala/Function1;Lscala/Function1;)Lscala/Function1;
       5: areturn

  public abstract java.lang.String toString();

  public int apply$mcII$sp(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokestatic  scala#110                // Method scala/Function1$class.apply$mcII$sp:(Lscala/Function1;I)I
       5: ireturn

  public long apply$mcJI$sp(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokestatic  scala#115                // Method scala/Function1$class.apply$mcJI$sp:(Lscala/Function1;I)J
       5: lreturn
    ...
}

% javap -c -classpath /tmp/function 'scala.Function1$mcII$sp'
Compiled from "Function1.scala"
public interface scala.Function1$mcII$sp extends scala.Function1<java.lang.Object, java.lang.Object> {
  public java.lang.Object apply(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #16                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
       5: invokeinterface #19,  2           // InterfaceMethod apply:(I)I
      10: invokestatic  #23                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
      13: areturn

  public abstract int apply$mcII$sp(int);

  public int apply(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokeinterface scala#30,  2           // InterfaceMethod apply$mcII$sp:(I)I
       7: ireturn
}
```
adriaanm pushed a commit that referenced this pull request Aug 8, 2015
And do the same for the specialized variants.

Tested by a Java source file that uses lambda syntax to create
instances of generic and specialized `Function{0,1}`.

Here's how the interfaces look now:

```
% javap -c -classpath /tmp/function 'scala.Function1'
Compiled from "Function1.scala"
public interface scala.Function1<T1, R> {
  public abstract R apply(T1);

  public <A> scala.Function1<A, R> compose(scala.Function1<A, T1>);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #18                 // Method scala/Function1$class.compose:(Lscala/Function1;Lscala/Function1;)Lscala/Function1;
       5: areturn

  public <A> scala.Function1<T1, A> andThen(scala.Function1<R, A>);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #24                 // Method scala/Function1$class.andThen:(Lscala/Function1;Lscala/Function1;)Lscala/Function1;
       5: areturn

  public abstract java.lang.String toString();

  public int apply$mcII$sp(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokestatic  scala#110                // Method scala/Function1$class.apply$mcII$sp:(Lscala/Function1;I)I
       5: ireturn

  public long apply$mcJI$sp(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokestatic  scala#115                // Method scala/Function1$class.apply$mcJI$sp:(Lscala/Function1;I)J
       5: lreturn
    ...
}

% javap -c -classpath /tmp/function 'scala.Function1$mcII$sp'
Compiled from "Function1.scala"
public interface scala.Function1$mcII$sp extends scala.Function1<java.lang.Object, java.lang.Object> {
  public java.lang.Object apply(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #16                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
       5: invokeinterface #19,  2           // InterfaceMethod apply:(I)I
      10: invokestatic  #23                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
      13: areturn

  public abstract int apply$mcII$sp(int);

  public int apply(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokeinterface scala#30,  2           // InterfaceMethod apply$mcII$sp:(I)I
       7: ireturn
}
```
@adriaanm adriaanm deleted the 2.11.4-ci branch September 2, 2015 23:20
adriaanm pushed a commit that referenced this pull request Sep 2, 2015
And do the same for the specialized variants.

Tested by a Java source file that uses lambda syntax to create
instances of generic and specialized `Function{0,1}`.

Here's how the interfaces look now:

```
% javap -c -classpath /tmp/function 'scala.Function1'
Compiled from "Function1.scala"
public interface scala.Function1<T1, R> {
  public abstract R apply(T1);

  public <A> scala.Function1<A, R> compose(scala.Function1<A, T1>);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #18                 // Method scala/Function1$class.compose:(Lscala/Function1;Lscala/Function1;)Lscala/Function1;
       5: areturn

  public <A> scala.Function1<T1, A> andThen(scala.Function1<R, A>);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #24                 // Method scala/Function1$class.andThen:(Lscala/Function1;Lscala/Function1;)Lscala/Function1;
       5: areturn

  public abstract java.lang.String toString();

  public int apply$mcII$sp(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokestatic  scala#110                // Method scala/Function1$class.apply$mcII$sp:(Lscala/Function1;I)I
       5: ireturn

  public long apply$mcJI$sp(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokestatic  scala#115                // Method scala/Function1$class.apply$mcJI$sp:(Lscala/Function1;I)J
       5: lreturn
    ...
}

% javap -c -classpath /tmp/function 'scala.Function1$mcII$sp'
Compiled from "Function1.scala"
public interface scala.Function1$mcII$sp extends scala.Function1<java.lang.Object, java.lang.Object> {
  public java.lang.Object apply(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #16                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
       5: invokeinterface #19,  2           // InterfaceMethod apply:(I)I
      10: invokestatic  #23                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
      13: areturn

  public abstract int apply$mcII$sp(int);

  public int apply(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokeinterface scala#30,  2           // InterfaceMethod apply$mcII$sp:(I)I
       7: ireturn
}
```
adriaanm pushed a commit that referenced this pull request Mar 30, 2016
Rather than in implementation of the abstract method in the
expanded anonymous class.

This leads to more more efficient use of the constant pool,
code shapes more amenable to SAM inlining, and is compatible
with the old behaviour of `-Xexperimental` in Scala 2.11,
which ScalaJS now relies upon.

Manual test:

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

package p1; trait T { val x = 0; def apply(): Any }; class DelambdafyInline { def t: T = (() => "") }

// Exiting paste mode, now interpreting.

scala> :javap -c p1.DelambdafyInline
Compiled from "<pastie>"
public class p1.DelambdafyInline {
  public p1.T t();
    Code:
       0: new           #10                 // class p1/DelambdafyInline$$anonfun$t$1
       3: dup
       4: aload_0
       5: invokespecial #16                 // Method p1/DelambdafyInline$$anonfun$t$1."<init>":(Lp1/DelambdafyInline;)V
       8: areturn

  public final java.lang.Object p1$DelambdafyInline$$$anonfun$1();
    Code:
       0: ldc           #22                 // String
       2: areturn

  public p1.DelambdafyInline();
    Code:
       0: aload_0
       1: invokespecial #25                 // Method java/lang/Object."<init>":()V
       4: return
}

scala> :javap -c p1.DelambdafyInline$$anonfun$t$1
Compiled from "<pastie>"
public final class p1.DelambdafyInline$$anonfun$t$1 implements p1.T,scala.Serializable {
  public static final long serialVersionUID;

  public int x();
    Code:
       0: aload_0
       1: getfield      #25                 // Field x:I
       4: ireturn

  public void p1$T$_setter_$x_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #25                 // Field x:I
       5: return

  public final java.lang.Object apply();
    Code:
       0: aload_0
       1: getfield      scala#34                 // Field $outer:Lp1/DelambdafyInline;
       4: invokevirtual scala#37                 // Method p1/DelambdafyInline.p1$DelambdafyInline$$$anonfun$1:()Ljava/lang/Object;
       7: areturn

  public p1.DelambdafyInline$$anonfun$t$1(p1.DelambdafyInline);
    Code:
       0: aload_1
       1: ifnonnull     6
       4: aconst_null
       5: athrow
       6: aload_0
       7: aload_1
       8: putfield      scala#34                 // Field $outer:Lp1/DelambdafyInline;
      11: aload_0
      12: invokespecial scala#42                 // Method java/lang/Object."<init>":()V
      15: aload_0
      16: invokespecial scala#45                 // Method p1/T.$init$:()V
      19: return
}

scala> :quit
```
adriaanm pushed a commit that referenced this pull request Mar 30, 2016
Rather than in implementation of the abstract method in the
expanded anonymous class.

This leads to more more efficient use of the constant pool,
code shapes more amenable to SAM inlining, and is compatible
with the old behaviour of `-Xexperimental` in Scala 2.11,
which ScalaJS now relies upon.

Manual test:

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

package p1; trait T { val x = 0; def apply(): Any }; class DelambdafyInline { def t: T = (() => "") }

// Exiting paste mode, now interpreting.

scala> :javap -c p1.DelambdafyInline
Compiled from "<pastie>"
public class p1.DelambdafyInline {
  public p1.T t();
    Code:
       0: new           #10                 // class p1/DelambdafyInline$$anonfun$t$1
       3: dup
       4: aload_0
       5: invokespecial #16                 // Method p1/DelambdafyInline$$anonfun$t$1."<init>":(Lp1/DelambdafyInline;)V
       8: areturn

  public final java.lang.Object p1$DelambdafyInline$$$anonfun$1();
    Code:
       0: ldc           #22                 // String
       2: areturn

  public p1.DelambdafyInline();
    Code:
       0: aload_0
       1: invokespecial #25                 // Method java/lang/Object."<init>":()V
       4: return
}

scala> :javap -c p1.DelambdafyInline$$anonfun$t$1
Compiled from "<pastie>"
public final class p1.DelambdafyInline$$anonfun$t$1 implements p1.T,scala.Serializable {
  public static final long serialVersionUID;

  public int x();
    Code:
       0: aload_0
       1: getfield      #25                 // Field x:I
       4: ireturn

  public void p1$T$_setter_$x_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #25                 // Field x:I
       5: return

  public final java.lang.Object apply();
    Code:
       0: aload_0
       1: getfield      scala#34                 // Field $outer:Lp1/DelambdafyInline;
       4: invokevirtual scala#37                 // Method p1/DelambdafyInline.p1$DelambdafyInline$$$anonfun$1:()Ljava/lang/Object;
       7: areturn

  public p1.DelambdafyInline$$anonfun$t$1(p1.DelambdafyInline);
    Code:
       0: aload_1
       1: ifnonnull     6
       4: aconst_null
       5: athrow
       6: aload_0
       7: aload_1
       8: putfield      scala#34                 // Field $outer:Lp1/DelambdafyInline;
      11: aload_0
      12: invokespecial scala#42                 // Method java/lang/Object."<init>":()V
      15: aload_0
      16: invokespecial scala#45                 // Method p1/T.$init$:()V
      19: return
}

scala> :quit
```

Adriaan is to `git blame` for `reflection-mem-typecheck.scala`.
adriaanm pushed a commit that referenced this pull request Aug 19, 2016
  - Avoid boxing the {Object, Int, ...}Ref itself by storing it in
    a val, not a var
  - Avoid box/unbox of primitive lazy expressions due which are added
    to "adapt" it to the erased type of the fictional syncronized
    method, by using a `return`. We have to add a dummy throw after
    the synchronized block, but this is elimnated by the always-on
    DCE in the code generator.

```
⚡  qscalac -Xprint:mixin $(f "class C { def foo = { lazy val x = 42; x }}"); javap -private -c -cp . C
[[syntax trees at end of                     mixin]] // a.scala
package <empty> {
  class C extends Object {
    def foo(): Int = {
      lazy <artifact> val x$lzy: scala.runtime.LazyInt = new scala.runtime.LazyInt();
      C.this.x$1(x$lzy)
    };
    final private[this] def x$1(x$lzy$1: scala.runtime.LazyInt): Int = {
      x$lzy$1.synchronized({
        if (x$lzy$1.initialized().unary_!())
          {
            x$lzy$1.initialized_=(true);
            x$lzy$1.value_=(42)
          };
        return x$lzy$1.value()
      });
      throw null
    };
    def <init>(): C = {
      C.super.<init>();
      ()
    }
  }
}

Compiled from "a.scala"
public class C {
  public int foo();
    Code:
       0: new           #12                 // class scala/runtime/LazyInt
       3: dup
       4: invokespecial #16                 // Method scala/runtime/LazyInt."<init>":()V
       7: astore_1
       8: aload_1
       9: invokestatic  #20                 // Method x$1:(Lscala/runtime/LazyInt;)I
      12: ireturn

  private static final int x$1(scala.runtime.LazyInt);
    Code:
       0: aload_0
       1: dup
       2: astore_1
       3: monitorenter
       4: aload_0
       5: invokevirtual scala#31                 // Method scala/runtime/LazyInt.initialized:()Z
       8: ifne          22
      11: aload_0
      12: iconst_1
      13: invokevirtual scala#35                 // Method scala/runtime/LazyInt.initialized_$eq:(Z)V
      16: aload_0
      17: bipush        42
      19: invokevirtual scala#39                 // Method scala/runtime/LazyInt.value_$eq:(I)V
      22: aload_0
      23: invokevirtual scala#42                 // Method scala/runtime/LazyInt.value:()I
      26: istore_2
      27: goto          33
      30: aload_1
      31: monitorexit
      32: athrow
      33: aload_1
      34: monitorexit
      35: iload_2
      36: ireturn
    Exception table:
       from    to  target type
           4    30    30   Class java/lang/Throwable

  public C();
    Code:
       0: aload_0
       1: invokespecial scala#43                 // Method java/lang/Object."<init>":()V
       4: return
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant