www.mimuw.edu.pl
Download
Report
Transcript www.mimuw.edu.pl
naciśnij klawisz...
Bytecode vs CIL
Nie zawsze kto pierwszy, ten lepszy
Porównanie
Mirosław Szymański
marzec 2004
Terminologia
JVM – Java Virtual Machine
<=> CLR – Common Language Runtime
lub VES – Virtual Execution System
Bytecode
JVM + .class
<=> CIL – Common Intermediate
Language MSIL – Microsoft
Intermediate Language
<=> CLI – Common Language
Infrastructure
Założenia projektowe i ich
konsekwencje
Bytecode
●
●
●
●
oprogramowanie urządzeń
“sieciowych”
CLI
●
●
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
●
●
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
CLR
●
●
●
rozmiar tablicy zm. lokalnych
określony podczas kompilacji
●
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
CIL
iload_1 ; push local int variable 1
ldloc.1 ; push local variable 1
iload_2 ; push local int variable 2
ldloc.2 ; push local variable 2
iadd
add
; add the two top elements
istore_3 ; pop result into variable 3
; 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 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
ldind.T
stloc Z
stind.T
ldloc Z
ldloca X
wkłada argument na stos
pobiera adres ze stosu, wkłada na stos wartość spod danego adresu (dereferencja)
pobiera wartość ze stosu i zapisuje ją w argumencie Z
zapisuje wartość typu T z wierzchołka stosu pod adresem pobranem ze stosu
wkłada zmienną lokalną Z na stos
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 8
tail. 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 wykonania
myVehicles[1] = c;
}
void main() {
Car[] myCars = new Car[2];
m(myCars);
}
Klasy zagnieżdżone
class 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”
–
●
“The Common Language Infrastructure Annotated
Standard”
–
●
Tim Lindholm, Frank Yellin, (java.sun.com)
“Shared Source CLI, Essentials”
–
●
Eric Meijer (Microsoft), John Gough (QUT)
“The JavaTM Virtual Machine Specification”, Second
Edition
–
●
Jim Miller, Susann Ragsdale, Addison Wesley 2003
“Technical Overview of the Common Language
Runtime”
–
●
K. John Gough
David Stutz, Ted Neward & Geoff Shilling – O'Reilly 2003
“One Runtime to Bind Them All”
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)