Obsah
1. Pohled pod kapotu JVM – zpracování výjimek v JVM, Python VM a Lua VM
2. Porovnání způsobů práce s výjimkami v jazycích Java, Lua a Python
3. Výjimky v programovacím jazyku Java
4. Vyhození výjimky s využitím instrukce athrow
5. Demonstrační příklad Test31.java: vyhození výjimky typu RuntimeException
6. Překlad demonstračního příkladu Test31.java do bajtkódu JVM
7. Demonstrační příklad Test32.java: vyhození výjimky typu Exception
8. Překlad demonstračního příkladu Test32.java do bajtkódu JVM
9. Demonstrační příklad Test33.java: implementace struktury try-catch
10. Překlad demonstračního příkladu Test33.java do bajtkódu JVM
11. Demonstrační příklad Test34.java: implementace struktury try-catch-finally
12. Překlad demonstračního příkladu Test34.java do bajtkódu JVM
13. Repositář se zdrojovými kódy všech sedmi dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – zpracování výjimek v JVM, Python VM a Lua VM
V předchozích částech tohoto seriálu jsme si popsali již prakticky všechny skupiny instrukcí, které je možné najít v bajtkódech určených pro zpracování (běh) ve virtuálních strojích Javy (JVM), Pythonu (Python VM) i ve virtuálním stroji programovacího jazyka Lua (Lua VM). Ještě si však musíme popsat jednu velmi důležitou vlastnost všech tří zmíněných bajtkódů – jedná se o instrukce a o specializované datové struktury použité při zpracování výjimek i při implementaci bloků try-catch-finally popř. jejich ekvivalentů (to se týká především jazyka Lua, který tyto bloky v současné verzi nepodporuje). Dnes se budeme zabývat převážně virtuálním strojem Javy, ovšem v následující části tohoto seriálu si osvětlíme princip práce s výjimkami i ve virtuálním stroji Pythonu a taktéž Lua VM.
2. Porovnání způsobů práce s výjimkami v jazycích Java, Lua a Python
Nejprve se na problematiku výjimek, včetně způsobu jejich vyhazování i zachycování, podívejme z hlediska programátora vytvářejícího aplikace v Javě, Pythonu či v jazyku Lua. Teprve poté si vysvětlíme způsob práce s výjimkami přímo v bajtkódu.
Začněme popisem práce s výjimkami v Javě. V tomto programovacím jazyku má vývojář k dispozici hned několik klíčových slov určených jak pro označení těch výjimek, které mohou vzniknout v nějaké metodě (klíčové slovo throws), tak i pro samotné programové vyhození výjimky zvoleného typu (klíčové slovo throw) i její zachycení (struktura tvořená dvojicí programových bloků try-catch popř. rozšířená i o blok finally). V prvním příkladu ModuloByZero.java je ukázáno použití bloků try-catch-finally při výpočtu zbytku po dělení i pro korektní reakci na stav, kdy je dělitel nulový. Pokud dojde k dělení nulou (a operace % taktéž provádí dělení), je vyhozena výjimka typu ArithmeticException, která je následně ve stejné metodě zachycena a vhodným způsobem zpracována:
public class Test { public static void main(String[] args) { int x = 42; int y = 0; try { int z = x % y; } catch (ArithmeticException e) { System.out.println("div/mod by zero detected!"); System.out.println(e); } finally { System.out.println("done"); } } }
Prakticky stejným způsobem jsou programové bloky try-catch-finally implementovány i v programovacím jazyku Python, až na jeden nepatrný (syntaktický) rozdíl – namísto klíčového slova catch se zde používá slovo except. Demonstrační příklad ModuloByZero.py, jehož zdrojový kód je umístěn pod tímto odstavcem, se do značné míry podobá výše uvedenému příkladu ModuloByZero.java, ovšem samotný zápis je mnohem stručnější (což se ostatně dá od Pythonu očekávat :-) a navíc i univerzálnější v případě, že bude operátor % přetížen a namísto číselných proměnných x a y budou použity objekty, které s operátorem % dokážou korektně pracovat:
x = 42 y = 0 try: z = x % y except ZeroDivisionError, e: print "div/mod by zero detected!" print e finally: print "done"
Zcela odlišná je však implementace podobného příkladu v programovacím jazyce Lua, a to z toho důvodu, že tento jazyk přímo neobsahuje podporu pro bloky try-catch-finally. Namísto toho je aplikován „funkcionální“ přístup, kdy je ta část programu, v níž může nastat nějaká výjimka, umístěna do samostatné funkce, která se pak zavolá v „sandboxu“ s využitím funkce pcall() (protected call). Výjimka se vyhazuje funkcí error() a pokud výjimka skutečně nastane, vrací funkce pcall() ve svém prvním výsledku hodnotu false (další návratová hodnota či návratové hodnoty již souvisí s volanou funkcí). V demonstračním příkladu ModuloByZero.lua je navíc použit malý trik se zjištěním, zda při dělení či při operaci modulo nedošlo k dělení nulou, protože Lua v tomto případě automaticky výjimku nevyhazuje (zmíněný trik je založen na normě IEEE 754 tvrdící, že dvě hodnoty NaN si nejsou nikdy rovny):
function mod(x, y) local result = x % y if result ~= result then error("ArithmeticException: / by zero") end return result end local x = 42 local y = 0 local status, result = pcall(mod , x, y) print(status, result) x = 10 y = 3 local status, result = pcall(mod , x, y) print(status, result)
3. Výjimky v programovacím jazyku Java
V programovacím jazyku Java je zpracování výjimek nedílnou součástí syntaxe i sémantiky, a to již od první verze Javy. Totéž platí o bajtkódu JVM, který obsahuje podporu pro instrukci athrow popsanou ve čtvrté kapitole a navíc se v bajtkódu používají i datové struktury popisující ty části bajtkódu, kde může vzniknout zachycovaná výjimka či výjimky. Díky této podpoře a taktéž s využitím podmíněných a nepodmíněných skoků lze bloky try-catch-finally v bajtkódu implementovat relativně úsporným způsobem, což bude ostatně ukázáno na demonstračních příkladech Test31, Test32, Test33 a konečně Test34.
4. Vyhození výjimky s využitím instrukce athrow
Velmi důležitou instrukcí, kterou můžeme v bajtkódu virtuálního stroje Javy často nalézt, je instrukce nazvaná příznačně 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ů (právě z tohoto důvodu začíná jméno instrukce znakem „a“, podobně jako jména prakticky všech instrukcí zpracovávajících reference na objekty a nikoli primitivní datové typy). Tato instrukce nemá žádné další operandy (kromě reference uložené na TOS), takže její celková velikost je přesně jeden bajt:
# | 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. Podrobnosti si ukážeme v následujících čtyřech demonstračních příkladech.
5. Demonstrační příklad Test31.java: vyhození výjimky typu RuntimeException
Způsob překladu Javovských programů, v nichž se používají a popř. i zpracovávají výjimky, si dnes ukážeme na čtveřici velmi jednoduchých demonstračních příkladů. V prvním příkladu nazvaném Test31 se ve statické metodě pojmenované throwRuntimeException() programově vyhazuje výjimka typu RuntimeException. Tento typ výjimky není zapotřebí zmiňovat v hlavičce metody a dokonce ho není ani nutné v aplikaci explicitně zachytit (tyto kontroly provádí již překladač javac, ovšem RuntimeException a od ní odvozené výjimky nepatří mezi výjimky kontrolované – checked). Pokud ovšem k této výjimce při běhu programu skutečně dojde a výjimka není nikde zachycena, bude běh programu a tím pádem i běh virtuálního stroje Javy ukončen a na terminál se vypíše klasický stack trace (poněkud odlišné je ovšem chování takové aplikace, kde k výjimce dojde v jiném vláknu; zde k ukončení celé JVM nedojde). Podívejme se nyní na zdrojový kód tohoto velmi jednoduchého demonstračního příkladu:
/** * Demonstracni priklad cislo 31. * * Vyhozeni vyjimky typu RuntimeException z testovane metody. */ public class Test31 { /** * Metoda, ktera vyhodi vyjimku typu RuntimeException() */ public static void throwRuntimeException() { throw new RuntimeException(); } /** * Zavolani metody throwRuntimeException(). */ public static void main(String[] args) { throwRuntimeException(); } }
Po spuštění tohoto demonstračního příkladu se na terminálu objeví informace o výjimce vyhozené z metody throwRuntimeException a následně i z metody main. Tato informace se vypíše ještě předtím, než se ukončí běh virtuálního stroje Javy:
Exception in thread "main" java.lang.RuntimeException at Test31.throwRuntimeException(Test31.java:12) at Test31.main(Test31.java:19)
6. Překlad demonstračního příkladu Test31.java do bajtkódu JVM
Překlad metody throwRuntimeException() do bajtkódu JVM je velmi jednoduchý. V těle této metody se nejdříve vytvoří a náležitě inicializuje objekt třídy RuntimeException a následně je použita instrukce athrow pro vyhození výjimky. Tato instrukce požaduje, aby na TOS byla umístěna reference na objekt představující výjimku, což je i důvod použití instrukce dup. Povšimněte si, že metoda neobsahuje žádné speciální označení ani metadata říkající, že při jejím běhu může k výjimce skutečně dojít:
public static void throwRuntimeException(); Code: 0: new #2; // vytvoření instance třídy java.lang.RuntimeException 3: dup // kopie reference na nově vytvořený objekt // inicializace objektu 4: invokespecial #3; // Method java/lang/RuntimeException."<init>":()V 7: athrow // objekt byl inicializován, vyhození výjimky
Ani při volání metody throwRuntimeException() není zapotřebí žádným způsobem specifikovat, že může dojít k výjimce:
)public static void main(java.lang.String[]); Code: 0: invokestatic #4; // zavolání statické metody throwRuntimeException() 3: return // ukončení běhu metody main()
Pro úplnost je ještě vypsán obsah constant poolu, protože výše uvedené bajtkódy používaly záznamy uložené na indexech 2, 3 a 4 (a samozřejmě i záznamy z těchto záznamů referencované):
Constant pool: #1 = Methodref #6.#16; // java/lang/Object."<init>":()V #2 = Class #17; // java/lang/RuntimeException #3 = Methodref #2.#16; // java/lang/RuntimeException."<init>":()V #4 = Methodref #5.#18; // Test31.throwRuntimeException:()V #5 = Class #19; // Test31 #6 = Class #20; // java/lang/Object #7 = Utf8 <init>; #8 = Utf8 ()V; #9 = Utf8 Code; #10 = Utf8 LineNumberTable; #11 = Utf8 throwRuntimeException; #12 = Utf8 main; #13 = Utf8 ([Ljava/lang/String;)V; #14 = Utf8 SourceFile; #15 = Utf8 Test31.java; #16 = NameAndType #7:#8; // "<init>":()V #17 = Utf8 java/lang/RuntimeException; #18 = NameAndType #11:#8; // throwRuntimeException:()V #19 = Utf8 Test31; #20 = Utf8 java/lang/Object;
7. Demonstrační příklad Test32.java: vyhození výjimky typu Exception
Zdrojový kód demonstračního příkladu Test32.java se do značné míry podobá zdrojovému kódu výše uvedeného příkladu Test31.java. Najdeme zde však tři odlišnosti. První odlišnost spočívá v tom, že se namísto výjimky typu RuntimeException programově vyhazuje výjimka typu Exception. S tím souvisí i další dvě změny – výjimky typu Exception (a samozřejmě i všechny odvozené výjimky) je zapotřebí buď explicitně zachytit nebo (opět explicitně) u metod, kde může výjimka vzniknout, použít zápis throws Exception, aby tak vývojář dal překladači Javy najevo, že se zpracováním výjimky tohoto typu ve své aplikaci počítá. Právě z tohoto důvodu jsou v hlavičkách obou statických funkcí deklarovaných ve třídě Test32 použity zápisy throws Exception; v opačném případě by nebylo možné provést úspěšný překlad tohoto příkladu:
/** * Demonstracni priklad cislo 32. * * Vyhozeni vyjimky typu Exception z testovane metody. */ public class Test32 { /** * Metoda, ktera vyhodi vyjimku typu Exception() */ public static void throwException() throws Exception { throw new Exception(); } /** * Zavolani metody throwException(). */ public static void main(String[] args) throws Exception { throwException(); } }
I po spuštění tohoto demonstračního příkladu dojde k ukončení běhu virtuálního stroje Javy. Opět se vypíše i historie volání metod uložených v jednotlivých zásobníkových rámcích:
Exception in thread "main" java.lang.Exception at Test32.throwException(Test32.java:12) at Test32.main(Test32.java:19)
8. Překlad demonstračního příkladu Test32.java do bajtkódu JVM
Velmi zajímavé bude zjistit, do jaké míry se budou odlišovat bajtkódy tříd Test31 a Test32. Překlad metody throwException():
public static void throwException() throws java.lang.Exception; Code: 0: new #2; // vytvoření instance třídy java.lang.Exception 3: dup // kopie reference na nově vytvořený objekt // inicializace objektu 4: invokespecial #3; // Method java/lang/Exception."<init>":()V 7: athrow // objekt byl inicializován, vyhození výjimky
Vidíme, že jediný rozdíl spočívá v přidané deklaraci „throws java.lang.Exception;“, což lze považovat za metadata bajtkódu.
Překlad metody main():
public static void main(java.lang.String[]) throws java.lang.Exception; Code: 0: invokestatic #4; // zavolání statické metody throwException:()V 3: return // ukončení běhu metody main()
I zde došlo pouze k přidání deklarace „throws java.lang.Exception“. Žádné další změny v bajtkódu nenajdeme.
Na závěr bude opět vypsán obsah constant poolu bajtkódu třídy Test32:
#1 = Methodref #6.#17; // java/lang/Object."<init>":()V #2 = Class #18; // java/lang/Exception #3 = Methodref #2.#17; // java/lang/Exception."<init>":()V #4 = Methodref #5.#19; // Test32.throwException:()V #5 = Class #20; // Test32 #6 = Class #21; // java/lang/Object #7 = Utf8 <init>; #8 = Utf8 ()V; #9 = Utf8 Code; #10 = Utf8 LineNumberTable; #11 = Utf8 throwException; #12 = Utf8 Exceptions; *** přidaný záznam *** #13 = Utf8 main; #14 = Utf8 ([Ljava/lang/String;)V; #15 = Utf8 SourceFile; #16 = Utf8 Test32.java; #17 = NameAndType #7:#8; // "<init>":()V #18 = Utf8 java/lang/Exception; #19 = NameAndType #11:#8; // throwException:()V #20 = Utf8 Test32; #21 = Utf8 java/lang/Object;
9. Demonstrační příklad Test33.java: implementace struktury try-catch
Demonstrační příklad nazvaný Test33.java se od obou předchozích demonstračních příkladů odlišuje, protože zde výjimku vyhazovanou z metody pojmenované throwException() zachycujeme, a to (samozřejmě) v bloku catch, kterému předchází blok try. Vzhledem k tomu, že výjimka je při volání statické metody throwException() skutečně vyhozena vždy, není příkaz „System.out.println(„try block“);“ umístěný v bloku try nikdy proveden; namísto toho je naopak vždy proveden příkaz „System.out.println(„catch block“);“ umístěný v bloku catch:
/** * Demonstracni priklad cislo 33. * * Implementace struktury try-catch. */ public class Test33 { /** * Metoda, ktera vyhodi vyjimku typu Exception() */ public static void throwException() throws Exception { throw new Exception(); } /** * Zavolani metody throwException(). */ public static void main(String[] args) throws Exception { try { throwException(); System.out.println("try block"); } catch (Exception e) { System.out.println("catch block"); } } }
Při spuštění tohoto příkladu se na standardním výstupu zobrazí (podle všech očekávání) jediný řádek textu:
catch block
10. Překlad demonstračního příkladu Test33.java do bajtkódu JVM
Bajtkód demonstračního příkladu Test33.java již musí obsahovat instrukce zajišťující zachycení a zpracování výjimky, proto bude velmi zajímavé ho prozkoumat. Metoda throwException() se přeloží naprosto stejným způsobem, jaký již známe z předchozího příkladu:
public static void throwException() throws java.lang.Exception; Code: 0: new #2; // vytvoření instance třídy java.lang.Exception 3: dup // kopie reference na nově vytvořený objekt // inicializace objektu 4: invokespecial #3; // Method java/lang/Exception."<init>":()V 7: athrow // objekt byl inicializován, vyhození výjimky
Ovšem bajtkód metody main() je již komplikovanější:
public static void main(java.lang.String[]) throws java.lang.Exception; Code: *** blok try *** 0: invokestatic #4; // volání metody throwException:()V // příprava na volání metody System.out.println() 3: getstatic #5; // Field java/lang/System.out:Ljava/io/PrintStream; 6: ldc #6; // konstanta obsahující řetězec "try block" 8: invokevirtual #7; // volání metody java.io.PrintStream.println:(java.lang.String) 11: goto 23 // skok ZA konec bloku catch *** blok catch *** 14: astore_1 // začátek bloku catch // příprava na volání metody System.out.println() 15: getstatic #5; // Field java/lang/System.out:Ljava/io/PrintStream; 18: ldc #8; // konstanta obsahujici retezec "catch block" 20: invokevirtual #7; // volání metody java.io.PrintStream.println:(java.lang.String) *** konec konstrukce try-catch *** 23: return // ukončení běhu metody main() Exception table: // tabulka obsahující seznam řádků a případných výjimek from to target type 0 11 14 Class java/lang/Exception
V tomto bajtkódu již můžeme vidět dvě novinky. První novinka je vlastně očekávaná – první sekvence instrukcí představuje tělo bloku try, druhá sekvence instrukcí pak tělo bloku catch. Na konci těla prvního bloku je umístěna instrukce goto provádějící nepodmíněný skok za účelem přeskoku celého bloku catch. Za jakých okolností je tělo bloku catch provedeno je specifikováno v datové struktuře Exception table. Zde jsou uloženy záznamy obsahující rozsah indexů instrukcí, kde může dojít k výjimce, index instrukce, na kterou se skočí v případě skutečného vzniku výjimky a samozřejmě i typ výjimky.
11. Demonstrační příklad Test34.java: implementace struktury try-catch-finally
Dnešní poslední demonstrační příklad nazvaný Test34.java je vlastně obdobou předchozího příkladu Test33.java, ovšem namísto neúplné struktury try-catch je zde implementována úplná programová struktura try-catch-finally, přičemž příkazy umístěné v bloku finally jsou vykonány vždy, nezávisle na tom, zda k zachycované výjimce dojde či nikoli:
/** * Demonstracni priklad cislo 34. * * Implementace struktury try-catch-finally. */ public class Test34 { /** * Metoda, ktera vyhodi vyjimku typu Exception() */ public static void throwException() throws Exception { throw new Exception(); } /** * Zavolani metody throwException(). */ public static void main(String[] args) throws Exception { try { throwException(); System.out.println("try block"); } catch (Exception e) { System.out.println("catch block"); } finally { System.out.println("finally block"); } } }
Podle očekávání dojde při spuštění tohoto příkladu k výpisu pouze dvou řetězců na standardní výstup:
catch block finally block
12. Překlad demonstračního příkladu Test34.java do bajtkódu JVM
Opět si ukažme, jak se obě metody deklarované ve třídě Test34 přeloží do bajtkódu JVM. Začneme bajtkódem metody throwException(), protože v něm nenalezneme žádné odlišnosti od předchozího příkladu:
public static void throwException() throws java.lang.Exception; Code: 0: new #2; // vytvoření instance třídy java.lang.Exception 3: dup // kopie reference na nově vytvořený objekt // inicializace objektu 4: invokespecial #3; // Method java/lang/Exception."<init>":()V 7: athrow // objekt byl inicializován, vyhození výjimky
Bajtkód metody main() je však již velmi rozsáhlý a najdeme zde hned několik nepodmíněných skoků realizovaných instrukcí goto:
public static void main(java.lang.String[]) throws java.lang.Exception; Code: *** blok try *** 0: invokestatic #4; // volání metody throwException:()V // příprava na volání metody System.out.println() 3: getstatic #5; // Field java/lang/System.out:Ljava/io/PrintStream; 6: ldc #6; // konstanta obsahující řetězec "try block" 8: invokevirtual #7; // volání metody java.io.PrintStream.println:(java.lang.String) *** blok finally #1 *** // příprava na volání metody System.out.println() 11: getstatic #5; // Field java/lang/System.out:Ljava/io/PrintStream; 14: ldc #8; // konstanta obsahující řetězec "finally block" 16: invokevirtual #7; // volání metody java.io.PrintStream.println:(java.lang.String) 19: goto 53 // skok ZA konec bloku finally *** blok catch *** 22: astore_1 23: getstatic #5; // Field java/lang/System.out:Ljava/io/PrintStream; 26: ldc #9; // konstanta obsahující řetězec "catch block" 28: invokevirtual #7; // volání metody java.io.PrintStream.println:(java.lang.String) *** blok finally #2 *** 31: getstatic #5; // Field java/lang/System.out:Ljava/io/PrintStream; 34: ldc #8; // konstanta obsahující řetězec "finally block" 36: invokevirtual #7; // volání metody java.io.PrintStream.println:(java.lang.String) 39: goto 53 // skok ZA konec bloku finally *** blok finally #3 - zachycení + rethrow jiné výjimky *** 42: astore_2 // uložit obsah TOS do lokální proměnné 43: getstatic #5; // Field java/lang/System.out:Ljava/io/PrintStream; 46: ldc #8; // konstanta obsahující řetězec "finally block" 48: invokevirtual #7; // volání metody java.io.PrintStream.println:(java.lang.String) 51: aload_2 // obnovit obsah TOS 52: athrow // a ihned vyvolat výjimku, kterou jsme zachytili jen dočasně 53: return // ukončení běhu metody main() Exception table: // tabulka obsahující seznam řádků a případných výjimek from to target type 0 11 22 Class java/lang/Exception // blok try 0 11 42 any // bloky try+finally #1 22 31 42 any // blok catch 42 43 42 any // instrukce zachycení jiné výjimky
Tento bajtkód sice může vypadat poněkud nepřehledně, ale ukázaný způsob překladu má své velmi dobré důvody. „Běžné“ chování metody je implementováno v instrukcích umístěných na indexech 0 až 11. Zde můžeme vidět jak implementaci všech příkazů v bloku try, tak i implementaci všech příkazů v bloku finally. To je vlastně logické, protože když nedojde ke vzniku výjimky, vykonají se právě tyto dva bloky v uvedeném pořadí (napřed blok try, poté blok finally).
V tabulce výjimek můžeme vidět, že instrukce od indexu 0 do indexu 11 jsou zde zmíněny hned dvakrát – pokud zde dojde k výjimce Exception (kterou zachytáváme), provedou se bloky catch+finally #2, které začínají na indexu 22. To je také očekávané chování, které je explicitně zapsáno ve zdrojovém kódu. Zajímavější je předposlední blok finally vykonaný ve chvíli, kdy vznikne jiný typ výjimky. I v tomto případě je totiž nutné vypsat řetězec „finally block“, ale navíc musí neznámá výjimka „probublat“ do volající metody, a to již známým způsobem: s využitím instrukce athrow.
13. Repositář se zdrojovými kódy všech sedmi dnešních demonstračních příkladů
Všech sedm (3+4) dnes popsaných a „disasemblovaných“ demonstračních příkladů bylo uloženo do Mercurial repositáře umístěného na adrese http://icedtea.classpath.org/people/ptisnovs/jvm-tools/ (revize s kódy 320255fc8ed7 a 673d8257fbd1). Odkazy na prozatím poslední verze těchto sedmi příkladů naleznete v tabulce umístěné pod tímto odstavcem:
14. Odkazy na Internetu
- Python Byte Code Instructions
https://docs.python.org/release/2.5.2/lib/bytecodes.html - Python 2.x: funkce range()
https://docs.python.org/2/library/functions.html#range - Python 2.x: typ iterátor
https://docs.python.org/2/library/stdtypes.html#iterator-types - Python break, continue and pass Statements
http://www.tutorialspoint.com/python/python_loop_control.htm - Python Bytecode: Fun With Dis
http://akaptur.github.io/blog/2013/08/14/python-bytecode-fun-with-dis/ - Python's Innards: Hello, ceval.c!
http://tech.blog.aknin.name/category/my-projects/pythons-innards/ - Byterun
https://github.com/nedbat/byterun - Python Byte Code Instructions
http://document.ihg.uni-duisburg.de/Documentation/Python/lib/node56.html - Python Byte Code Instructions
https://docs.python.org/3.2/library/dis.html#python-bytecode-instructions - dis – Python module
https://docs.python.org/2/library/dis.html - Comparison of Python virtual machines
http://polishlinux.org/apps/cli/comparison-of-python-virtual-machines/ - Lambda the Ultimate: Coroutines in Lua,
http://lambda-the-ultimate.org/node/438 - Coroutines Tutorial,
http://lua-users.org/wiki/CoroutinesTutorial - Lua Coroutines Versus Python Generators,
http://lua-users.org/wiki/LuaCoroutinesVersusPythonGenerators - Programming in Lua 9.1 – Coroutine Basics,
http://www.lua.org/pil/9.1.html - Wikipedia CZ: Koprogram,
http://cs.wikipedia.org/wiki/Koprogram - Wikipedia EN: Coroutine,
http://en.wikipedia.org/wiki/Coroutine - Programming in Lua (first edition)
http://www.lua.org/pil/contents.html - Programming in Lua: 6 – More about Functions
http://www.lua.org/pil/6.html - Lua Lanes,
http://kotisivu.dnainternet.net/askok/bin/lanes/ - Programming in Lua: 6.1 – Closures
http://www.lua.org/pil/6.1.html - Programming in Lua: 9.1 – Coroutine Basics
http://www.lua.org/pil/9.1.html - Programming in Lua: Numeric for
http://www.lua.org/pil/4.3.4.html - Programming in Lua: break and return
http://www.lua.org/pil/4.4.html - Programming in Lua: Tables
http://www.lua.org/pil/2.5.html - Programming in Lua: Table Constructors
http://www.lua.org/pil/3.6.html - Programovací jazyk Lua
http://palmknihy.cz/web/kniha/programovaci-jazyk-lua-12651.htm - Lua: Tables Tutorial
http://lua-users.org/wiki/TablesTutorial - Lua: Control Structure Tutorial
http://lua-users.org/wiki/ControlStructureTutorial - Lua Types Tutorial
http://lua-users.org/wiki/LuaTypesTutorial - Goto Statement in Lua
http://lua-users.org/wiki/GotoStatement - Lua 5.2 sources
http://www.lua.org/source/5.2/ - Lua 5.2 sources – lopcodes.h
http://www.lua.org/source/5.2/lopcodes.h.html - Lua 5.2 sources – lopcodes.c
http://www.lua.org/source/5.2/lopcodes.c.html - For-each Loop in Java
http://www.leepoint.net/notes-java/flow/loops/foreach.html - For Loop (Wikipedia)
http://en.wikipedia.org/wiki/For_loop - Heinz Rutishauser
http://en.wikipedia.org/wiki/Heinz_Rutishauser - Parrot
http://www.parrot.org/ - Parrot languages
http://www.parrot.org/languages - Parrot Primer
http://docs.parrot.org/parrot/latest/html/docs/intro.pod.html - Parrot Opcodes
http://docs.parrot.org/parrot/latest/html/ops.html - Parrot VM
http://en.wikibooks.org/wiki/Parrot_Virtual_Machine - Parrot Assembly Language
http://www.perl6.org/archive/pdd/pdd06_pasm.html - Parrot Reference: Chapter 11 – Perl 6 and Parrot Essentials
http://oreilly.com/perl/excerpts/perl-6-and-parrot-essentials/parrot-reference.html - O-code
http://en.wikipedia.org/wiki/O-code_machine - 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 - GC safe-point (or safepoint) and safe-region
http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html - Safepoints in HotSpot JVM
http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html - Java theory and practice: Synchronization optimizations in Mustang
http://www.ibm.com/developerworks/java/library/j-jtp10185/ - How to build hsdis
http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/tools/hsdis/README - Java SE 6 Performance White Paper
http://www.oracle.com/technetwork/java/6-performance-137236.html - Lukas Stadler's Blog
http://classparser.blogspot.cz/2010/03/hsdis-i386dll.html - How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
http://dropzone.nfshost.com/hsdis.htm - PrintAssembly
https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly - The Java Virtual Machine Specification: 3.14. Synchronization
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.14 - The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4 - The Java Virtual Machine Specification: 17.4. Memory Model
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4 - The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7 - Open Source ByteCode Libraries in Java
http://java-source.net/open-source/bytecode-libraries - 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/ - BCEL Home page
http://commons.apache.org/bcel/ - Byte Code Engineering Library (před verzí 5.0)
http://bcel.sourceforge.net/ - Byte Code Engineering Library (verze >= 5.0)
http://commons.apache.org/proper/commons-bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - Javassist
http://www.jboss.org/javassist/ - Byteman
http://www.jboss.org/byteman - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - 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 - 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/ - jclasslib bytecode viewer
http://www.ej-technologies.com/products/jclasslib/overview.html