Obsah
3. Problémy s instrukcemi jsr, jsr_w a ret
5. Demonstrační příklad: rozdíl mezi voláním metody rozhraní a běžné virtuální metody
6. Vyhození výjimky s využitím instrukce athrow
7. Synchronizace s využitím instrukcí monitorenter a monitorexit
8. Kontrola typů za běhu: instrukce instanceof a checkcast
1. Pohled pod kapotu JVM (12.část – volání metod rozhraní, synchronizované bloky a kontrola typů za běhu)
V dnešní části seriálu o programovacím jazyce Java i o vlastnostech virtuálního stroje tohoto jazyka si popíšeme všechny zbývající instrukce, které lze najít ve standardním bajtkódu získaného překladem javovských tříd, výčtových typů či rozhraní. Prozatím tedy vynecháme ty instrukce, které se používají v souvislosti s dynamicky typovanými (skriptovacími) jazyky. V předchozích šesti částech tohoto seriálu [1][2][3][4][5][6] jsme si již většinu instrukcí JVM popsali, ovšem ještě nám zbývá se zmínit o deseti instrukcích sloužících pro různé účely, například pro vyhození výjimky, vstup a výstup ze synchronizovaného bloku, kontrolu typu (objektu) v době běhu programu (runtime check) atd.
Taktéž jsme si prozatím nepopsali instrukce, které se v bajtkódu většinou nevyskytují, a to především z toho důvodu, že jejich použití je z různých důvodů problematické – to je případ instrukcí jsr, jsr_w a ret popsaných ve druhé kapitole, s nimiž se již v bajtkódu vytvářeném moderními implementacemi Javy (JDK6, JDK7) nesetkáme, i když virtuální stroj Javy s těmito instrukcemi umí pracovat.
Začněme však popisem nejjednodušší instrukce virtuálního stroje Javy. Jedná se o instrukci pojmenovanou nop, kterou můžeme najít i v instrukčních sadách reálných mikroprocesorů. Název instrukce nop je vlastně zkratkou vzniklou ze sousloví „no operation“, protože tato instrukce skutečně nic nedělá, pouze v bajtkódu „zabírá“ jeden bajt. V bajtkódu generovaném pomocí překladače javac se s touto instrukcí většinou nesetkáme, ale v případě manipulace s bajtkódem, například s využitím knihovny ASM může být instrukce nop užitečná.
Operační kód instrukce nop je snadno zapamatovatelný, protože se jedná o instrukci ležící na samotném začátku tabulky všech instrukcí, tj. její operační kód je roven 0×00:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
0 | nop | 0×00 | × | neprovede žádnou operaci |
2. Instrukce jsr, jsr_w a ret
Instrukční soubor virtuálního stroje Javy obsahuje i instrukce nazvané jsr a ret. Instrukce jsr, neboli volání subrutiny, existuje ve dvou variantách. V „krátké“ variantě jsr je za instrukčním kódem uvedena relativní adresa (platná v rámci těla metody) reprezentovaná šestnáctibitovým číslem, zatímco „dlouhá“ varianta jsr_w používá relativní 32bitovou adresu (opět jde o adresu relativní v rámci dané metody). Použití 32bitové adresy je však ve skutečnosti zbytečné, neboť délka metod přeložených do bajtkódu je stejně dalšími okolnostmi omezena na 65535 bajtů. Zajímavé je, že instrukce ret taktéž obsahuje parametr. Jedná se o index lokální proměnné, která obsahuje adresu, na níž se má řízení programu vrátit. Můžeme zde tedy nalézt určitou asymetrii (instrukce jsr totiž ukládá návratovou adresu na zásobník operandů a nikoli do lokální proměnné), která však byla do instrukční sady zavedena naschvál, a to kvůli tomu, jakým způsobem se měly instrukce jsr a ret využívat. Operační kódy obou variant instrukce jsr i jediné varianty instrukce ret jsou vypsány v následující tabulce:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
1 | jsr | 0×A8 | highbyte, lowbyte | skok na relativní 16bitovou adresu uloženou v highbyte a lowbyte |
2 | jsr_w | 0×C9 | byte1, byte2, byte3, byte4 | skok na relativní 32bitovou adresu |
3 | ret | 0×A9 | index | skok na adresu zapsanou v lokální proměnné |
Plný název těchto instrukcí – jump to subroutine a return – sice může navozovat dojem, že se jedná o instrukce použitelné pro volání funkcí či metod (funkce = zjednodušeně řečeno veřejná statická metoda), ve skutečnosti tomu ale tak není, protože instrukce jsr a ret slouží, či lépe řečeno v minulosti sloužily, pro skoky v rámci těla jedné metody. Tyto instrukce byly do JVM přidány z toho důvodu, aby bylo možné opakující se části kódu do bajtkódu zapsat pouze jednou. Ovšem vzhledem k tomu, že překladač prakticky neprovádí žádnou optimalizaci bajtkódu (to by znemožnilo pohodlné ladění), využívaly se tyto instrukce pouze pro zápis těla bloku finally. Důvod je prostý – příkazy zapsané v bloku finally se provedou vždy, tedy nezávisle na tom, zda dojde či nedojde k přerušení běhu metody kvůli vzniklé výjimce, což znamená, že při překladu do bajtkódu se vlastně blok finally (resp. příkazy v něm uvedené) volá z více míst; jak po úspěšném dokončení všech příkazů uvedených v bloku try, tak i po vzniku výjimky a jejím zpracování v bloku catch (těchto bloků samozřejmě může existovat libovolné množství).
3. Problémy s instrukcemi jsr, jsr_w a ret
Podívejme se na jednoduchý demonstrační příklad, v němž je v metodě pojmenované tryFinally() použit blok try následovaný blokem finally. Touto konstrukcí programátor naznačuje, že se metoda wrapItUp() má zavolat vždy, nezávisle na tom, zda došlo ke vzniku výjimky či nikoli:
class Test1 { void tryFinally() { try { tryItOut(); } finally { wrapItUp(); } } void tryItOut() {} void wrapItUp() {} }
Starší verze JDK metodu tryFinally() přeložily následujícím způsobem:
Method void tryFinally() // začátek bloku try 0 aload_0 // uložit this (implicitní parametr) na zásobník operandů // this tedy bude předán metodě tryItOut() 1 invokevirtual #6 // zavolání metody tryItOut() uvnitř bloku try 4 jsr 14 // zavolání bloku finally 7 return // konec bloku try a současně i konec metody // blok zavolaný v případě výskytu výjimky 8 astore_1 // uložit referenci na objekt reprezentující výjimku 9 jsr 14 // zavolání bloku finally 12 aload_1 // načíst referenci na objekt reprezentující výjimku 13 athrow // skutečné vyhození výjimky z metody // začátek bloku finally 14 astore_2 // návratová adresa umístěná na TOS instrukcí jsr se uloží do lokální proměnné 15 aload_0 // uložit this (implicitní parametr) na zásobník operandů // this tedy bude předán metodě wrapItUp() 16 invokevirtual #5 // zavolání metody wrapItUp() uvnitř bloku finally 19 ret 2 // návrat z bloku finally (návratová adresa je načtena z proměnné #2) // tabulka používaná při práci s výjimkami bude popsána v dalších kapitolách Exception table: From To Target Type 0 4 8 any
Později se však přišlo na to, že větvení běhu programu s využitím skoku do subrutin zvětšuje – a to mnohdy velmi podstatně – stavový prostor metody, který je kontrolován verifikátorem při načítání bajtkódu. Tento nedostatek mohl být zneužit k DOS útokům, protože virtuálnímu stroji mohl být předán bajtkód se speciálně upravenou metodou obsahující mnoho volání subrutin. Z tohoto důvodu se dnes již s instrukcemi jsr, jsr_w a ret nesetkáme, protože moderní překladače vytvoří následující batjkód:
void tryFinally(); Code: // začátek bloku try 0 aload_0 // uložit this (implicitní parametr) na zásobník operandů // this tedy bude předán metodě tryItOut() 1: invokevirtual #2; // zavolání metody tryItOut() uvnitř bloku try // zde začíná první sekvence instrukcí odpovídající bloku finally 4: aload_0 // uložit this (implicitní parametr) na zásobník operandů // this tedy bude předán metodě wrapItUp() 5: invokevirtual #3; // zavolání metody wrapItUp() 8: goto 18 // konec bloku try 11: astore_1 // blok zavolaný v případě výskytu výjimky // zde začíná druhá sekvence instrukcí odpovídající bloku finally 12: aload_0 // uložit this (implicitní parametr) na zásobník operandů // this tedy bude předán metodě wrapItUp() 13: invokevirtual #3; // zavolat metodu wrapItUp() - opakujeme se! 16: aload_1 17: athrow // skutečné vyhození výjimky z metody 18: return // konec metody // tabulka používaná při práci s výjimkami bude popsána v dalších kapitolách Exception table: from to target type 0 4 11 any 11 12 11 any
Blok finally se tedy v bajtkódu může opakovat, ovšem stavový prostor metody je jednodušší a lépe verifikovatelný.
4. Instrukce invokeinterface
Další prozatím nepopsanou instrukcí je instrukce nazvaná invokeinterface. Tato instrukce slouží k zavolání metody rozhraní, což sice může vypadat poněkud nesmyslně (v rozhraní mohou být pouze hlavičky metod, ale ne jejich implementace), ale v řeči tvůrců bajtkódu se tím myslí stav, kdy se volá metoda, jejíž konkrétní implementaci je možné rozeznat až v čase běhu programu (runtime). Instrukce invokeinterface se částečně podobá již popsaným instrukcím invokestatic, invokevirtual a invokespecial, ovšem s tím rozdílem, že se za operačním kódem nachází jak dvojice bajtů obsahujících index do constant poolu, tak i počet argumentů volané metody. Ve skutečnosti se však jedná o údaj, který se zde nachází z historických důvodů a čistě teoreticky by nemusel být uváděn, protože počet argumentů metody lze získat i z její signatury uložené na constant poolu. V následující tabulce jsou pro přehlednost uvedeny všechny čtyři instrukce sloužící pro zavolání různých typů metod.
# | 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ů |
3 | invokespecial | 0×B7 | highbyte, lowbyte | zavolání speciální metody, většinou konstruktoru |
4 | invokeinterface | 0×B9 | highbyte, lowbyte, count | zavolání metody deklarované v rozhraní, samozřejmě s předáním parametrů |
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 či rozhraní) a taktéž na záznam typu Name and Type (signatura metody či atributu).
Podívejme se na případ, v němž překladač musí použít metodu invokeinterface, protože v čase překladu nemůže rozhodnout o tom, metoda jaké třídy se bude ve skutečnosti volat – může se jednat o metodu compareTo() jakékoli třídy implementující rozhraní Comparable:
class Test2 { public int compare(Comparable a, Comparable b) { return a.compareTo(b); } }
Vygenerovaný bajtkód vypadá následovně:
public int compare(java.lang.Comparable, java.lang.Comparable); Code: 0: aload_1 // uložit na zásobník první (viditelný) parametr metody - objekt a 1: aload_2 // uložit na zásobník druhý (viditelný) parametr metody - objekt b 2: invokeinterface #2, 2; // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I // první dvojka je index do constant poolu // první dvojka je počet parametrů metody (this, b) 7: ireturn // návrat z metody compare() s návratovou hodnotou
5. Demonstrační příklad: rozdíl mezi voláním metody rozhraní a běžné virtuální metody
Z předchozího popisu nemusí být možná zcela zřejmé, ve kterých případech použije překladač instrukci invokevirtual a kdy se naopak musí uchýlit k instrukci invokeinterface. Ukažme si proto ještě jeden demonstrační příklad, v němž budou použity obě instrukce. Ve zdrojovém kódu tohoto příkladu je trojice metod, z nichž první přidává prvek do obecné kolekce, tedy do v čase překladu neznámé třídy, o níž je známo jen to, že implementuje rozhraní Collection. Ve druhé metodě se přidává prvek do kolekce typu seznam, tj. do v čase překladu neznámé třídy implementující rozhraní List a teprve v metodě třetí se prvek přidává do kolekce reprezentované známou implementací – třídou ArrayList. Všechny tři metody v demonstračním příkladu vypadají podobně, ale jejich bajtkód se bude lišit:
import java.util.Collection; import java.util.List; import java.util.ArrayList; class Test3 { public void addToCollection(Collection c, Object o) { c.add(o); } public void addToList(List l, Object o) { l.add(o); } public void addToArrayList(ArrayList l, Object o) { l.add(o); } }
V bajtkódu metody addCollection() se musí volat metoda rozhraní, protože překladač nemůže v době překladu vědět, která konkrétní třída (resp. instance které třídy) bude této metodě v čase běhu programu předána:
public void addToCollection(java.util.Collection, java.lang.Object); Code: 0: aload_1 // uložit první (viditelný) parametr metody na zásobník (obecná kolekce) 1: aload_2 // uložit druhý (viditelný) parametr metody na zásobník (prvek) 2: invokeinterface #2, 2; // metoda rozhraní java/util/Collection.add:(Ljava/lang/Object;)Z // Z v signatuře značí návratovou hodnotu typu boolean 7: pop // odstranit návratovou hodnotu vrácenou metodou Collection.add() 8: return // návrat z metody
Podobné je tomu i v bajtkódu metody addToList():
public void addToList(java.util.List, java.lang.Object); Code: 0: aload_1 // uložit první (viditelný) parametr metody na zásobník (seznam) 1: aload_2 // uložit druhý (viditelný) parametr metody na zásobník (prvek) 2: invokeinterface #3, 2; // metoda rozhraní java/util/List.add:(Ljava/lang/Object;)Z // Z v signatuře značí návratovou hodnotu typu boolean 7: pop // odstranit návratovou hodnotu vrácenou metodou List.add() 8: return // návrat z metody
Teprve v metodě addToArrayList() již překladač ví, že se bude volat metoda třídy ArrayList, popř. metoda potomka této třídy. Proto může použít instrukci invokevirtual a nikoli invokeinterface:
public void addToArrayList(java.util.ArrayList, java.lang.Object); Code: 0: aload_1 // uložit první (viditelný) parametr metody na zásobník (seznam) 1: aload_2 // uložit druhý (viditelný) parametr metody na zásobník (prvek) 2: invokevirtual #4; // metoda java/util/ArrayList.add:(Ljava/lang/Object;)Z // Z v signatuře značí návratovou hodnotu typu boolean 5: pop // odstranit návratovou hodnotu vrácenou metodou ArrayList.add() 6: return // návrat z metody
6. Vyhození výjimky s využitím instrukce athrow
Další důležitou instrukcí, kterou můžeme v bajtkódu často nalézt, je instrukce nazvaná athrow. Tato instrukce slouží k vyhození výjimky, přičemž při zavolání této instrukce musí být reference na objekt reprezentující výjimku uložena na vrcholu (TOS) zásobníku operandů. Tato instrukce nemá žádné operandy:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
1 | athrow | 0×BF | × | vyhození výjimky |
Bajtkód každé metody navíc může obsahovat tabulku obsahující seznam výjimek, které mohou nastat a adresy instrukcí, na něž se provede skok ve chvíli, kdy k dané výjimce skutečně dojde. Pokud však tato tabulka není přítomna, popř. neobsahuje záznam s daným typem výjimky, je výjimka vyhozena (throw) z metody a může být zachycena v nadřazených metodách, opět s využitím zmíněné tabulky.
Opět se podívejme na jednoduchý demonstrační příklad. Ten obsahuje dvě metody, z nichž jedna vyvolá obecnou výjimku typu RuntimeException(), jejíž objekt je zkonstruován bezparametrickým konstruktorem, zatímco druhá metoda vyvolá tutéž výjimku, ovšem sestrojenou konstruktorem s parametrem typu String:
class Test4 { public static void throwRuntimeException1() { throw new RuntimeException(); } public static void throwRuntimeException2() { throw new RuntimeException("Hello world!"); } }
Bajtkód první metody je velmi jednoduchý, protože se v něm nejdříve zavolá instrukce new pro vytvoření instance třídy RuntimeException a následně je zavolán její konstruktor. Poslední instrukce výjimku skutečně vyvolá:
public static void throwRuntimeException1(); Code: 0: new #2; // vytvoření instance třídy java/lang/RuntimeException 3: dup // zachovat referenci pro instrukci athrow 4: invokespecial #3; // konstruktor: metoda java/lang/RuntimeException."<init>":()V 7: athrow // vyhození výjimky
Druhou metodu lze považovat za poněkud kuriózně pojatou variantu na program vypisující řetězec „Hello world!“:
public static void throwRuntimeException2(); Code: 0: new #2; // vytvoření instance třídy java/lang/RuntimeException 3: dup // zachovat referenci pro instrukci athrow 4: ldc #4; // konstantní řetězec "Hello world!" 6: invokespecial #5; // konstruktor: metoda java/lang/RuntimeException."<init>":(Ljava/lang/String;)V 9: athrow // vyhození výjimky
7. Synchronizace s využitím instrukcí monitorenter a monitorexit
Zajímavou dvojici instrukcí, kterou jsme si až doposud nepopsali, tvoří instrukce nazvané monitorenter a monitorexit. Jedná se o instrukce, které jsou využívány zejména pro implementaci synchronizovaných bloků, tj. bloků příkazů prováděných v daném okamžiku maximálně jedním vláknem. Princip práce obou instrukcí je založen na tom, že každému objektu je již v době jeho konstrukce přiřazen monitor (tj. jeden z typů synchronizačního primitiva), který může vlastnit pouze (lepé řečeno maximálně) jedno vlákno. Instrukce monitorenter slouží k získání tohoto monitoru s tím, že v případě, že je již monitor daného objektu vlastněn jiným vláknem, bude současné vlákno čekat na uvolnění tohoto monitoru, popř. při špatném naprogramování dojde k oblíbenému deadlocku :-). Opačný význam má instrukce monitorexit, která naopak monitor uvolní a zpřístupní tak dalším případně čekajícím vláknům. Obě popisované instrukce při svém spuštění očekávají, že se na vrcholu zásobníku operandů bude nacházet reference na objekt, jehož monitor se má při vstupu do synchronizovaného bloku použít:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
1 | monitorenter | 0×C2 | × | vstup do synchronizovaného bloku (získání monitoru) |
2 | monitorexit | 0×C3 | × | výstup ze synchronizovaného bloky (uvolnění monitoru) |
Opět si ukážeme jednoduchý demonstrační příklad, který bude ilustrovat, jakým způsobem se instrukce monitorenter a monitorexit používají. Zdrojový kód tohoto příkladu je následující:
class Test5 { Object zamek; public int syncAdd(int x, int y) { synchronized(zamek) { return x + y; } } public void syncHelloWorld() { synchronized(zamek) { System.out.println("Hello world!"); } } }
Bajtkód metody syncAdd() obsahuje jak synchronizovaný blok, tak i – což je velmi důležité – sekvenci instrukcí, která zajistí uvolnění monitoru a to i při výskytu jakéhokoli typu výjimky:
public int syncAdd(int, int); Code: 0: aload_0 // uložení this na TOS 1: getfield #2; // Field zamek:Ljava/lang/Object; 4: dup // duplikace reference na zámek 5: astore_3 // uložení zámku do lokální pomocné proměnné 6: monitorenter // vstup do synchronizovaného bloku 7: iload_1 // uložení prvního viditelného parametru metody na zásobník 8: iload_2 // uložení druhého viditelného parametru metody na zásobník 9: iadd // součet 10: aload_3 // načtení reference na zámek do TOS 11: monitorexit // výstup ze synchronizovaného bloku 12: ireturn // návratová hodnota metody je nyní na TOS // blok instrukcí zavolaný v případě výskytu výjimky 13: astore 4 // meziuložení objektu reprezentujícího výjimku 15: aload_3 // načíst zámek (referenci na zámek) 16: monitorexit // výstup ze synchronizovaného bloku 17: aload 4 // reference na výjimku 19: athrow // skutečné vyhození výjimky // blok instrukcí zavolaný v případě výskytu výjimky Exception table: from to target type 7 12 13 any 13 17 13 any
I v případě bajtkódu metody syncHelloWorld() je použita sekvence instrukcí pro uvolnění monitoru při výskytu výjimky:
public void syncHelloWorld(); Code: 0: aload_0 // uložení this na TOS 1: getfield #2; // Field zamek:Ljava/lang/Object; 4: dup // duplikace reference na zámek 5: astore_1 // uložení zámku do lokální pomocné proměnné 6: monitorenter // vstup do synchronizovaného bloku 7: getstatic #3; // atribut java/lang/System.out:Ljava/io/PrintStream; 10: ldc #4; // konstantní řetězec "Hello world!" 12: invokevirtual #5; // metoda java/io/PrintStream.println:(Ljava/lang/String;)V 15: aload_1 // načtení reference na zámek do TOS 16: monitorexit // výstup ze synchronizovaného bloku 17: goto 25 // skok na příkaz return 20: astore_2 // meziuložení objektu reprezentujícího výjimku 21: aload_1 // načíst zámek (referenci na zámek) 22: monitorexit // výstup ze synchronizovaného bloku 23: aload_2 // reference na výjimku 24: athrow // skutečné vyhození výjimky 25: return // návrat z metody Exception table: from to target type 7 17 20 any 20 23 20 any
8. Kontrola typů za běhu: instrukce instanceof a checkcast
Posledními dvěma instrukcemi, s nimiž se v dnešním článku seznámíme, jsou instrukce nazvané instanceof a checkcast. Instrukce instanceof je přímým protějškem stejnojmenného operátoru nabízeného programovacím jazykem Java. Tento operátor a tím pádem i tato instrukce slouží ke zjištění, zda je objekt instancí dané třídy, přičemž se tento test většinou provádí až v čase běhu aplikace (JVM samozřejmě podporuje plnohodnotné RTTI – runtime type identification). Výsledkem testu je pravdivostní hodnota true popř. false. Druhá instrukce checkcast provádí velmi podobný test, ovšem s tím rozdílem, že se namísto pravdivostní hodnoty false v případě neshody typu objektu vyvolá výjimka ClassCastException. Překladač tuto instrukci vkládá do bajtkódu zejména tehdy, pokud programátor zapíše do zdrojového kódu přetypování, které nemusí být vždy typově bezpečné.
Operační kódy instrukcí instanceof a checkcast jsou vypsány v tabulce umístěné pod tímto odstavcem:
# | Instrukce | Opkód | Operandy | Prováděná operace |
---|---|---|---|---|
1 | instanceof | 0×C1 | highbyte, lowbyte | test, zda je objekt zadaného typu |
2 | checkcast | 0×C0 | highbyte, lowbyte | kontrola, zda je objekt zadaného typu |
Podívejme se na demonstrační příklad obsahující dvě metody. V první metodě je použit operátor instanceof, který se přímo přeloží do stejně pojmenované instrukce. Ve druhé metodě je parametr typu Object přetypován na objekt typu String, což vede k tomu, že překladač vloží do kódu nezbytné kontroly, zda lze toto přetypování skutečně v čase běhu programu provést:
class Test6 { public boolean isString(Object o) { return o instanceof String; } public String returnString(Object o) { return (String)o; } }
Bajtkód metody isString() vypadá následovně:
public boolean isString(java.lang.Object); Code: 0: aload_1 // načtení prvního viditelného parametru metody 1: instanceof #2; // test, zda se jedná o instanci java/lang/String 4: ireturn // hodnota true/false je současně i návratovou hodnotou metody
V bajtkódu metody returnString můžeme vidět vloženou instrukci checkcast, jejíž zavolání může vyvolat výjimku typu ClassCastException v případě, že metodě nebyl předán objekt typu String:
public java.lang.String returnString(java.lang.Object); Code: 0: aload_1 // načtení prvního viditelného parametru metody 1: checkcast #2; // kontrola, zda se jedná o instanci java/lang/String 4: areturn // pokud nedošlo k výjimce, vrátí se reference na objekt uložený na TOS
9. Odkazy na Internetu
- Java 6 try/finally compilation without jsr/ret
http://cliffhacks.blogspot.com/2008/02/java-6-tryfinally-compilation-without.html - An empirical study of Java bytecode programs
http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/ - 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