Obsah
1. Pohled pod kapotu JVM – překlad dalších řídicích struktur do bajtkódů JVM, Lua VM a Python VM
2. Počítaná programová smyčka for – prapředek všech strukturovaných programových smyček
3. Příkaz return – ukončení běhu funkce/metody s předáním návratové hodnoty
4. Ukázky překladu příkazu return do bajtkódu
5. Počítaná programová smyčka for
6. Ukázky překladu jednoduché počítané smyčky typu for do bajtkódu
7. Složitější programová smyčka typu for – výpočet faktoriálu
8. Překlad vnořených počítaných smyček typu for do bajtkódu
9. Příkazy break a continue, popř. jejich ekvivalenty
10. Překlad příkazů typu break a continue do bajtkódu
11. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – překlad dalších řídicích struktur do bajtkódů JVM, Lua VM a Python VM
V dnešní části seriálu o programovacím jazyku Java i o virtuálním stroji Javy si nejprve ukážeme, jakým způsobem se překládají příkazy return do bajtkódu JVM, Lua VM i Python VM. Posléze se budeme věnovat zajímavějšímu tématu – způsobu překladu počítaných programových smyček typu for, protože tento typ programových smyček je (ve své původní variantě) součástí poměrně velkého množství algoritmů, především numerických algoritmů, kde se pracuje s vektory (jednorozměrnými poli) a maticemi (dvourozměrnými poli). Ostatně právě z tohoto důvodu se s tímto typem smyček můžeme setkat už ve třetí generaci programovacích jazyků (v čele s FORTRANem), kde se dokonce původně jednalo o jeden ze dvou způsobů tvorby programových smyček (první způsob využíval příkaz GOTO pro provedení skoku).
2. Počítaná programová smyčka for – prapředek všech strukturovaných programových smyček
U počítané programové smyčky for se na chvíli zastavme, protože historie jejího vzniku je velmi zajímavá a sahá vlastně až do let 1945 a 1946. V této době dokončil slavný konstruktér počítačů Konrad Zuse návrh svého programovacího jazyka nazvaného Plankalkül (slovo „plan“ zde mělo význam podobný slovu „program“, takže například Zusem navrhované „podplány“ byly vlastně „podprogramy/subrutiny/funkce“). Původně sice nebyl tento programovací jazyk skutečně implementován (na to si museli nadšenci počkat ještě zhruba padesát let), ovšem Plankalkül ovlivnil dalšího evropského průkopníka IT – Heinze Rutishausera, který v padesátých letech minulého století navrhl vyšší programovací jazyk nazvaný Superplan. A právě v tomto dnes již polozapomenutém programovacím jazyku se poprvé objevilo klíčové slovo für (tedy německá varianta for), zatímco tvůrci FORTRANu použili klíčové slovo do, jenž má dnes většinou poněkud jiný význam.
Heinz Rutishauser se později podílel na vzniku návrhu programovacího jazyka ALGOL 58, kde se pro počítanou programovou smyčku objevilo (v anglické verzi tohoto jazyka!) klíčové slovo for. ALGOL 58 sice nebyl příliš úspěšný, ovšem jeho nástupce ALGOL 60 již ano a právě odtud se slovo for dostalo jak do „pascalské větve“ (Pascal, Modula, Lua), tak i do „céčkové větve“ (C, C++, Java, JavaScript…) programovacích jazyků.
3. Příkaz return – ukončení běhu funkce/metody s předáním návratové hodnoty
Nejprve si ukážeme, jakým způsobem se do bajtkódu JVM, Lua VM a Python VM překládá příkaz pro návrat z funkce či metody. Tento příkaz se ve všech třech jazycích (Java, Lua i Python) zapisuje klíčovým slovem return, což vlastně není příliš překvapivé, protože toto slovo se v prakticky stejném významu používá v programovacích jazycích již zhruba po dobu padesáti let. Svůj původ má v podobně pojmenované strojové instrukci pro návrat ze subrutiny a podobně se chová i ve vyšších programovacích jazycích (zde se však liší návratové typy a některé jazyky mají sémantiku složitější kvůli existenci uzávěrů – closures). Podívejme se však na demonstrační příklady, z nichž bude patrný i rozdíl mezi všemi třemi popisovanými jazyky.
Demonstrační příklad Test12.java
V programovacím jazyku Java lze příkaz return uvést bez výrazu, ovšem pouze v případě, že se jedná o metodu typu void, tj. metodu bez návratové hodnoty. V opačném případě se musí za klíčové slovo return zapsat výraz odpovídající návratovému typu metody – což může být jeden z primitivních datových typů (boolean, char, byte, short, int, long, float, double) či referenční datový typ, tj. objekt:
/** * Ukazka zpusobu predavani navratovych hodnot * ze statickych metod. */ public class Test12 { /** * Navratova hodnota typu void. */ static void returnVoid() { return; } /** * Navratova hodnota typu boolean. */ static boolean returnBooleanTrue() { return true; } /** * Navratova hodnota typu boolean. */ static boolean returnBooleanFalse() { return false; } /** * Navratova hodnota typu byte. */ static byte returnByte() { return -1; } /** * Navratova hodnota typu char. */ static char returnChar() { return 'a'; } /** * Navratova hodnota typu short. */ static short returnShort() { return 0; } /** * Navratova hodnota typu int. */ static int returnInt() { return 1; } /** * Navratova hodnota typu long. */ static long returnLong() { return 2L; } /** * Navratova hodnota typu float. */ static float returnFloat() { return 3.0f; } /** * Navratova hodnota typu double. */ static double returnDouble() { return 4.0; } /** * Navratova hodnota typu reference. */ static Object returnReference() { return null; } /** * Vse je nutne otestovat. */ public static void main(String[] args) { returnVoid(); System.out.println(returnBooleanTrue()); System.out.println(returnBooleanFalse()); System.out.println(returnByte()); System.out.println(returnChar()); System.out.println(returnShort()); System.out.println(returnInt()); System.out.println(returnLong()); System.out.println(returnFloat()); System.out.println(returnDouble()); System.out.println(returnReference()); } }
Demonstrační příklad Test12.lua
U programovacího jazyka Lua se díky dynamickému typování nemusí uvádět návratové typy funkcí, takže je použití příkazu return v tomto případě poněkud volnější, než tomu bylo v Javě. Příkaz lze uvést bez výrazu, s jedním výrazem či dokonce s několika výrazy. Výrazy mohou být jakéhokoli podporovaného typu, tj. nil (datový typ a současně i jeho jediná povolená hodnota), pravdivostní typ, číslo (celé i reálné), řetězec, tabulka (i asociativní pole) a posledním zajímavým typem je funkce:
-- -- Ukazka zpusobu predavani navratovych hodnot -- z funkci -- -- -- Funkce bez navratove hodnoty -- function returnVoid() return end -- -- Funkce vracejici nil -- function returnNil() return nil end -- -- Navratova hodnota typu Boolean. -- function returnBooleanTrue() return true end -- -- Navratova hodnota typu Boolean. -- function returnBooleanFalse() return false end -- -- Navratova hodnota Number. -- function returnNumber1() return 42 end -- -- Navratova hodnota Number. -- function returnNumber2() return 42.0 end -- -- Navratova hodnota typu String. -- function returnString() return "Hello" end -- -- Navratova hodnota typu table. -- function returnTable() return {1,2,3} end -- -- Navratova hodnota typu function. -- function returnFunction() return function() print("Hello world!") end end -- -- Vse je nutne otestovat. -- function main() print(returnVoid()) print(returnNil()) print(returnBooleanTrue()) print(returnBooleanFalse()) print(returnNumber1()) print(returnNumber2()) print(returnString()) print(returnTable()) print(returnFunction()) end main()
Demonstrační příklad Test12.py
Pro programovací jazyk Python platí podobná pravidla pro použití příkazu return, jako tomu bylo v Lue. Zajímavé je, že lze vracet i strukturované datové typy seznam či n-tice a dokonce i lambda funkce (což na druhou stranu není tak překvapivé, ovšem v Javě jsme si museli na podobnou sémantiku počkat téměř dvacet let :-):
-- -- Ukazka zpusobu predavani navratovych hodnot -- z funkci -- -- -- Funkce bez navratove hodnoty -- def returnVoid(): return -- -- Funkce vracejici None -- def returnNone(): return None -- -- Navratova hodnota typu Boolean. -- def returnBooleanTrue(): return True -- -- Navratova hodnota typu Boolean. -- def returnBooleanFalse(): return False -- -- Navratova hodnota Number. -- def returnNumber1(): return 42 -- -- Navratova hodnota Number. -- def returnNumber2(): return 42.0 -- -- Navratova hodnota typu String. -- def returnString(): return "Hello" -- -- Navratova hodnota typu tuple. -- def returnTuple(): return (1,2,3) -- -- Navratova hodnota typu lambda (anonymni funkce). -- def returnLambda(): return lambda arg1, arg2: arg1 + arg2 -- -- Vse je nutne otestovat. -- def main(): print(returnVoid()) print(returnNone()) print(returnBooleanTrue()) print(returnBooleanFalse()) print(returnNumber1()) print(returnNumber2()) print(returnString()) print(returnTuple()) print(returnLambda()) -- -- Vypsani bajkkodu testovane funkce -- def disassemble(): from dis import dis print("\nreturnVoid:") dis(returnVoid) print("\nreturnNone:") dis(returnNone) print("\nreturnBooleanTrue:") dis(returnBooleanTrue) print("\nreturnBooleanFalse:") dis(returnBooleanFalse) print("\nreturnNumber1:") dis(returnNumber1) print("\nreturnNumber2:") dis(returnNumber2) print("\nreturnString:") dis(returnString) print("\nreturnTuple:") dis(returnTuple) print("\nreturnLambda:") dis(returnLambda) main() disassemble()
4. Ukázky překladu příkazu return do bajtkódu
V této kapitole budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test12.java, Test12.lua i Test12.py.
Bajtkód demonstračního příkladu Test12.java
V bajtkódu JVM existuje několik instrukcí pro ukončení metody s případným předáním návratové hodnoty volající metodě (caller). Po provedení těchto instrukcí dojde ke zrušení celého zásobníkového rámce metody, z níž se vyskakuje, a řízení se předá volající metodě. Připomeňme si, že volající metoda si může návratovou hodnotu vyzvednout z vrcholu svého zásobníku operandů. Použití dále vypsaných instrukcí typu *return je jedinou možností, jak může volaná metoda modifikovat obsah zásobníku operandů metody volající – v ostatních případech jsou totiž zásobníky operandů (i datová oblast) obou metod od sebe izolovány, což přispívá jak k větší bezpečnosti, tak i k oddělení jednotlivých částí kódu. To samozřejmě zjednodušuje práci just-in-time překladače při provádění optimalizací. Ukončení metody s uložením návratové hodnoty zabezpečuje šestice instrukcí *return, která je vypsaná v následující tabulce:
# | Instrukce | Opkód | Datový typ na TOS | Operace |
---|---|---|---|---|
1 | ireturn | 0×AC | int | získání návratové hodnoty typu int z TOS zásobníku operandů + návrat z metody |
2 | lreturn | 0×AD | long | získání návratové hodnoty typu long z TOS zásobníku operandů + návrat z metody |
3 | freturn | 0×AE | float | získání návratové hodnoty typu float z TOS zásobníku operandů + návrat z metody |
4 | dreturn | 0×AF | double | získání návratové hodnoty typu double z TOS zásobníku operandů + návrat z metody |
5 | areturn | 0×B0 | reference | získání návratové hodnoty typu reference na objekt z TOS zásobníku operandů + návrat z metody |
6 | return | 0×B1 | × | pouze návrat z metody, žádná hodnota se nevrací |
Zajímavé je „přetížení“ instrukce ireturn i pro datové typy boolean, char, byte a short, což je ostatně patrné i z následujícího kódu:
Compiled from "Test12.java" public class Test12 extends java.lang.Object{ static void returnVoid(); Code: 0: return // instrukce pro návrat z metody bez vrácení hodnoty static boolean returnBooleanTrue(); Code: 0: iconst_1 // uložení konstanty 1 (int) na zásobník operandů 1: ireturn // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku static boolean returnBooleanFalse(); Code: 0: iconst_0 // uložení konstanty 0 (int) na zásobník operandů 1: ireturn // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku static byte returnByte(); Code: 0: iconst_m1 // uložení konstanty -1 (int) na zásobník operandů 1: ireturn // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku static char returnChar(); Code: 0: bipush 97 // uložení konstanty 97 (int) na zásobník operandů 2: ireturn // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku static short returnShort(); Code: 0: iconst_0 // uložení konstanty 0 (int) na zásobník operandů 1: ireturn // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku static int returnInt(); Code: 0: iconst_1 // uložení konstanty 1 (int) na zásobník operandů 1: ireturn // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku static long returnLong(); Code: 0: ldc2_w #2; // konstanta typu long umístěná v constant poolu 3: lreturn // instrukce pro návrat z metody s vrácením hodnoty typu long z vrcholu zásobníku static float returnFloat(); Code: 0: ldc #4; // konstanta typu float umístěná v constant poolu 2: freturn // instrukce pro návrat z metody s vrácením hodnoty typu float z vrcholu zásobníku static double returnDouble(); Code: 0: ldc2_w #5; // konstanta typu double umístěná v constant poolu 3: dreturn // instrukce pro návrat z metody s vrácením hodnoty typu double z vrcholu zásobníku static java.lang.Object returnReference(); Code: 0: aconst_null // speciální instrukce pro uložení "null" na vrchol zásobníku 1: areturn // instrukce pro návrat z metody s vrácením hodnoty typu reference z vrcholu zásobníku
Bajtkód demonstračního příkladu Test12.lua
V bajtkódu programovacího jazyka Lua je situace jednodušší, neboť se zde pro návrat z funkce používá jediná instrukce RETURN kompatibilní se všemi datovými typy. Nejprve je nutné načíst hodnotu příslušného typu do registru a posléze zavolat instrukci RETURN, které se předá mj. i počet registrů, jejichž hodnota se má předat volající funkci:
function <Test12.lua:11,13> (2 instructions at 0x9e8fc88) 0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions 1 [12] RETURN 0 1 // explicitní vrácení "ničeho" :-) 2 [13] RETURN 0 1 // vkládáno automaticky function <Test12.lua:18,20> (3 instructions at 0x9e8fe38) 0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions 1 [19] LOADNIL 0 0 // pro hodnotu nil existuje specializovaná instrukce 2 [19] RETURN 0 2 3 [20] RETURN 0 1 // vkládáno automaticky function <Test12.lua:25,27> (3 instructions at 0x9e8ff68) 0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions 1 [26] LOADBOOL 0 1 0 // hodnota false 2 [26] RETURN 0 2 3 [27] RETURN 0 1 // vkládáno automaticky function <Test12.lua:32,34> (3 instructions at 0x9e8fde0) 0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions 1 [33] LOADBOOL 0 0 0 // hodnota true 2 [33] RETURN 0 2 3 [34] RETURN 0 1 // vkládáno automaticky function <Test12.lua:39,41> (3 instructions at 0x9e90280) 0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions 1 [40] LOADK 0 -1 // číselná konstanta 42 2 [40] RETURN 0 2 3 [41] RETURN 0 1 // vkládáno automaticky function <Test12.lua:46,48> (3 instructions at 0x9e90428) 0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions 1 [47] LOADK 0 -1 // číselná konstanta 42 2 [47] RETURN 0 2 3 [48] RETURN 0 1 // vkládáno automaticky function <Test12.lua:53,55> (3 instructions at 0x9e90480) 0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions 1 [54] LOADK 0 -1 // řetězcová konstanta 2 [54] RETURN 0 2 3 [55] RETURN 0 1 // vkládáno automaticky function <Test12.lua:60,62> (7 instructions at 0x9e90000) 0 params, 4 slots, 0 upvalues, 0 locals, 3 constants, 0 functions 1 [61] NEWTABLE 0 3 0 // konstruktor tabulky 2 [61] LOADK 1 -1 ; 1 3 [61] LOADK 2 -2 ; 2 4 [61] LOADK 3 -3 ; 3 5 [61] SETLIST 0 3 1 // přidání prvků do tabulky 6 [61] RETURN 0 2 // vrácení tabulky 7 [62] RETURN 0 1 // vkládáno automaticky function <Test12.lua:67,69> (3 instructions at 0x9e906e8) 0 params, 2 slots, 1 upvalue, 0 locals, 0 constants, 1 function 1 [68] CLOSURE 0 0 // vrácení uzávěru 2 [68] RETURN 0 2 3 [69] RETURN 0 1 // vkládáno automaticky function <Test12.lua:68,68> (4 instructions at 0x9e90740) 0 params, 2 slots, 1 upvalue, 0 locals, 2 constants, 0 functions 1 [68] GETTABUP 0 0 -1 // tělo uzávěru 2 [68] LOADK 1 -2 ; "Hello world!" 3 [68] CALL 0 2 1 4 [68] RETURN 0 // vkládáno automaticky
Bajtkód demonstračního příkladu Test12.py
Bajtkód Python VM taktéž používá univerzální instrukci RETURN_VALUE, nezávisle na datovém typu vrácené hodnoty:
returnVoid: 12 0 LOAD_CONST 0 (None) 3 RETURN_VALUE returnNone: 18 0 LOAD_CONST 0 (None) 3 RETURN_VALUE returnBooleanTrue: 24 0 LOAD_GLOBAL 0 (True) 3 RETURN_VALUE returnBooleanFalse: 30 0 LOAD_GLOBAL 0 (False) 3 RETURN_VALUE returnNumber1: 36 0 LOAD_CONST 1 (42) 3 RETURN_VALUE returnNumber2: 42 0 LOAD_CONST 1 (42.0) 3 RETURN_VALUE returnString: 48 0 LOAD_CONST 1 ('Hello') 3 RETURN_VALUE returnTuple: 54 0 LOAD_CONST 4 ((1, 2, 3)) // n-tice reprezentovaná konstantou 3 RETURN_VALUE returnLambda: 60 0 LOAD_CONST 1 (code object lambda at 0xb773f968, file "Test12.py", line 60) 3 MAKE_FUNCTION 0 // z kodu se vytvorila skutecna funkce 6 RETURN_VALUE
5. Počítaná programová smyčka for
Nyní se budeme zabývat způsobem překladu počítané programové smyčky typu for o jejíž historii vzniku jsme se zmínili ve druhé kapitole. Rozdíly mezi jednotlivými programovacími jazyky budou napsány v navazujících podkapitolách:
Demonstrační příklad Test13.java
V programovacím jazyku Java je počítaná smyčka for realizována způsobem převzatým z programovacího jazyka C, tj. lze zadat jak inicializační výraz (výrazy), tak i podmínku ukončení smyčky a iterační příkaz:
/** * Jednoducha pocitana smycka typu for. */ public class Test13 { /** * Metoda s jednoduchou pocitanou smyckou typu for. */ static int testForLoop() { int result = 0; for (int i = 0; i <= 10; i++) { result++; } return result; } /** * Vse je nutne otestovat. */ public static void main(String[] args) { System.out.println(testForLoop()); } }
Demonstrační příklad Test13.lua
Programovací jazyk Lua se v případě počítané smyčky nechal inspirovat takovými jazyky, jako je Algol, Pascal, Modula či BASIC. Zadává se počáteční a koncová hodnota počitadla, nepovinně i přírůstek (který může být záporný, výchozí hodnota je samozřejmě 1):
-- -- Jednoducha pocitana smycka typu "for". -- -- -- Funkce s jednoduchou pocitanou smyckou typu for. -- function testForLoop() local result = 0 for i = 0, 10 do result = result + 1 end return result; end -- -- Vse je nutne otestovat. -- function main() print(testForLoop()) end main()
Demonstrační příklad Test13.py
Programovací jazyk Python sice počítanou smyčku for přímo nepodporuje, ale ve skutečnosti to ani není zapotřebí, neboť ji lze nahradit smyčkou typu for-each, které se předá nějaký objekt typu sekvence, typicky vytvořený přes xrange() (v Pythonu 3 pak range):
-- -- Jednoducha pocitana smycka typu for. -- -- -- Funkce s jednoduchou pocitanou smyckou typu for. -- def testForLoop(): result = 0; for i in xrange(0,11): result = result + 1 return result -- -- Vse je nutne otestovat. -- def main(): print(testForLoop()) -- -- Vypsani bajkkodu testovane funkce -- def disassemble(): from dis import dis print("\ntestForLoop:") dis(testForLoop) main() disassemble()
6. Ukázky překladu jednoduché počítané smyčky typu for do bajtkódu
Nyní se podívejme na to, jakým způsobem se jednotlivé implementace počítané smyčky typu for přeložily do bajtkódu.
Bajtkód demonstračního příkladu Test13.java
U JVM je překlad proveden způsobem, s nímž jsme se již setkali minule při popisu smyček typu while, tj. s využitím nízkoúrovňových podmíněných i nepodmíněných skoků:
Compiled from "Test13.java" public class Test13 extends java.lang.Object{ static int testForLoop(); Code: 0: iconst_0 // počáteční hodnota proměnné result 1: istore_0 2: iconst_0 // počáteční hodnota počitadla 3: istore_1 4: iload_1 // začátek smyčky 5: bipush 10 // hodnota horní meze 7: if_icmpgt 19 // při překročení horní meze skok ZA konec smyčky 10: iinc 0, 1 // zvýšit hodnotu proměnné result 13: iinc 1, 1 // zvýšit hodnotu počitadla 16: goto 4 // nepodmíněný skok na začátek smyčky 19: iload_0 20: ireturn // vrátit hodnotu proměnné result
Bajtkód demonstračního příkladu Test13.lua
Pravděpodobně nejzajímavější je bajtkód Lua VM, v němž jsou použity dvě specializované instrukce nazvané FORPREP a FORLOOP. První z těchto instrukcí nejprve sníží hodnotu počitadla o krok, takže se například namísto počáteční hodnoty 0 bude v počitadle nacházet hodnota –1. Současně se po provedení této instrukce přesune řízení na instrukci FORLOOP (to není žádná magie, protože relativní adresa skoku je součástí instrukčního slova FORPREP). Celá smyčka je pak realizována instrukcí FORLOOP, která zvýší hodnotu počitadla o krok, provede porovnání aktuální hodnoty počitadla s horní mezí a popř. provede skok na začátek smyčky, tedy za instrukci nacházející se těsně za FORPREP. Výsledkem je velmi elegantní bajtkód:
function <Test13.lua:10,16> (9 instructions at 0x9f49c88) 0 params, 5 slots, 0 upvalues, 5 locals, 3 constants, 0 functions 1 [11] LOADK 0 -1 ; 0 // počáteční hodnota proměnné result 2 [12] LOADK 1 -1 ; 0 // počáteční hodnota počitadla 3 [12] LOADK 2 -2 ; 10 // hodnota horní meze 4 [12] LOADK 3 -3 ; 1 // krok smyčky 5 [12] FORPREP 1 1 ; to 7 // příprava na smyčku snížení hodnoty počitadla o krok // a skok na iterační příkaz 6 [13] ADD 0 0 -3 ; - 1 // zvýšit hodnotu proměnné result 7 [12] FORLOOP 1 -2 ; to 6 // provedení iterace - zvýšení hodnoty počitadla // test a případný skok na instrukci číslo 6 8 [15] RETURN 0 2 // vrátit hodnotu proměnné result 9 [16] RETURN 0 1 // automaticky generovaný návrat z funkce
Bajtkód demonstračního příkladu Test13.py
U bajtkódu programovacího jazyka Python jsou taktéž použity specializované instrukce bajtkódu nazvané GET_ITER a FOR_ITER. Ty jsou použity ve všech typech smyčky for-each, zde konkrétně pro práci s objektem vytvořeným funkcí/konstruktorem xrange:
testForLoop: 9 0 LOAD_CONST 1 (0) // počáteční hodnota proměnné result 3 STORE_FAST 0 (result) 10 6 SETUP_LOOP 33 (to 42) // konstrukce programové smyčky 9 LOAD_GLOBAL 0 (xrange) // příprava na volání xrange() 12 LOAD_CONST 1 (0) // dolní mez 15 LOAD_CONST 2 (11) // horní mez 18 CALL_FUNCTION 2 // zavolání xrange() 21 GET_ITER 22 FOR_ITER 16 (to 41) // vlastní smyčka 25 STORE_FAST 1 (i) 11 28 LOAD_FAST 0 (result) // * 31 LOAD_CONST 3 (1) // * result = result + 1 34 BINARY_ADD // * 35 STORE_FAST 0 (result) // * 38 JUMP_ABSOLUTE 22 // další iterace (skok na začátek smyčky) 41 POP_BLOCK // úklid po ukončení smyčky 12 42 LOAD_FAST 0 (result) 45 RETURN_VALUE // vrátit hodnotu proměnné result
7. Složitější programová smyčka typu for – výpočet faktoriálu
Počítaná smyčka for použitá v předchozích demonstračních příkladech vlastně představovala nejjednodušší formu této řídicí struktury. Nyní se podíváme na praktičtější příklad – výpočet faktoriálu. Zde je již nutné, aby se uvnitř smyčky využívala aktuální hodnota počitadla.
Demonstrační příklad Test14.java
Implementace výpočtu faktoriálu s využitím iterační smyčky je v Javě přímočará:
/** * Jednoducha pocitana smycka typu "for" * pouzita pro vypocet faktorialu. */ public class Test14 { /** * Vypocet faktorialu pocitanou smyckou * typu "for". */ static int factorial(int n) { int result = 1; for (int i = 2; i <= n; i++) { result *= i; } return result; } /** * Vse je nutne otestovat. */ public static void main(String[] args) { for (int n = 0; n <= 10; n++) { System.out.println(n + "\t" + factorial(n)); } } }
Demonstrační příklad Test14.lua
Totéž platí i pro programovací jazyk Lua:
-- -- Jednoducha pocitana smycka typu "for" -- pouzita pro vypocet faktorialu. -- -- -- Vypocet faktorialu pocitanou smyckou -- typu "for". -- function factorial(n) local result = 1 for i = 2, n do result = result * i end return result; end -- -- Vse je nutne otestovat. -- function main() for n = 0, 10 do print(n .. "\t" .. factorial(n)) end end main()
Demonstrační příklad Test14.py
Ani v případě programovacího jazyka Python není zapotřebí používat žádné složitější jazykové konstrukce:
-- -- Jednoducha pocitana smycka typu for -- pouzita pro vypocet faktorialu. -- -- -- Vypocet faktorialu pocitanou smyckou -- typu "for". -- def factorial(n): result = 1; for i in xrange(2, n+1): result = result * i return result -- -- Vse je nutne otestovat. -- def main(): for n in xrange(0, 11): print "%d\t%d" % (n, factorial(n)) -- -- Vypsani bajkkodu testovane funkce -- def disassemble(): from dis import dis print("\nfactorial:") dis(factorial) main() disassemble()
V dalším textu budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test14.java, Test14.lua i Test14.py.
Bajtkód demonstračního příkladu Test14.java
U JVM se výpočet faktoriálu provádí v bajtkódu opět s využitím nízkoúrovňových podmíněných i nepodmíněných skoků:
Compiled from "Test14.java" public class Test14 extends java.lang.Object{ static int factorial(int); Code: 0: iconst_1 // počáteční hodnota proměnné result 1: istore_1 2: iconst_2 // počáteční hodnota počitadla 3: istore_2 4: iload_2 // začátek smyčky 5: iload_0 // hodnota horní meze je předána v parametru 6: if_icmpgt 19 // při překročení horní meze skok ZA konec smyčky 9: iload_1 10: iload_2 11: imul // vynásobit hodnotu proměnné result aktuální hodnotou počitadla 12: istore_1 13: iinc 2, 1 // zvýšit hodnotu počitadla 16: goto 4 // nepodmíněný skok na začátek smyčky 19: iload_1 20: ireturn // vrátit hodnotu proměnné result
Bajtkód demonstračního příkladu Test14.lua
U programovacího jazyka Lua nalezneme v bajtkódu podle očekávání instrukce FORPREP i FORLOOP:
function <Test14.lua:12,18> (9 instructions at 0x869ec88) 1 param, 6 slots, 0 upvalues, 6 locals, 2 constants, 0 functions 1 [13] LOADK 1 -1 ; 1 // počáteční hodnota proměnné result 2 [14] LOADK 2 -2 ; 2 // počáteční hodnota počitadla 3 [14] MOVE 3 0 // přesun parametru (horní mez) do registru 3 4 [14] LOADK 4 -1 ; 1 // krok smyčky 5 [14] FORPREP 2 1 ; to 7 // příprava na smyčku snížení hodnoty počitadla o krok // a skok na iterační příkaz 6 [15] MUL 1 1 5 // tělo smyčky zkrácené na jedinou instrukci 7 [14] FORLOOP 2 -2 ; to 6 // provedení iterace - zvýšení hodnoty počitadla // test a případný skok na instrukci číslo 6 8 [17] RETURN 1 2 // vrátit hodnotu proměnné result 9 [18] RETURN 0 1 // automaticky generovaný návrat z funkce
Bajtkód demonstračního příkladu Test14.py
V případě bajtkódu Pythonu se pro konstrukci smyčky používají speciální instrukce GET_ITER a FOR_ITER:
factorial: 11 0 LOAD_CONST 1 (1) // počáteční hodnota proměnné result 3 STORE_FAST 1 (result) 12 6 SETUP_LOOP 37 (to 46) // konstrukce programové smyčky 9 LOAD_GLOBAL 0 (xrange) // příprava na volání xrange() 12 LOAD_CONST 2 (2) // dolní mez 15 LOAD_FAST 0 (n) // horní mez 18 LOAD_CONST 1 (1) // (n+1) 21 BINARY_ADD 22 CALL_FUNCTION 2 // zavolání xrange() 25 GET_ITER 26 FOR_ITER 16 (to 45) // vlastní smyčka 29 STORE_FAST 2 (i) 13 32 LOAD_FAST 1 (result) // * 35 LOAD_FAST 2 (i) // * result = result * n 38 BINARY_MULTIPLY // * 39 STORE_FAST 1 (result) // * 42 JUMP_ABSOLUTE 26 // další iterace (skok na začátek smyčky) 45 POP_BLOCK // úklid po ukončení smyčky 14 46 LOAD_FAST 1 (result) 49 RETURN_VALUE // vrátit hodnotu proměnné result
8. Překlad vnořených počítaných smyček typu for do bajtkódu
Dalším typickým příkladem z praxe je použití dvou vnořených počítaných smyček typu for. V dnešním třetím demonstračním příkladu se bude jednat o velmi jednoduchý (a v případě výpisu výsledků i naivní) algoritmus pro tisk malé násobilky.
Demonstrační příklad Test15.java
V případě Javy je tento algoritmus přímočarý (pro jednoduchost ignorujme znak [TAB] na konci každého řádku):
/** * Vnorene smycky typu "for". */ public class Test15 { /** * Staticka metoda s dvojici vnorenych * programovych smycek typu "for". */ static void testNestedForLoops() { for (int j = 1; j <= 10; j++) { for (int i = 1; i <= 10; i++) { System.out.print(i * j); System.out.print('\t'); } System.out.println(); } } /** * Vse je nutne otestovat. */ public static void main(String[] args) { testNestedForLoops(); } }
Demonstrační příklad Test15.lua
V programovacím jazyku Lua je nutné pro tisk bez odřádkování použít funkci io.write() namísto print():
-- -- Vnorene smycky typu "for". -- -- -- Funkce s dvojici vnorenych -- programovych smycek typu "for". -- function testNestedForLoops() for j = 1,10 do for i = 1,10 do io.write(i * j) io.write('\t') end print() end end -- -- Vse je nutne otestovat. -- function main() testNestedForLoops(); end main()
Demonstrační příklad Test15.py
Podobně je tomu v programovacím jazyku Python, kde se namísto příkazu/funkce print() musí použít například sys.stdout.write():
-- -- Vnorene smycky typu "for". -- import sys -- -- Funkce s dvojici vnorenych -- programovych smycek typu "for". -- def testNestedForLoops(): for j in xrange(1,11): for i in xrange(1,11): sys.stdout.write(str(i * j)) sys.stdout.write("\t") print("") -- -- Vse je nutne otestovat. -- def main(): testNestedForLoops(); -- -- Vypsani bajkkodu testovane funkce -- def disassemble(): from dis import dis print("\ntestNestedForLoops:") dis(testNestedForLoops) main() disassemble()
V dalším textu budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test15.java, Test15.lua i Test15.py.
Bajtkód demonstračního příkladu Test15.java
V bajtkódu JVM je jasně viditelná struktura obou programových smyček:
Compiled from "Test15.java" public class Test15 extends java.lang.Object{ public Test15(); static void testNestedForLoops(); Code: 0: iconst_1 1: istore_0 2: iload_0 // začátek vnější smyčky 3: bipush 10 // hodnota horní meze vnější smyčky 5: if_icmpgt 51 // při překročení horní meze skok ZA konec smyčky 8: iconst_1 9: istore_1 10: iload_1 // začátek vnitřní smyčky 11: bipush 10 // hodnota horní meze vnitřní smyčky 13: if_icmpgt 39 // při překročení horní meze skok ZA konec smyčky 16: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 19: iload_1 20: iload_0 21: imul 22: invokevirtual #3; // Method java/io/PrintStream.print:(I)V 25: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 28: bipush 9 30: invokevirtual #4; // Method java/io/PrintStream.print:(C)V 33: iinc 1, 1 // zvýšit hodnotu počitadla vnitřní smyčky 36: goto 10 // nepodmíněný skok na začátek vnitřní smyčky 39: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 42: invokevirtual #5; // Method java/io/PrintStream.println:()V 45: iinc 0, 1 // zvýšit hodnotu počitadla vnější smyčky 48: goto 2 // nepodmíněný skok na začátek vnější smyčky 51: return // návrat z metody
Bajtkód demonstračního příkladu Test15.lua
I v případě bajtkódu Lua VM získáme přehledně strukturovaný bajtkód:
function <Test15.lua:11,19> (21 instructions at 0x9356cb0) 0 params, 10 slots, 1 upvalue, 8 locals, 6 constants, 0 functions 1 [12] LOADK 0 -1 ; 1 // počáteční hodnota počitadla 2 [12] LOADK 1 -2 ; 10 // horní mez vnější smyčky 3 [12] LOADK 2 -1 ; 1 // krok vnější smyčky 4 [12] FORPREP 0 15 ; to 20 // přípravný krok pro vnější smyčku 5 [13] LOADK 4 -1 ; 1 // počáteční hodnota počitadla 6 [13] LOADK 5 -2 ; 10 // horní mez vnitřní smyčky 7 [13] LOADK 6 -1 ; 1 // krok vnitřní smyčky 8 [13] FORPREP 4 8 ; to 17 // přípravný krok pro vnitřní smyčku 9 [14] GETTABUP 8 0 -3 ; _ENV "io" 10 [14] GETTABLE 8 8 -4 ; "write" 11 [14] MUL 9 7 3 12 [14] CALL 8 2 1 // zavolání funkce io.write() 13 [15] GETTABUP 8 0 -3 ; _ENV "io" 14 [15] GETTABLE 8 8 -4 ; "write" 15 [15] LOADK 9 -5 ; "\t" 16 [15] CALL 8 2 1 // zavolání funkce io.write() 17 [13] FORLOOP 4 -9 ; to 9 // vnitřní smyčka – začátek další iterace 18 [17] GETTABUP 4 0 -6 ; _ENV "print" 19 [17] CALL 4 1 1 // zavolání funkce print() 20 [12] FORLOOP 0 -16 ; to 5 // vnější smyčka – začátek další iterace 21 [19] RETURN 0 1 // automaticky generovaný návrat z funkce
Bajtkód demonstračního příkladu Test14.py
Nyní se podívejme na bajtkód vygenerovaný pro Python VM:
testNestedForLoops: 12 0 SETUP_LOOP 96 (to 99) // konstrukce vnější programové smyčky 3 LOAD_GLOBAL 0 (xrange) 6 LOAD_CONST 1 (1) // dolní mez 9 LOAD_CONST 2 (11) // horní mez 12 CALL_FUNCTION 2 // zavolání xrange() 15 GET_ITER 16 FOR_ITER 79 (to 98) // vlastní vnější smyčka 19 STORE_FAST 0 (j) 13 22 SETUP_LOOP 65 (to 90) // konstrukce vnitřní programové smyčky 25 LOAD_GLOBAL 0 (xrange) 28 LOAD_CONST 1 (1) // dolní mez 31 LOAD_CONST 2 (11) // horní mez 34 CALL_FUNCTION 2 // zavolání xrange() 37 GET_ITER 38 FOR_ITER 48 (to 89) // vlastní vnitřní smyčka 41 STORE_FAST 1 (i) 14 44 LOAD_GLOBAL 1 (sys) 47 LOAD_ATTR 2 (stdout) 50 LOAD_ATTR 3 (write) 53 LOAD_GLOBAL 4 (str) 56 LOAD_FAST 1 (i) 59 LOAD_FAST 0 (j) 62 BINARY_MULTIPLY 63 CALL_FUNCTION 1 // zavolání str() 66 CALL_FUNCTION 1 // zavolání sys.stdout.write() 69 POP_TOP 15 70 LOAD_GLOBAL 1 (sys) 73 LOAD_ATTR 2 (stdout) 76 LOAD_ATTR 3 (write) 79 LOAD_CONST 3 ('\t') 82 CALL_FUNCTION 1 // zavolání sys.stdout.write() 85 POP_TOP 86 JUMP_ABSOLUTE 38 // další iterace (skok na začátek vnitřní smyčky) 89 POP_BLOCK // úklid po ukončení smyčky 16 90 LOAD_CONST 4 ('') 93 PRINT_ITEM 94 PRINT_NEWLINE // zavolání print() 95 JUMP_ABSOLUTE 16 // další iterace (skok na začátek vnější smyčky) 98 POP_BLOCK // úklid po ukončení smyčky 99 LOAD_CONST 0 (None) 102 RETURN_VALUE // návrat se speciální hodnotou None
9. Příkazy break a continue, popř. jejich ekvivalenty
S programovými smyčkami všech typů (počítané i nepočítané) poměrně úzce souvisí i příkazy break a continue sloužící buď k ukončení běhu smyčky popř. k přeskočení zbytku těla smyčky a zahájení nové iterace. Oba zmíněné příkazy jsou podporovány v Javě a Pythonu, ovšem v případě programovacího jazyka Lua je nutné příkaz continue nahradit programovou logikou, v současné verzi jazyka velmi pravděpodobně příkazem goto.
Demonstrační příklad Test16.java
Následující demonstrační příklad pouze ukazuje možnosti příkazů break a continue, protože implementovaný algoritmus ve skutečnosti nemá žádný větší význam:
/** * Vnorene smycky typu "for" * spolecne s prikazy "break" a "continue". */ public class Test16 { /** * Staticka metoda s dvojici vnorenych * programovych smycek typu "for". */ static void testNestedForLoops() { for (int y = 0; y < 10; y++) { if (y < 5) continue; for (int x = 0; x < 10; x++) { if (x == 5) break; } } } }
Demonstrační příklad Test16.lua
Implementace téhož algoritmu v programovacím jazyku Lua vyžaduje použití příkazu goto na návěští umístěné na konci těla smyčky. Návěští se podle upravené syntaxe zapisuje se „čtyřtečkou“ na začátku i na konci jeho jména:
-- -- Vnorene smycky typu "for" -- spolecne s prikazy "break" a "continue". -- -- -- Funlkce s dvojici vnorenych -- programovych smycek typu "for". --/ function testNestedForLoops() for y = 0, 9 do if y < 5 then goto continue end for x = 0, 9 do if x == 5 then break end end ::continue:: end end
Demonstrační příklad Test16.py
Implementace původního algoritmu v Pythonu je prakticky stejná jako tomu bylo v Javě, pokud tedy odhlédneme od použití funkce xrange() a poněkud odlišné (elegantnější :-) syntaxe:
-- -- Vnorene smycky typu "for" -- spolecne s prikazy "break" a "continue". -- -- -- Funkce s dvojici vnorenych -- programovych smycek typu "for". -- def testNestedForLoops(): for y in xrange(1,11): if y ==5: continue for x in xrange(1,11): if x == 5: break -- -- Vypsani bajkkodu testovane funkce -- def disassemble(): from dis import dis print("\ntestNestedForLoops:") dis(testNestedForLoops) disassemble()
10. Překlad příkazů typu break a continue do bajtkódu
V této kapitole budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test16.java, Test16.lua i Test16.py.
Bajtkód demonstračního příkladu Test16.java
V bajtkódu vytvořeného pro JVM můžeme vidět použití nepodmíněných i podmíněných skoků; takto generovaný bajtkód do značné míry připomíná strojový kód mnoha typů mikroprocesorů:
static void testNestedForLoops(); Code: 0: iconst_0 // inicializace počitadla vnější smyčky 1: istore_0 // jedná se o první lokální proměnnou (s viditelností jen uvnitř smyčky) 2: iload_0 // podmínka ukončení vnější smyčky 3: bipush 10 // konstanta představující hodnotu počitadla, při jejímž dosažení se smyčka ukončí 5: if_icmpge 44 // počitadlo dosáhlo mezní hodnoty - skok ZA konec vnější smyčky 8: iload_0 // implementace podmínky "if (y < 5) continue;" 9: iconst_5 // konstanta, s níž je hodnota počitadla srovnávána 10: if_icmpge 16 13: goto 38 // skok ZA konec vnitřní smyčky 16: iconst_0 // inicializace počitadla vnitřní smyčky 17: istore_1 // jedná se o druhou lokální proměnnou (s viditelností jen uvnitř smyčky) 18: iload_1 // podmínka ukončení vnitřní smyčky 19: bipush 10 // konstanta představující hodnotu počitadla, při jejímž dosažení se smyčka ukončí 21: if_icmpge 38 // počitadlo dosáhlo mezní hodnoty - skok ZA konec vnitřní smyčky 24: iload_1 // implementace podmínky "if (x == 5) break;" 25: iconst_5 // konstanta, s níž je hodnota počitadla srovnávána 26: if_icmpne 32 29: goto 38 // skok ZA konec vnitřní smyčky 32: iinc 1, 1 // zvýšení počitadla vnitřní smyčky 35: goto 18 // další iterace vnitřní smyčky 38: iinc 0, 1 // zvýšení počitadla vnější smyčky 41: goto 2 // další iterace vnější smyčky 44: return
Bajtkód demonstračního příkladu Test16.lua
V případě programovacího jazyka Lua je do sekvence instrukcí s dvojicí do sebe vnořených programových smyček vložena i dvojice skoků; první pro implementaci continue, druhý pro implementaci break:
function <Test16.lua:10,22> (15 instructions at 0x8862cb0) 0 params, 8 slots, 0 upvalues, 8 locals, 4 constants, 0 functions 1 [11] LOADK 0 -1 ; 0 // počáteční hodnota počitadla 2 [11] LOADK 1 -2 ; 9 // horní mez vnější smyčky 3 [11] LOADK 2 -3 ; 1 // krok vnější smyčky 4 [11] FORPREP 0 9 ; to 14 // přípravný krok pro vnější smyčku 5 [12] LT 1 3 -4 ; - 5 6 [12] JMP 0 7 ; to 14 // implementace "continue" 7 [15] LOADK 4 -1 ; 0 // počáteční hodnota počitadla 8 [15] LOADK 5 -2 ; 9 // horní mez vnitřní smyčky 9 [15] LOADK 6 -3 ; 1 // krok vnitřní smyčky 10 [15] FORPREP 4 2 ; to 13 // přípravný krok pro vnitřní smyčku 11 [16] EQ 1 7 -4 ; - 5 12 [16] JMP 0 1 ; to 14 // implementace "break" 13 [15] FORLOOP 4 -3 ; to 11 // vnitřní smyčka – začátek další iterace 14 [11] FORLOOP 0 -10 ; to 5 // vnější smyčka – začátek další iterace 15 [22] RETURN 0 1 // automaticky generovaný návrat z funkce
Bajtkód demonstračního příkladu Test16.py
Podobně je tomu i v případě bajtkódu vytvořeného pro Python VM:
testNestedForLoops: 11 0 SETUP_LOOP 87 (to 90) // konstrukce vnější programové smyčky 3 LOAD_GLOBAL 0 (xrange) 6 LOAD_CONST 1 (1) // dolní mez 9 LOAD_CONST 2 (11) // horní mez 12 CALL_FUNCTION 2 // zavolání xrange() 15 GET_ITER 16 FOR_ITER 70 (to 89) // vlastní vnější smyčka 19 STORE_FAST 0 (y) 12 22 LOAD_FAST 0 (y) 25 LOAD_CONST 3 (5) 28 COMPARE_OP 2 (==) 31 JUMP_IF_FALSE 7 (to 41) // implementace "continue" 34 POP_TOP 13 35 JUMP_ABSOLUTE 16 38 JUMP_FORWARD 1 (to 42) 41 POP_TOP 14 42 SETUP_LOOP 41 (to 86) // konstrukce vnitřní programové smyčky 45 LOAD_GLOBAL 0 (xrange) 48 LOAD_CONST 1 (1) // dolní mez 51 LOAD_CONST 2 (11) // horní mez 54 CALL_FUNCTION 2 // zavolání xrange() 57 GET_ITER 58 FOR_ITER 24 (to 85) // vlastní vnitřní smyčka 61 STORE_FAST 1 (x) 15 64 LOAD_FAST 1 (x) 67 LOAD_CONST 3 (5) 70 COMPARE_OP 2 (==) 73 JUMP_IF_FALSE 5 (to 81) // implementace "break" 76 POP_TOP 16 77 BREAK_LOOP 78 JUMP_ABSOLUTE 58 81 POP_TOP 82 JUMP_ABSOLUTE 58 85 POP_BLOCK // úklid po ukončení smyčky 86 JUMP_ABSOLUTE 16 89 POP_BLOCK // úklid po ukončení smyčky 90 LOAD_CONST 0 (None) 93 RETURN_VALUE // návrat se speciální hodnotou None
11. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů
Všechny dnes popsané a využité demonstrační příklady (naprogramované v Javě, Lue i Pythonu) byly uloženy do Mercurial repositáře umístěného na adrese http://icedtea.classpath.org/people/ptisnovs/jvm-tools/. Odkazy na prozatím poslední verze těchto příkladů naleznete v tabulce pod tímto odstavcem:
12. Odkazy na Internetu
- Programming in Lua (first edition)
http://www.lua.org/pil/contents.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 - Lua: Control Structure Tutorial
http://lua-users.org/wiki/ControlStructureTutorial - Lua Types Tutorial
http://lua-users.org/wiki/LuaTypesTutorial - Programovací jazyk Lua
http://palmknihy.cz/web/kniha/programovaci-jazyk-lua-12651.htm - Goto Statement in Lua
http://lua-users.org/wiki/GotoStatement - Python break, continue and pass Statements
http://www.tutorialspoint.com/python/python_loop_control.htm - 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 - 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 - 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 - 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/ - O-code
http://en.wikipedia.org/wiki/O-code_machine - BCPL
http://en.wikipedia.org/wiki/BCPL - The BCPL Cintcode System and Cintpos User Guide by Martin Richards
http://www.cl.cam.ac.uk/users/mr/bcplman.pdf - Bootstrapping the BCPL Compiler using INTCODE
http://www.gtoal.com/languages/bcpl/amiga/bcpl/booting.txt - p-code machine
http://en.wikipedia.org/wiki/P-code_machine - ucsd-psystem-vm 0.11 (a portable virtual machine for the UCSD p-System)
http://ucsd-psystem-vm.sourceforge.net/ - Introduction to Smalltalk bytecodes
http://marianopeck.wordpress.com/2011/05/21/introduction-to-smalltalk-bytecodes/ - Audio File Formats.
http://sox.sourceforge.net/AudioFormats-11.html - TestSounds.com: pure digital sounds to test your audio
http://www.testsounds.com/ - Test Tones (20hz – 20khz)
http://mdf1.tripod.com/test-tones.html - WAV (Wikipedia)
http://en.wikipedia.org/wiki/WAV - WAVE PCM soundfile format
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ - Audio Interchange File Format
http://en.wikipedia.org/wiki/Aiff - Musical Instrument Digital Interface,
http://en.wikipedia.org/wiki/Musical_Instrument_Digital_Interface - A MIDI Pedalboard Encode,
http://www.pykett.org.uk/a_midi_pedalboard_encoder.htm - MIDI Note Number, Frequency Table,
http://tonalsoft.com/pub/news/pitch-bend.aspx - Note names, MIDI numbers and frequencies,
http://www.phys.unsw.edu.au/jw/notes.html - The MIDI Specification,
http://www.gweep.net/~prefect/eng/reference/protocol/midispec.html - Essentials of the MIDI protocol,
http://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html - General MIDI,
http://en.wikipedia.org/wiki/General_MIDI - Obecné MIDI (General MIDI),
http://www-kiv.zcu.cz/~herout/html_sbo/midi/5.html - Custom Chips: Paula
http://www.amiga-hardware.com/showhardware.cgi?HARDID=1460 - Big Book of Amiga Hardware
http://www.amiga-resistance.info/bboahfaq/ - Amiga Hardware Database
http://amiga.resource.cx/ - ExoticA
http://www.exotica.org.uk/wiki/Main_Page - The absolute basics of Amiga audio
http://www.sufo.estates.co.uk/amiga/amimus.html - Wikipedia: Tracker
http://en.wikipedia.org/wiki/Tracker - Wikipedia: Trackers
http://en.wikipedia.org/wiki/Trackers - Ultimate Soundtracker
http://en.wikipedia.org/wiki/Ultimate_Soundtracker - Protracker
http://en.wikipedia.org/wiki/ProTracker - Impulse Tracker
http://en.wikipedia.org/wiki/Impulse_Tracker - Scream Tracker
http://en.wikipedia.org/wiki/ScreamTracker - MikMod for Java
http://jmikmod.berlios.de/ - List of audio trackers
http://en.wikipedia.org/wiki/List_of_audio_trackers - Wikipedia: Module File
http://en.wikipedia.org/wiki/Module_file - Wikipedia: Chiptune
http://en.wikipedia.org/wiki/Chiptune - SDL_mixer 2.0
http://www.libsdl.org/projects/SDL_mixer/ - SDLJava: package sdljava.ttf
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/package-summary.html#package_description - SDLJava: class sdljava.ttf.SDLTTF
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTTF.html - SDLJava: class sdljava.ttf.SDLTrueTypeFont
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTrueTypeFont.html - SDL_ttf Documentation
http://www.libsdl.org/projects/SDL_ttf/docs/ - SDL_ttf 2.0 (není prozatím součástí SDLJava)
http://www.libsdl.org/projects/SDL_ttf/ - SDL_ttf doc
http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf_frame.html - SDL 1.2 Documentation: SDL_Surface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html - SDL 1.2 Documentation: SDL_PixelFormat
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html - SDL 1.2 Documentation: SDL_LockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html - SDL 1.2 Documentation: SDL_UnlockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html - SDL 1.2 Documentation: SDL_LoadBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html - SDL 1.2 Documentation: SDL_SaveBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html - SDL 1.2 Documentation: SDL_BlitSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html - SDL 1.2 Documentation: SDL_VideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html - SDL 1.2 Documentation: SDL_GetVideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html - glDrawArrays
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArrays.xml - glDrawElements
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElements.xml - glDrawArraysInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArraysInstanced.xml - glDrawElementsInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElementsInstanced.xml - Root.cz: Seriál Grafická knihovna OpenGL
http://www.root.cz/serialy/graficka-knihovna-opengl/ - Root.cz: Seriál Tvorba přenositelných grafických aplikací využívajících knihovnu GLUT
http://www.root.cz/serialy/tvorba-prenositelnych-grafickych-aplikaci-vyuzivajicich-knihovnu-glut/ - Best Practices for Working with Vertex Data
https://developer.apple.com/library/ios/documentation/3ddrawing/conceptual/opengles_programmingguide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html - Class BufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferStrategy.html - Class Graphics
http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Graphics.html - Double Buffering and Page Flipping
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html - BufferStrategy and BufferCapabilities
http://docs.oracle.com/javase/tutorial/extra/fullscreen/bufferstrategy.html - Java:Tutorials:Double Buffering
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering - Double buffer in standard Java AWT
http://www.codeproject.com/Articles/2136/Double-buffer-in-standard-Java-AWT - Java 2D: Hardware Accelerating – Part 1 – Volatile Images
http://www.javalobby.org/forums/thread.jspa?threadID=16840&tstart=0 - Java 2D: Hardware Accelerating – Part 2 – Buffer Strategies
http://www.javalobby.org/java/forums/t16867.html - How does paintComponent work?
http://stackoverflow.com/questions/15544549/how-does-paintcomponent-work - A Swing Architecture Overview
http://www.oracle.com/technetwork/java/architecture-142923.html - Class javax.swing.JComponent
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html - Class java.awt.Component
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html - Class java.awt.Component.BltBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.BltBufferStrategy.html - Class java.awt.Component.FlipBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.FlipBufferStrategy.html - Metoda java.awt.Component.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html#isDoubleBuffered() - Metoda javax.swing.JComponent.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#isDoubleBuffered() - Metoda javax.swing.JComponent.setDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#setDoubleBuffered(boolean) - Javadoc – třída GraphicsDevice
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsDevice.html - Javadoc – třída GraphicsEnvironment
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsEnvironment.html - Javadoc – třída GraphicsConfiguration
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsConfiguration.html - Javadoc – třída DisplayMode
http://docs.oracle.com/javase/7/docs/api/java/awt/DisplayMode.html - Lesson: Full-Screen Exclusive Mode API
http://docs.oracle.com/javase/tutorial/extra/fullscreen/ - Full-Screen Exclusive Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html - Display Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/displaymode.html - Using the Full-Screen Exclusive Mode API in Java
http://www.developer.com/java/other/article.php/3609776/Using-the-Full-Screen-Exclusive-Mode-API-in-Java.htm - 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 - MultiMedia eXtensions
http://softpixel.com/~cwright/programming/simd/mmx.phpi - SSE (Streaming SIMD Extentions)
http://www.songho.ca/misc/sse/sse.html - Timothy A. Chagnon: SSE and SSE2
http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf - Intel corporation: Extending the Worldr's Most Popular Processor Architecture
http://download.intel.com/technology/architecture/new-instructions-paper.pdf - SIMD architectures:
http://arstechnica.com/old/content/2000/03/simd.ars/ - 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