Obsah
1. Instrukce sloužící pro přístup k atributům tříd (statickým datovým atributům)
2. Instrukce sloužící pro přístup k atributům objektů
3. Demonstrační příklad – přístup k atributům tříd a objektů
4. Instrukce invokestatic a invokevirtual
5. Demonstrační příklad – využití instrukcí invokestatic a invokevirtual v bajtkódu
6. Instrukce invokevirtual při volání metody deklarované v předkovi třídy
8. Demonstrační příklady – využití instrukce invokespecial
1. Instrukce sloužící pro přístup k atributům tříd (statickým datovým atributům)
Po popisu všech instrukcí sloužících pro provádění aritmetických a bitových operací i instrukcí umožňujících řízení běhu programu nám ještě zbývá si popsat několik dalších skupin instrukcí. Velmi důležité jsou především instrukce, které slouží pro práci s třídami a objekty. Tyto instrukce umožňují přístup k atributům tříd (tj. k atributům s nastaveným modifikátorem „static“, někdy se jim proto také říká statické datové atributy) i k atributům objektů. Další instrukce pak slouží pro volání statických i virtuálních metod, včetně volání konstruktorů. První skupinu instrukcí, se kterou se dnes seznámíme, tvoří instrukce sloužící pro přesuny dat mezi zásobníkem operandů a vybraným atributem třídy (statickým datovým atributem) či atributem objektu. Tyto instrukce nepracují přímo s adresou vybraného atributu (tu ostatně ani nelze nijak zjistit), ale s jeho signaturou, která je uložena v constant poolu. Díky tomu je umožněn dynamický výběr správného atributu prováděný až v čase běhu aplikace.
V následující tabulce jsou vypsány dvě instrukce, které umožňují práci s třídními (statickými) atributy:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
1 | getstatic | 0×B2 | highbyte, lowbyte | získá z constant poolu záznam typu FieldReference a uloží hodnotu získaného atributu na zásobník operandů |
2 | putstatic | 0×B3 | highbyte, lowbyte | opak předchozí instrukce: přesun hodnoty ze zásobníku operandů do statického atributu |
Operandy highbyte a lowbyte tvoří šestnáctibitový index do constant poolu. Záznam na daném indexu musí být typu FieldReference, což je pro připomenutí záznam obsahující odkaz na další záznam typu Class (jméno třídy) a taktéž na záznam typu Name and Type (signatura metody či atributu).
Povšimněte si jedné zajímavosti: obě dvě instrukce vypsané v předchozí tabulce dokážou pracovat s jakýmkoli datovým typem atributu. Virtuální stroj Javy totiž ze signatury atributu zjistí jeho typ a překladač musí zajistit, aby se na zásobníku operandů skutečně nacházel operand daného typu (což platí pro instrukci putstatic, zde ovšem může dojít k implicitním typovým konverzím popsaným v další kapitole), jinak dojde k chybě při analýze bajtkódu při jeho načítání do virtuálního stroje Javy. Situace je poněkud složitější v případě polí, což je však problematika, kterou se budeme podrobněji zabývat až v navazující části tohoto seriálu (pro přístup k prvkům polí totiž existuje samostatná sada instrukcí rozdělených podle typu pole, resp. podle typů prvků uložených v poli).
U instrukce putstatic se kontroluje, zda atribut není finální (klíčové slovo final). Pokud tomu tak je, vyvolá se výjimka typu IllegalAccessError. Samozřejmě se jedná o stav, který je kontrolován již při překladu, ovšem kvůli dynamičnosti celého JVM se může stát, že se v bajtkódu mění atribut třídy jiné verze, než byla verze použitá při překladu.
2. Instrukce sloužící pro přístup k atributům objektů
Instrukce getstatic a putstatic z předchozí kapitoly dokážou přečíst či naopak nastavit pouze statický atribut, tj. atribut společný pro všechny instance jedné třídy. Pro čtení či zápis atributu přiřazeného ke konkrétnímu objektu (=instanci třídy) se naproti tomu používají instrukce nazvané getfield a putfield, které se od obou předchozích instrukcí liší v jednom důležitém detailu: tyto instrukce očekávají, že na zásobníku operandů bude uložena reference na objekt daného typu.
V tomto ohledu je pro popis jednodušší instrukce getfield, která pracuje pouze s prvkem uloženým na vrcholu zásobníku operandů (TOS neboli top of stack). Tento prvek musí obsahovat referenci na objekt, jehož atribut se má přečíst. Reference je při provádění instrukce getfield ze zásobníku operandů odstraněna a namísto ní se na zásobník operandů uloží hodnota přečteného atributu.
Instrukce putfield pracuje s dvojicí prvků uložených na zásobníku operandů. Na TOS musí být uložena hodnota, na kterou se má atribut nastavit a pod TOS je očekávána reference na objekt daného typu. Oba prvky jsou po provedení instrukce putfield ze zásobníku operandů odstraněny. Navíc se při provádění instrukce putfield provádí stejná kontrola na „finálnost“ atributu, jako tomu bylo u instrukce putstatic.
Operační kódy a stručný popis instrukcí getfield a putfield jsou vypsány v následující tabulce:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
3 | getfield | 0×B4 | highbyte, lowbyte | získá hodnotu atributu objektu, jehož reference je uložena na TOS a tuto hodnotu následně uloží na zásobník operandů |
4 | putfield | 0×B5 | highbyte, lowbyte | obsah TOS se přenese do atributu objektu, jehož reference je uložena na druhém místě zásobníku operandů |
Operandy highbyte a lowbyte opět společně tvoří šestnáctibitový index do constant poolu.
U instrukcí putstatic a putfield může docházet k typovým konverzím mezi prvkem uloženým na zásobníku operandů a skutečným typem atributu třídy či objektu. Ke konverzím dochází u atributů typu boolean, byte, char a short, protože hodnoty tohoto typu nemohou být na zásobníku operandů uloženy (některými důvody, proč tomu tak je, jsme se již zabývali v předchozích částech tohoto seriálu). Virtuální stroj Javy však dokáže automaticky a bez varování či dokonce zobrazení chybové zprávy převést hodnotu prvku typu int na hodnotu atributu typu boolean/byte/char/short, a to i v těch případech, kdy při konverzi dojde k zanedbání nejvyšších bitů hodnoty.
3. Demonstrační příklad – přístup k atributům tříd a objektů
Způsob využití všech čtyř instrukcí popsaných v tabulkách uvedených v první kapitole a taktéž ve druhé kapitole si ukážeme na jednoduchém demonstračním příkladu. Ve zdrojovém kódu tohoto příkladu je deklarována čtveřice metod. Dvě metody jsou statické a v jejich těle se přistupuje k dvojici statických atributů, zatímco ve zbývajících dvou metodách se přistupuje k nestatickým atributům (atributům objektů). Zdrojový kód dnešního prvního demonstračního příkladu má tvar:
class Test1 { // staticky atribut static int staticField; // nestaticky atribut int nonStaticField; static void setStaticField(int x) { staticField = x; } static int getStaticField() { return staticField; } void setNonStaticField(int x) { this.nonStaticField = x; } int getNonStaticField() { return this.nonStaticField; } }
V dalším popisu nám pomůže znalost obsahu constant poolu, především těch záznamů, které jsou ohraničeny hvězdičkou. Jedná se o záznamy typu FieldReference, z nichž lze vyčíst celou signaturu atributu (touto problematikou jsme se již taktéž v minulosti zabývali):
Velikost const. poolu: 25 prvku 1 10 MethodRef 5 21 java/lang/Object.<init>()V *************************************************************** 2 9 FieldRef 4 22 Test1.staticField:I 3 9 FieldRef 4 23 Test1.nonStaticField:I *************************************************************** 4 7 Class 24 Test1 5 7 Class 25 java/lang/Object 6 1 String "staticField" 7 1 String "I" 8 1 String "nonStaticField" 9 1 String "<init>" 10 1 String "()V" 11 1 String "Code" 12 1 String "LineNumberTable" 13 1 String "setStaticField" 14 1 String "(I)V" 15 1 String "getStaticField" 16 1 String "()I" 17 1 String "setNonStaticField" 18 1 String "getNonStaticField" 19 1 String "SourceFile" 20 1 String "Test1.java" 21 12 Name and type 10 9 ()V <init> 22 12 Name and type 7 6 I staticField 23 12 Name and type 7 8 I nonStaticField 24 1 String "Test1" 25 1 String "java/lang/Object"
Výpis bajtkódu vygenerovaného pro statickou metodu pojmenovanou getStaticField, v níž se čte hodnota statického atributu, která je následně použita jako návratová hodnota metody:
static int getStaticField(); Code: 0: getstatic #2; // uložení hodnoty atributu specifikovaného // záznamem číslo 2 z constant poolu na zásobník // operandů 3: ireturn // výskok z metody s předáním návratové hodnoty // uložené na TOS
Výpis bajtkódu vygenerovaného pro statickou metodu setStaticField, v níž se modifikuje hodnota statického atributu:
static void setStaticField(int); Code: 0: iload_0 // uložit na zásobník operandů // první (a jediný) parametr metody 1: putstatic #2; // přenos hodnoty uložené na zásobníku operandů // do atributu specifikovaného záznamem číslo 2 // v constant poolu (Test1.staticField:I) // Původní obsah TOS je odstraněn. 4: return // výskok z metody bez předání návratové hodnoty
Výpis bajtkódu vygenerovaného pro nestatickou metodu getNonStaticField, v níž se čte hodnota nestatického atributu:
int getNonStaticField(); Code: 0: aload_0 // uložit na zásobník operandů neviditelný // parametr metody (this) 1: getfield #3; // uložení hodnoty atributu specifikovaného // záznamem číslo 3 z constant poolu na zásobník // operandů. Původní obsah TOS (hodnota this) // je použit a následně odstraněn. 4: ireturn // výskok z metody s předáním návratové hodnoty // uložené na TOS
Výpis bajtkódu vygenerovaného pro nestatickou metodu setNonStaticField, v níž se modifikuje hodnota nestatického atributu. Zde se pracuje s dvojicí prvků uložených na zásobníku operandů, jedná se tedy o nejsložitější případ:
void setNonStaticField(int); Code: 0: aload_0 // uložit na zásobník operandů neviditelný // parametr metody (this) 1: iload_1 // uložit na zásobník operandů první viditelný // parametr metody (int) 2: putfield #3; // přenos hodnoty uložené na zásobníku operandů // do atributu specifikovaného záznamem číslo 3 // v constant poolu (Test1.nonStaticField:I) // Původní obsah TOS i hodnoty pod TOS jsou odstraněny 5: return // výskok z metody bez předání návratové hodnoty
4. Instrukce invokestatic a invokevirtual
Další skupina instrukcí slouží pro volání metod, ať již se jedná o metody statické, nestatické (většinou tedy o metody virtuální), tak i o metody speciální, mezi něž patří zejména konstruktory. Základními instrukcemi patřícími do této skupiny jsou instrukce nazvané invokestatic a invokevirtual. Instrukce invokestatic slouží, jak již ostatně název této instrukce napovídá, k zavolání statické metody, tj. metody, kterou je možné zavolat i v případě, že neexistuje žádná instance třídy, v níž je tato metoda deklarována (samozřejmě za předpokladu, že jsou vhodně nastavena přístupová práva k metodě). Naproti tomu druhá instrukce ze stejné skupiny – instrukce invokevirtual – je určena pro zavolání nestatické metody, tj. metody, které je jako první (skrytý) parametr předána reference na objekt, v jehož rámci je metoda zavolána (metoda však nesmí být privátní, v tomto případě by se musela použít instrukce invokespecial). Obě instrukce pracují se signaturami metod uloženými v constant poolu (je to trošku podobné instrukcím uvedeným v první a ve druhé kapitole) a před zavoláním statické či nestatické metody je nutné na zásobník operandů uložit všechny parametry, které se mají volané metodě předat.
Formát obou zmíněných instrukcí je vypsán v tabulce zobrazené pod tímto odstavcem:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
1 | invokestatic | 0×B8 | highbyte, lowbyte | zavolání statické metody s předáním parametrů této metodě |
2 | invokevirtual | 0×B6 | highbyte, lowbyte | zavolání nestatické metody s předáním hodnoty this a všech dalších parametrů |
Operandy highbyte a lowbyte tvoří šestnáctibitový index do constant poolu. Záznam uložený na daném indexu musí být typu MethodReference, což je pro připomenutí záznam obsahující odkaz na záznam typu Class (jméno třídy) a taktéž na záznam typu Name and Type (signatura metody či atributu). Až na rozdíl mezi FieldReference a MethodReference je tedy význam operandů highbyte a lowbyte stejný, jako tomu bylo u instrukcí putfield, putstatic, getfield a getstatic.
V případě instrukce invokevirtual je však situace poněkud složitější, protože virtuální stroj Javy musí zjistit, metoda které třídy má být ve skutečnosti zavolána – může se totiž jednat o metodu předka, a to v libovolné úrovni (klidně se může jednat i o metodu prapředka všech tříd – třídy Object). Proto virtuální stroj Javy rekurzivně prochází předky třídy, jejíž instance je uložena na zásobníku operandů a hledá metodu se signaturou stejnou, jako je signatura uložená v constant poolu. Jakmile je taková metoda nalezena, je rekurzivní vyhledávání je ukončeno a nalezená metoda je zavolána se všemi parametry, včetně skrytého parametru představujícího this (referenci na objekt, pro nějž je metoda zavolána).
5. Demonstrační příklad – využití instrukcí invokestatic a invokevirtual v bajtkódu
Způsob využití instrukcí invokestatic a invokevirtual si ukážeme na demonstračním příkladu se čtveřicí metod. První dvě metody, z nichž jedna je statická (staticMethod) a druhá nestatická (nonStaticMethod), mají dva parametry typu int, ale pro jednoduchost je jejich tělo prázdné. Tyto metody jsou volány z dalších dvou metod, z nichž je opět jedna metoda statická (callStaticMethod) a druhá nestatická (callNonStaticMethod):
class Test2 { static void staticMethod(int x, int y) { // nic = prazdne telo } void nonStaticMethod(int x, int y) { // nic = prazdne telo } void callStaticMethod() { staticMethod(10, 20); } void callNonStaticMethod() { nonStaticMethod(10, 20); } }
Podobně jako u prvního demonstračního příkladu, i zde si nejdříve ukážeme obsah constant poolu se zvýrazněním záznamů, s nimiž se bude dále pracovat:
Velikost const. poolu: 21 prvku 1 10 MethodRef 5 17 java/lang/Object.<init>()V *************************************************************** 2 10 MethodRef 4 18 Test2.staticMethod(II)V 3 10 MethodRef 4 19 Test2.nonStaticMethod(II)V *************************************************************** 4 7 Class 20 Test2 5 7 Class 21 java/lang/Object 6 1 String "<init>" 7 1 String "()V" 8 1 String "Code" 9 1 String "LineNumberTable" 10 1 String "staticMethod" 11 1 String "(II)V" 12 1 String "nonStaticMethod" 13 1 String "callStaticMethod" 14 1 String "callNonStaticMethod" 15 1 String "SourceFile" 16 1 String "Test2.java" 17 12 Name and type 7 6 ()V <init> 18 12 Name and type 11 10 (II)V staticMethod 19 12 Name and type 11 12 (II)V nonStaticMethod 20 1 String "Test2" 21 1 String "java/lang/Object"
Bajtkód volané statické metody nazvané staticMethod je velmi jednoduchý:
static void staticMethod(int, int); Code: // tato metoda nemá žádné tělo, obsahuje jen // instrukci pro návrat 0: return // výskok z metody bez předání návratové hodnoty
Podobně je tomu u bajtkódu nestatické metody nonStaticMethod:
void nonStaticMethod(int, int); Code: // tato metoda nemá žádné tělo, obsahuje jen // instrukci pro návrat 0: return // výskok z metody bez předání návratové hodnoty
Při volání statické metody se na zásobník operandů ukládají pouze viditelné parametry volané metody:
void callStaticMethod(); Code: 0: bipush 10 // první parametr volané statické metody 2: bipush 20 // druhý parametr volané statické metody 4: invokestatic #2; // Method staticMethod:(II)V // oba prvky na zásobníku operandů se při // návratu odstraní 7: return // výskok z metody bez předání návratové hodnoty
Složitější je to v případě metody nestatické, protože na zásobník operandů je nutné kromě viditelných parametrů uložit i neviditelný parametr this:
void callNonStaticMethod(); Code: 0: aload_0 // implicitní parametr (this) volané nestatické metody 1: bipush 10 // první viditelný parametr volané nestatické metody 3: bipush 20 // druhý viditelný parametr volané nestatické metody 5: invokevirtual #3; // Method nonStaticMethod:(II)V // všechny tři prvky na zásobníku operandů se při // návratu odstraní 8: return // výskok z metody bez předání návratové hodnoty
6. Instrukce invokevirtual při volání metody deklarované v předkovi třídy
Ve čtvrté kapitole jsme si řekli, že způsob zjištění metody, která se má skutečně zavolat instrukcí invokevirtual je poměrně složitý, protože daná metoda může být deklarována v některém předkovi třídy, nikoli v samotné třídě (přesněji řečeno instanci této třídy), pro kterou se metoda volá. Toto chování si můžeme ukázat na demonstračním příkladu s trojicí tříd ClassA, ClassB a ClassC tvořících hierarchii, na jejímž vrcholu stojí třída ClassA (jejímž předkem je samozřejmě třída Object):
class ClassA { void methodA() { } } class ClassB extends ClassA { } class ClassC extends ClassB { void methodC() { // zde se vola metoda deklarovana // v prapredkovi = tride ClassA methodA(); } }
Podívejme se nyní, jak vypadá bajtkód metody methodC:
void methodC(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokevirtual #2; // Method methodA:()V // ClassC.methodA:()V 4: return
Ve skutečnosti se však v bajtkódu třídy ClassC žádná metoda nazvaná methodA nenachází. Z tohoto důvodu musí virtuální stroj Javy danou metodu postupně hledat v předcích dané třídy, tj. nejdříve ve třídě ClassB (bez úspěchu) a posléze ve třídě ClassA (zde již s úspěchem).
7. Instrukce invokespecial
Další instrukcí určenou pro volání metod, je instrukce nazvaná invokespecial. Tato instrukce se používá zejména při inicializaci objektu, konkrétně při volání konstruktoru předka poté, co je objekt vytvořen, ale taktéž při volání privátních metod, popř. překrytých metod. Struktura instrukce invokespecial je vypsána v následující tabulce:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
1 | invokespecial | 0×B7 |
8. Demonstrační příklady – využití instrukce invokespecial
Jak jsme si již řekli v předchozí kapitole, má instrukce invokespecial hned několik využití. Prvním z nich je volání privátní metody. Rozdíl mezi voláním privátní a neprivátní metody ilustruje následující demonstrační příklad:
class PrivateAndPublicCall1 { private void privateMethod() { // nic = prazdne telo } public void publicMethod() { // nic = prazdne telo } void call() { privateMethod(); publicMethod(); } }
Zajímat nás samozřejmě bude bajtkód metody call, která volá jak privátní metodu, tak i metodu veřejnou:
void call(); Code: 0: aload_0 // uložit referenci "this" // na zásobník operandů 1: invokespecial #2; // Method privateMethod:()V // privátní metoda = invokespecial 4: aload_0 // uložit referenci "this" // na zásobník operandů 5: invokevirtual #3; //Method publicMethod:()V // veřejná metoda = invokevirtual 8: return
Aby to však nebylo tak jednoduché, je situace při volání statických privátních a veřejných metod odlišná, protože se zde použije stejná instrukce:
class PrivateAndPublicCall2 { private static void privateStaticMethod() { // nic = prazdne telo } public static void publicStaticMethod() { // nic = prazdne telo } void callStatic() { privateStaticMethod(); publicStaticMethod(); } }
V tomto případě je bajtkód metody callStatic následující:
void callStatic(); Code: 0: invokestatic #4; //Method privateStaticMethod:()V 3: invokestatic #5; //Method publicStaticMethod:()V 6: return
Instrukce invokespecial se využívá taktéž při inicializaci objektů, což si ukážeme na poněkud odlišném demonstračním příkladu s následujícím zdrojovým kódem, v jehož metodách se konstruují instance tříd Test3, Integer a String:
class Test3 { public static void testInvokeSpecial1() { new Test3(); } public static Integer testInvokeSpecial2() { return new Integer(42); } public static void testInvokeSpecial3() { new String("pokus"); } }
Opět nebude na škodu si ukázat obsah constant poolu uloženého v bajtkódu. Důležité záznamy jsou ohraničeny hvězdičkami:
Velikost const. poolu: 29 prvku 1 10 MethodRef 9 20 java/lang/Object.<init>()V 2 7 Class 21 Test3 *************************************************************** 3 10 MethodRef 2 20 Test3.<init>()V *************************************************************** 4 7 Class 22 java/lang/Integer *************************************************************** 5 10 MethodRef 4 23 java/lang/Integer.<init>(I)V *************************************************************** 6 7 Class 24 java/lang/String 7 8 String const 25 "pokus" *************************************************************** 8 10 MethodRef 6 26 java/lang/String.<init>(Ljava/lang/String;)V *************************************************************** 9 7 Class 27 java/lang/Object 10 1 String "<init>" 11 1 String "()V" 12 1 String "Code" 13 1 String "LineNumberTable" 14 1 String "testInvokeSpecial1" 15 1 String "testInvokeSpecial2" 16 1 String "()Ljava/lang/Integer;" 17 1 String "testInvokeSpecial3" 18 1 String "SourceFile" 19 1 String "Test3.java" 20 12 Name and type 11 10 ()V <init> 21 1 String "Test3" 22 1 String "java/lang/Integer" 23 12 Name and type 28 10 (I)V <init> 24 1 String "java/lang/String" 25 1 String "pokus" 26 12 Name and type 29 10 (Ljava/lang/String;)V <init> 27 1 String "java/lang/Object" 28 1 String "(I)V" 29 1 String "(Ljava/lang/String;)V"
V bajtkódu metody testInvokeSpecial1 se nejdříve pomocí instrukce new vytvoří instance třídy Test3 a posléze se zavolá speciální metoda nazvaná <init>, která (poněkud zjednodušeně řečeno) odpovídá konstruktoru této třídy. Povšimněte si také dvojice instrukcí dup a pop na adresách 3 a 7. Tyto instrukce slouží pro úschovu a následné odstranění reference na objekt vytvořený pomocí new, i když ve skutečnosti není tato reference nikde použita (instrukce invokespecial taktéž využívá referenci na vytvořený objekt, ovšem tato reference je při zpracování této instrukce z TOS odstraněna):
public static void testInvokeSpecial1(); Code: 0: new #2; // vytvoření instance třídy Test3 3: dup // invokespecial využije a zahodí referenci // uloženou na TOS, proto javac vygeneruje // tuto instrukci, která referenci na // zásobníku zachová 4: invokespecial #3; // zavolání konstruktoru bez parametrů: // Method "<init>":()V // na zásobníku operandů je uložena reference // vytvořeného objektu 7: pop // objekt je sice vytvořen, ale jeho referenci // nevyužíváme: je odstraněna pomocí pop 8: return // výskok z metody bez předání návratové hodnoty
V metodě testInvokeSpecial2 je vytvořen objekt typu Integer, přičemž je využit jednoparametrický konstruktor této třídy. Povšimněte si, že v bajtkódu je opět využita instrukce dup pro vytvoření kopie reference na vytvořený objekt, a v tomto případě je kopie skutečně využita instrukcí areturn:
public static java.lang.Integer testInvokeSpecial2(); Code: 0: new #4; // vytvoření instance třídy java.lang.Integer 3: dup // invokespecial využije a zahodí referenci // uloženou na TOS, proto javac vygeneruje // tuto instrukci, která referenci na // zásobníku zachová 4: bipush 42 // parametr předaný konstruktoru třídy Integer 6: invokespecial #5; // zavolání konstruktoru s jedním parametrem: // Method java/lang/Integer."<init>":(I)V // na zásobníku operandů je uložena reference // vytvořeného objektu 9: areturn // výskok z metody s předáním návratové hodnoty
V metodě testInvokeSpecial3 je nejprve vytvořena instance třídy String, a to mimochodem značně neefektivním a amatérským způsobem :-) Konstruktor třídy String je volán s jedním parametrem, kterým je řetězcová konstanta uložená v constant poolu. I přesto, že se s referencí na vytvořený objekt nijak nepracuje, vygeneruje překladač dvojici instrukcí dup a pop, podobně jako tomu bylo v metodě testInvokeSpecial1:
public static void testInvokeSpecial3(); Code: 0: new #6; // vytvoření instance třídy java.lang.String 3: dup // invokespecial využije a zahodí referenci // uloženou na TOS, proto javac vygeneruje // tuto instrukci, která referenci na // zásobníku zachová 4: ldc #7; // String pokus 6: invokespecial #8; // zavolání konstruktoru s jedním parametrem: // Method java/lang/String."<init>":(Ljava/lang/String;)V 9: pop // objekt je sice vytvořen, ale jeho referenci // nevyužíváme: je odstraněna pomocí pop 10: return // výskok z metody bez předání návratové hodnoty
9. Odkazy na Internetu
- Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
http://www.root.cz/clanky/vyuziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/ - Root.cz: JamVM aneb alternativa k HotSpotu nejenom pro embedded zařízení a chytré telefony
http://www.root.cz/clanky/jamvm-aneb-alternativa-k-hotspotu-nejenom-pro-embedded-zarizeni-tablety-a-chytre-telefony/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - BCEL Home page
http://commons.apache.org/bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - FindBugs
http://findbugs.sourceforge.net/ - GNU Classpath
www.gnu.org/s/classpath/ - Java VMs Compared
http://bugblogger.com/java-vms-compared-160/ - JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
http://www.jcp.org/en/jsr/detail?id=223 - Scripting for the Java Platform
http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/ - Scripting for the Java Platform (Wikipedia)
http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - Java Community Process
http://en.wikipedia.org/wiki/Java_Specification_Request - Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html - Great Computer Language Shootout
http://c2.com/cgi/wiki?GreatComputerLanguageShootout - Java performance
http://en.wikipedia.org/wiki/Java_performance - Trying the prototype
http://mail.openjdk.java.net/pipermail/lambda-dev/2010-August/002179.html - Better closures (for Java)
http://blogs.sun.com/jrose/entry/better_closures - Lambdas in Java: An In-Depth Analysis
http://www.infoq.com/articles/lambdas-java-analysis - Class ReflectiveOperationException
http://download.java.net/jdk7/docs/api/java/lang/ReflectiveOperationException.html - Proposal: Indexing access syntax for Lists and Maps
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001108.html - Proposal: Elvis and Other Null-Safe Operators
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000047.html - Java 7 : Oracle pushes a first version of closures
http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/ - Groovy: An agile dynamic language for the Java Platform
http://groovy.codehaus.org/Operators - Better Strategies for Null Handling in Java
http://www.slideshare.net/Stephan.Schmidt/better-strategies-for-null-handling-in-java - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Java Virtual Machine
http://en.wikipedia.org/wiki/Java_virtual_machine - ==, .equals(), compareTo(), and compare()
http://leepoint.net/notes-java/data/expressions/22compareobjects.html - New JDK7 features
http://openjdk.java.net/projects/jdk7/features/ - Project Coin: Bringing it to a Close(able)
http://blogs.sun.com/darcy/entry/project_coin_bring_close - CloseableFinder source code
http://blogs.sun.com/darcy/resource/ProjectCoin/CloseableFinder.java - Joe Darcy blog about JDK
http://blogs.sun.com/darcy - Java 7 – more dynamics
http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/ - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html