2011-06-27 17 views
9

Po sugestii extempore niedawno o tym, jak dostać scala mi powiedzieć, czy istnieje boks dzieje patrząc na kod bajtowy, stworzyłem tę klasę:Jak rozpoznać boks/unboxing w Scala

class X { def foo(ls : Array[Long]) = ls map (_.toDouble) 

Gdyby spojrzeć na kod bajtowy dla foo:

public double[] foo(long[]); 
    Code: 
    Stack=4, Locals=2, Args_size=2 
    0: getstatic  #11; //Field scala/Predef$.MODULE$:Lscala/Predef$; 
    3: aload_1 
    4: invokevirtual #16; //Method scala/Predef$.longArrayOps:([J)Lscala/collection/mutable/ArrayOps; 
    7: new  #18; //class X$$anonfun$foo$1 
    10: dup 
    11: aload_0 
    12: invokespecial #22; //Method X$$anonfun$foo$1."<init>":(LX;)V 
    15: getstatic  #27; //Field scala/Array$.MODULE$:Lscala/Array$; 
    18: getstatic  #32; //Field scala/reflect/Manifest$.MODULE$:Lscala/reflect/Manifest$; 
    21: invokevirtual #36; //Method scala/reflect/Manifest$.Double:()Lscala/reflect/AnyValManifest; 
    24: invokevirtual #40; //Method scala/Array$.canBuildFrom:(Lscala/reflect/ClassManifest;)Lscala/collection/generic/CanBuildFrom; 
    27: invokeinterface #46, 3; //InterfaceMethod scala/collection/TraversableLike.map:(Lscala/Function1;Lscala/collection/generic/CanBuildFrom;)Ljava/lan         g/Object; 
    32: checkcast  #48; //class "[D" 
    35: areturn 
    LineNumberTable: 
    line 7: 0 

żadnych oznak box/unbox tam. Ale nadal jestem podejrzliwy, więc skompilowany z -print():

[[syntax trees at end of cleanup]]// Scala source: X.scala 
package <empty> { 
    class X extends java.lang.Object with ScalaObject { 
    def foo(ls: Array[Long]): Array[Double] = scala.this.Predef.longArrayOps(ls).map({ 
(new anonymous class X$$anonfun$foo$1(X.this): Function1) 
}, scala.this.Array.canBuildFrom(reflect.this.Manifest.Double())).$asInstanceOf[Array[Double]](); 
    def this(): X = { 
    X.super.this(); 
    () 
    } 
}; 
@SerialVersionUID(0) final <synthetic> class X$$anonfun$foo$1 extends scala.runtime.AbstractFunction1$mcDJ$sp with Serializable { 
    final def apply(x$1: Long): Double = X$$anonfun$foo$1.this.apply$mcDJ$sp(x$1); 
    <specialized> def apply$mcDJ$sp(v1: Long): Double = v1.toDouble(); 
    final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Double.box(X$$anonfun$foo$1.this.apply(scala.Long.unbox(v1))); 
    def this($outer: X): anonymous class X$$anonfun$foo$1 = { 
     X$$anonfun$foo$1.super.this(); 
    () 
    } 
    } 
} 

Główne uwagi na temat tego kodu, że stworzona została funkcja anonimowa specjalistyczne dla Long => Double i że funkcjonalność map jest świadczona przez longArrayOps(ls).map (ArrayOps to nie wyspecjalizowany).

Pytanie brzmi:: "czy w tym przykładzie występuje boxing/unboxing?"

Odpowiedz

6

Prawdopodobnie boks się dzieje. Trzeba patrzeć na miejscu, w którym rzeczywista map-Call jest wykonana:

27: invokeinterface #46, 3; //InterfaceMethod scala/collection/TraversableLike.map:(Lscala/Function1;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object; 

Na starcie powinno to iść do ArrayOps#ofLong. Ponieważ ArrayOps nie jest wyspecjalizowany, jest mało prawdopodobne, że Twój telefon map przejdzie bez boksu.

Aby się przekonać, możesz spróbować połączyć się z kodami bajtowymi (może być to trudne, ponieważ tak jak w twojej funkcji możesz napotkać ekspedycję runtime) lub przejść przez debugger (trudne, ponieważ większość debugerów nie wyświetla się kod bajtowy, jednak możliwe jest ustawienie punktów przerwania w metodach boksowania Scala lub Java).

Ze względów praktycznych okazało się, że może to być nieistotne, jeśli boxing jest wykonywany w bajtodzie, ponieważ w przypadku metod gorących kompilator Hotspot może czasami całkowicie zainicjować standardowy łańcuch wywołań funkcji wyższego rzędu, w którym to przypadku można wyeliminować boksowanie.

+2

Skąd wiesz na pewno, że HotSpot to robił? –

2

Możesz użyć profilera (jvisualvm jest darmowy z Oracle SDK), aby wyszukać boks/rozpakować. Zaletą jest to, że zauważysz tylko odpowiednie boksowanie - nic, co dzieje się tylko kilka razy i nic, co nie zostanie zoptymalizowane przez HotSpot.

Cóż, nie jestem całkowicie pewien tego ostatniego, ale spodziewam się, że prawdopodobnie JIT będzie nadal używany podczas korzystania z profilera próbkowania (który zapewnia również jvisualvm).

Powiązane problemy