naciśnij klawisz...
-
Upload
daquan-neal -
Category
Documents
-
view
38 -
download
0
description
Transcript of naciśnij klawisz...
naciśnij klawisz...
Bytecode vs CIL
Nie zawsze kto pierwszy, ten lepszy
Mirosław Szymańskimarzec 2004
Porównanie
Terminologia
JVM – Java Virtual Machine
Bytecode
JVM + .class
<=> CLR – Common Language Runtime lub VES – Virtual Execution System
<=> CIL – Common Intermediate Language MSIL – Microsoft Intermediate Language
<=> CLI – Common Language Infrastructure
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
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#
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
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
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
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
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
Operacje arytmetyczne
Bytecode● przepełnienie nigdy nie
jest wykrywane
CIL● istnieją wersje instrukcji
arytmetycznych wyrzucające OverflowException
– wymagane przez niektóre języki, np.: Ada95, SML
add.ovf
add.ovf.un (unsigned)
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 zldarg xa; ldarg ya; ldind.i4stind.i4; ldarg ya; ldloc zstind.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 stosldind.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 Zstind.T zapisuje wartość typu T z wierzchołka stosu pod adresem pobranem ze stosuldloc Z wkłada zmienną lokalną Z na stosldloca X wkłada na stos adres zmiennej lokalnej X
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
CIL● jedna instrukcja alokująca i
wywołuąca konstruktor
newobj C::.ctor()
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 8tail. call void Bootom()ret
}
Wyjątki – stack trace
JVM● Stack trace tworzony jest
w momencie tworzenia obiektu wyjątku
CLR● Stack trace tworzony jest
podczas przekazywania 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 wykonaniamyVehicles[1] = c;
}void main() {
Car[] myCars = new Car[2];m(myCars);
}
Klasy zagnieżdżoneclass outerClass{
public int outer = 5;
class innerClass{public void inc() {
outer++;}
}
public outerClass(){innerClass i = new innerClass();i.inc();
}
public static void 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)