Come riconoscere il boxing/unboxing in un codice Scala decompilato?
Domanda
Nella migliore risposta accettata a questa domanda, c'è una chiara spiegazione del perché si verifica la boxe.
Tuttavia, se decompilo il codice (usando il decompiler Java) non riesco a vedere l'uso di scala.runtime.BoxesRunTime.Inoltre, se profiliamo il codice (utilizzando JProfiler) non riesco a vedere alcuna istanza di BoxesRunTime.
Quindi, come posso vedere realmente una prova dell'avvenuto inscatolamento/unboxing?
Soluzione
In questo codice:
class Foo[T] {
def bar(i: T) = i
}
object Main {
def main(args: Array[String]) {
val f = new Foo[Int]
f.bar(5)
}
}
L'invocazione di bar
dovrebbe prima racchiudere il numero intero.Compilando con Scala 2.8.1 e utilizzando:
javap -c -l -private -verbose -classpath <dir> Main$
per vedere il bytecode prodotto per il main
metodo del Main
rendimento della classe:
public void main(java.lang.String[]);
...
9: iconst_5
10: invokestatic #24; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
13: invokevirtual #28; //Method Foo.bar:(Ljava/lang/Object;)Ljava/lang/Object;
16: pop
17: return
...
Puoi vedere la chiamata a BoxesRunTime
prima della chiamata a bar
.
BoxesRunTime
è un oggetto che contiene metodi di boxing per i tipi primitivi, quindi dovrebbe esserci esattamente un'istanza in totale.Il problema qui è che questo particolare file nella libreria è stato scritto in Java e le conversioni sono metodi statici.Per questo motivo non ce ne sono istanze in fase di runtime, anche se usarlo nel codice Scala sembra come se fosse un oggetto.
Probabilmente dovresti cercare primitive boxed (ad es.java.lang.Integer) con JProfile, anche se non sono sicuro di come funzioni la JVM e se possa effettivamente riscrivere il codice in fase di esecuzione e ottimizzarlo per evitare il boxing.Per quanto ne so, non dovrebbe applicare la specializzazione (ma credo che CLR lo faccia).Alcuni microbenchmark con e senza la situazione del boxing sono un altro modo per capire cosa succede in fase di esecuzione.
MODIFICARE:
Quanto sopra presuppone che un parametro di tipo non sia stato annotato con il file @specialized
annotazione.In questo caso il boxing/unboxing può essere evitato.Alcune classi nella libreria standard sono specializzate.Vedere questo sid.
Altri suggerimenti
Dato il seguente programma Test.Scala:
object Test {
def main(args:Array[String]) {
val list = List(1,5,15)
val res = list.map(e => e*2).filter(e => e>10)
}
}
Se compilo con scalac -Xprint:jvm Test.scala
, Ottengo questo frammento che suggerisce che si verifica la specializzazione (scusate per la pasta larga):
package <empty> {
final class Test extends java.lang.Object with ScalaObject {
def main(args: Array[java.lang.String]): Unit = {
val list: List = immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1, 5, 15}));
val res: List = list.map({
(new Test$$anonfun$1(): Function1)
}, immutable.this.List.canBuildFrom()).$asInstanceOf[scala.collection.TraversableLike]().filter({
(new Test$$anonfun$2(): Function1)
}).$asInstanceOf[List]();
()
};
def this(): object Test = {
Test.super.this();
()
}
};
@SerialVersionUID(0) @serializable final <synthetic> class Test$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp {
final def apply(e: Int): Int = Test$$anonfun$1.this.apply$mcII$sp(e);
<specialized> def apply$mcII$sp(v1: Int): Int = v1.*(2);
final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Int.box(Test$$anonfun$1.this.apply(scala.Int.unbox(v1)));
def this(): Test$$anonfun$1 = {
Test$$anonfun$1.super.this();
()
}
};
@SerialVersionUID(0) @serializable final <synthetic> class Test$$anonfun$2 extends scala.runtime.AbstractFunction1$mcZI$sp {
final def apply(e: Int): Boolean = Test$$anonfun$2.this.apply$mcZI$sp(e);
<specialized> def apply$mcZI$sp(v1: Int): Boolean = v1.>(10);
final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Boolean.box(Test$$anonfun$2.this.apply(scala.Int.unbox(v1)));
def this(): Test$$anonfun$2 = {
Test$$anonfun$2.super.this();
()
}
}
}
Potrebbe essere il motivo per cui non vedi alcuna prova della boxe in bytecode ...