2011-02-13 15 views
8

W zaakceptowanej najlepszej odpowiedzi na this question, istnieje wyraźne wyjaśnienie, dlaczego boks się dzieje.Jak rozpoznać boks/rozpakować w dekompilowanym kodzie Scala?

Jednakże, jeśli dekompiluję kod (używając dekompilatora java), nie widzę możliwości użycia scala.runtime.BoxesRunTime. Ponadto, jeśli profiluję kod (używając JProfiler), nie widzę żadnych instancji BoxesRunTime.

Więc, jak naprawdę widzę dowód na boksowanie/rozpakowywanie?

Odpowiedz

7

W tym kodzie:

class Foo[T] { 
    def bar(i: T) = i 
} 


object Main { 
    def main(args: Array[String]) { 
    val f = new Foo[Int] 
    f.bar(5) 
    } 
} 

Wywołanie bar powinny pierwszym polu liczbę całkowitą. Kompilacja z Scala 2.8.1 i przy użyciu:

javap -c -l -private -verbose -classpath <dir> Main$ 

zobaczyć kodu bajtowego wyprodukowany dla metody main rentowności Main Klasa:

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                      
... 

widać wywołanie BoxesRunTime przed wywołaniem bar .

BoxesRunTime to obiekt, który zawiera metody bokowania dla typów pierwotnych, więc w sumie powinno być dokładnie jedno wystąpienie. Problem polega na tym, że ten konkretny plik w bibliotece został napisany w Javie, a konwersje są metodami statycznymi. Z tego powodu nie ma żadnych jego instancji w czasie wykonywania, chociaż użycie go w kodzie Scala wydaje się być obiektem.

Prawdopodobnie powinieneś szukać plików podstawowych w pudełku (np. Java.lang.Integer) w programie JProfile, ale nie jestem pewien, jak działa JVM i czy w rzeczywistości może on przepisać kod w czasie wykonywania i zoptymalizować go, aby uniknąć boksowania. Według mojej wiedzy, nie powinien on stosować specjalizacji (ale uważam, że CLR). Kilka mikrobańek z sytuacją boksu i bez niej to kolejny sposób, aby dowiedzieć się, co dzieje się w czasie wykonywania.

Edycja:

powyżej jest przy założeniu, że parametr typu nie opisywane z @specialized adnotacji. W takim przypadku można uniknąć boksowania/rozpakowywania. Niektóre klasy w bibliotece standardowej są wyspecjalizowane. Zobacz this sid.

1

Biorąc pod uwagę następujący program 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) 
    } 
} 

Jeśli mogę skompilować z scalac -Xprint:jvm Test.scala, otrzymuję ten fragment sugerujący, że specjalizację występuje (przepraszam za szerokim pasty):

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(); 
    () 
    } 
    } 
} 

Mogłoby dlaczego nie widzisz żadnego dowodu boksowania w bajtode ...

+1

Specjalność występuje dla anonimowych klas funkcji "Test $$ anonfun $ #", ponieważ funkcje są wyspecjalizowane. Jednak te anonimowe klasy funkcji są używane w metodach 'map' i' filter', które nie są wyspecjalizowane i wywołują ich domyślny rodzajowy 'apply', który oczekuje obiektu - boks powinien tam wystąpić. Jeśli dekompilujesz kod 'TraversableLike' i szukasz' map' lub 'filter', powinny one wywoływać wywołania' BoxesRunTime'. – axel22

Powiązane problemy