Comment reconnaître la boxe / déballage dans un code Scala décompilé?
Question
Dans la meilleure réponse acceptée à cette question, il y a une explication claire pourquoi la boxe se produit.
Cependant, si je décompile le code (en utilisant Java Decompiler), je ne vois pas l'utilisation de scala.runtime.boxesruntime. De plus, si je profile le code (en utilisant jprofiler), je ne vois aucune instance de boxesruntime.
Alors, comment puis-je vraiment voir une preuve de boxe / déballage se dérouler?
La solution
Dans ce code:
class Foo[T] {
def bar(i: T) = i
}
object Main {
def main(args: Array[String]) {
val f = new Foo[Int]
f.bar(5)
}
}
L'invocation de bar
Devrait d'abord boxer l'entier. Compilation avec Scala 2.8.1 et en utilisant:
javap -c -l -private -verbose -classpath <dir> Main$
pour voir le bytecode produit pour le main
Méthode de la Main
Rendement de la 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
...
Vous pouvez voir l'appel à BoxesRunTime
Avant l'appel à bar
.
BoxesRunTime
est un objet qui contient des méthodes de boxe pour les types primitifs, il devrait donc y avoir exactement une instance au total. L'astuce ici est que ce fichier particulier dans la bibliothèque a été écrit en Java, et les conversions sont des méthodes statiques. Pour cette raison, il n'y a pas de cas lors de l'exécution, bien que l'utiliser dans Scala Code a l'impression qu'il s'agissait d'un objet.
Vous devriez probablement rechercher des primitives en boîte (par exemple java.lang.integer) avec JProfile, bien que je ne sache pas comment le JVM fonctionne et si elle peut réécrire le code au moment de l'exécution et l'optimiser pour éviter la boxe. À ma connaissance, cela ne devrait pas appliquer de spécialisation (mais je crois que CLR le fait). Quelques microbenchacs avec et sans la situation de boxe sont une autre façon de comprendre ce qui se passe au moment de l'exécution.
ÉDITER:
Ce qui précède est en supposant qu'un paramètre de type n'a pas été annoté avec le @specialized
annotation. Dans ce cas, la boxe / déballage peut être évitée. Certaines classes de la bibliothèque standard sont spécialisées. Voir Ce sid.
Autres conseils
Compte tenu du test suivant.Scala Programme:
object Test {
def main(args:Array[String]) {
val list = List(1,5,15)
val res = list.map(e => e*2).filter(e => e>10)
}
}
Si je me compile avec scalac -Xprint:jvm Test.scala
, Je reçois cet extrait suggérant que la spécialisation se produit (désolé pour une pâte large):
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();
()
}
}
}
Cela pourrait être la raison pour laquelle vous ne voyez aucune preuve de boxe dans Bytecode ...