270 likes | 390 Views
naciśnij klawisz. Bytecode vs CIL Nie zawsze kto pierwszy, ten lepszy Mirosław Szymański marzec 2004. Porównanie. <=> CLR – Common Language Runtime lub VES – Virtual Execution System <=> CIL – Common Intermediate Language MSIL – Microsoft Intermediate Language
E N D
Bytecode vs CIL Nie zawsze kto pierwszy, ten lepszy Mirosław Szymański marzec 2004 Porównanie
<=> CLR – Common Language Runtime lub VES – Virtual Execution System <=> CIL – Common Intermediate Language MSIL – Microsoft Intermediate Language <=> CLI – Common Language Infrastructure Terminologia JVM – Java Virtual Machine Bytecode JVM + .class
CLI zwięzłość kodu praktycznie rezygnacja z możliwości interpretacji nacisk na wspieranie wielu języków programowania (w szczególności Javy) w rzeczywistości języki oferowane w .NET to “skórki” na C# Założenia projektowe i ich konsekwencje Bytecode • oprogramowanie urządzeń “sieciowych” • zwięzłość kodu • nacisk na możliwość interpretacji kodu (czasami chcemy uniknąć dużego kosztu kompilacji JIT) • ograniczone wsparcie dla języków innych niż Java
Cechy wspólne • Wirtualna maszyna • stos + zestaw instrukcji operujących na stosie • Instrukcje wspierające obiektowy model programowania • Pliki .class oraz assembly files • opisują klasy • wszelkie odwołania do elementów są odwołaniami przez referencje do puli stałych, pozwala to na sprawdzanie zgodności typów podczas ładowania
Cechy wspólne • garbage collector • brak wielodziedziczenia • możliwość implementowania wielu interfejsów • jednobajtowe instrukcje
CLR osobne tablice dla zmiennych lokalnych i argumentów pozycje w tablicy zm.lokalnych mają określony typ, mogą być używane tylko przez zmienne danego typu rozmiar tablicy zm.lokalnych nie jest z góry znany, ponieważ mogą tam się znaleźć struktury przy kompilacij znana jest tylko liczba zmiennych lokalnych Wirtualna maszyna – różnice JVM • wspólna tablica dla zmiennych lokalnych i argumentów • pozycje w tablicy zmiennych lokalnych mogą być wielokrotnie używane, nawet dla zmiennych różnych typów • rozmiar tablicy zm. lokalnych określony podczas kompilacji
CIL ldloc.1 ; push local variable 1 ldloc.2 ; push local variable 2 add ; add the two top elements stloc.3 ; pop result into variable 3 Podstawowe instrukcje Bytecode iload_1 ; push local int variable 1 iload_2 ; push local int variable 2 iadd ; add the two top elements istore_3 ; pop result into variable 3
CIL istnieją wersje instrukcji arytmetycznych wyrzucające OverflowException wymagane przez niektóre języki, np.: Ada95, SML add.ovf add.ovf.un (unsigned) Operacje arytmetyczne Bytecode • przepełnienie nigdy nie jest wykrywane
Wskaźniki [CIL] • unmanaged pointers • operacje bezpieczne (typesafe) • odczytanie/zapisanie zawartości • operacje niebezpieczne • pointer ± integer • pointer ± pointer • managed pointers • np. wskaźnik do pola obiektu • w C# używane do przekazywania parametrów typu out
Wskaźniki cd. [CIL] .method static void swap(int32& xa, int32& ya) { .maxstack 2 .locals (int32 z) ldarg xa; ldind.i4; stloc z ldarg xa; ldarg ya; ldind.i4 stind.i4; ldarg ya; ldloc z stind.i4; ret } Przykładowe wywołanie metody swap() .locals (int32 x, int32 y) ldloca x; ldloca y; call void swap(int32&, int32&) ldarg X wkłada argument na stos ldind.T pobiera adres ze stosu, wkłada na stos wartość spod danego adresu (dereferencja) stloc Z pobiera wartość ze stosu i zapisuje ją w argumencie Z stind.T zapisuje wartość typu T z wierzchołka stosu pod adresem pobranem ze stosu ldloc Z wkłada zmienną lokalną Z na stos ldloca X wkłada na stos adres zmiennej lokalnej X
CIL jedna instrukcja alokująca i wywołuąca konstruktor newobj C::.ctor() Tworzenie obiektu Bytecode • stała sekwencja instrukcji: new C dup invokespecial C.<init>()V • weryfikator musi sprawdzać czy każdy obiekt został zainicjalizowany przed użyciem, oraz czy nie został zainicjalizowany więcej niż raz
Wywołania ogonowe (tailcalls) [CIL] • wsparcie dla języków funkcyjnych • prefiks tail. informuje kompilator, aby skasował ramke stosu przed wywołaniem metody • następujący kod zapętli się zamiast wyrzucić wyjątek przepełnienia stosu: .method public static void Bottom() { .maxstack 8 tail. call void Bootom() ret }
CLR Stacktrace tworzony jest podczas przekazywania wyjątku Wyjątki – stack trace JVM • Stacktrace tworzony jest w momencie tworzenia obiektu wyjątku Zwykle efekt jest ten sam. Wyjątkiem jest sytuacja, gdy obiekt wyjątku tworzony jest w innej metodzie niż jest wyrzucany.
Tablice [CIL] Tablice wielowymiarowe: • “prawdziwe”, np.: int[,] • w stylu C/Java (jagged arrays), np..: int [][] • są typu System.Array, w szczególności nie jest poprawne następujące przeciążenie metody: void method(int [][]) void method(float [][]) Tablice 0-wymiarowe - brak • jedyny język w którym zostały zaimplementowane to APL • problemy związane z implementacją
Tablice Pytanie: powinny być invariant czy covariant ? przykład: class Vehicle {. . .} class Car: Vehicle {. . .} void m(Vehicle[] myVehicles) { Vehicle v = new Vehicle(); Car c = new Car(); myVehicles[0] = v; myVehicles[1] = c; } void main() { Car[] myCars = new Car[2]; m(myCars); }
Tablice Opcja pierwsza: invariant class Vehicle {. . .} class Car: Vehicle {. . .} void m(Vehicle[] myVehicles) { Vehicle v = new Vehicle(); Car c = new Car(); myVehicles[0] = v; myVehicles[1] = c; } void main() { Car[] myCars = new Car[2]; m(myCars); // błąd podczas kompilacji }
Tablice Opcja druga: covariant (zgodna z Javą) class Vehicle {. . .} class Car: Vehicle {. . .} void m(Vehicle[] myVehicles) { Vehicle v = new Vehicle(); Car c = new Car(); myVehicles[0] = v; // błąd podczas wykonania myVehicles[1] = c; } void main() { Car[] myCars = new Car[2]; m(myCars); }
Klasy zagnieżdżone class outerClass{ publicintouter = 5; class innerClass{ publicvoid inc() { outer++; } } public outerClass(){ innerClass i = new innerClass(); i.inc(); } publicstaticvoid main(String args[]) { outerClass o = new outerClass(); } }
Method void inc() aload_0 getfield #2 <Field outerClass this$0> dup getfield #4 <Field int outer> iconst_1 iadd putfield #4 <Field int outer> return } Method outerClass. innerClass(outerClass) aload_0 invokespecial #1 <Method java.lang.Object()> aload_0 aload_1 putfield #2 <Field outerClass this$0> aload_0 iconst_3 putfield #3 <Field int inner> return
Method outerClass() aload_0 invokespecial #1 <Method java.lang.Object()> aload_0 iconst_5 putfield #2 <Field int outer> new #3 <Class outerClass. innerClass> dup aload_0 invokespecial #4 <Method outerClass. innerClass(outerClass)> astore_1 aload_1 invokevirtual #5 <Method void inc()> return
Klasy zagnieżdżone c.d. class outerClass2{ public int outer = 5; class innerClass{ public int inner = 3; class innerClass2{ public void write2() { inner++; outer++; } } ... }
Method void write2() aload_0 getfield #2 <Field outerClass2.innerClass this$1> dup getfield #4 <Field int inner> iconst_1 iadd putfield #4 <Field int inner> aload_0 getfield #2 <Field outerClass2.innerClass this$1> invokestatic #5 <Method outerClass2 access$000(outerClass2.innerClass)> dup getfield #6 <Field int outer> iconst_1 iadd putfield #6 <Field int outer> return } Statyczna metoda klasy innerClass: Method outerClass2 access$000(outerClass2.innerClass) 0 aload_0 1 getfield #1 <Field outerClass2 this$0> 4 areturn }
Kierunki rozwoju JVM • klasy zagnieżdżone (na poziomie JVM) • dodanie generics na poziomie JVM • dodanie innych sposobów przekazywania parametrów metod • rozwój hamowany przez konieczność zachowania kompatybilności wstecz
Kierunki rozwoju CLI • dodanie preprocesora języka pośredniego, generującego kod bardziej przyjazny interpretacji • cel – systemy o ograniczonych możliwościach, np. telefony komórkowe • okrojona wersja VM mogłaby być pozbawiona możliwości dynamicznego ładowania modułów. Dzięki temu VM nie musiałaby sprawdzać zgodności typów. Efekt: bardzo mała wirtualna maszyna, idealna do urządzeń dedykowanych (telefony, mikrofalówki :) ) • dodanie generics • dodanie wielodziedziczenia
Literatura • “Stacking them up: a Comparison of Virtual Machines” • K. John Gough • “The Common Language Infrastructure Annotated Standard” • Jim Miller, Susann Ragsdale, Addison Wesley 2003 • “Technical Overview of the Common Language Runtime” • Eric Meijer (Microsoft), John Gough (QUT) • “The JavaTM Virtual Machine Specification”, Second Edition • Tim Lindholm, Frank Yellin, (java.sun.com) • “Shared Source CLI, Essentials” • David Stutz, Ted Neward & Geoff Shilling – O'Reilly 2003 • “One Runtime to Bind Them All” • Osvaldo Pinali Doederlein, 2002
Epilog “It would be unfair to state that the CLI as it is now, is already the perfect multi-language platform. It currently has good support for imperative (COBOL, C, Pascal, Fortran) and statically typed OO languages (such as C#, Eiffel, Oberon, Component Pascal). Microsoft continues to work with language implementers and researchers to improve support for languages in nonstandard paradigms” Eric Meijer (Microsoft), John Gough (QUT)