Obsah
1. Pohled pod kapotu JVM – překlad programových smyček do bajtkódů JVM, Lua VM a Python VM
2. Jednoduchá programová smyčka typu while
3. Ukázky překladu jednoduché programové smyčky while do bajtkódu
4. Programová smyčka typu while se složitějším tělem
5. Ukázky překladu složitější programové smyčky while do bajtkódu
6. Dvě vnořené smyčky typu while – výpis řady prvočísel
7. Ukázky překladu vnořených smyček while do bajtkódu
8. Jednoduchá programová smyčka typu do-while/repeat-until
9. Ukázky překladu jednoduché programové smyčky do-while/repeat-until do bajtkódu
10. Dvě vnořené smyčky typu do-while – výpis řady prvočísel
11. Ukázky překladu vnořených smyček do-while do bajtkódu
12. Obsah následující části seriálu
13. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – překlad programových smyček do bajtkódů JVM, Lua VM a Python VM
V předchozích dvou částech seriálu o programovacím jazyku Java i o JVM jsme si stručně popsali některé základní vlastnosti bajtkódu JVM, Lua VM a Python VM. Prozatím známe základní informace o způsobu překladu aritmetických a logických výrazů – zde jsme si vysvětlili základní rozdíly mezi virtuálními stroji založenými na zásobníku (což je JVM a Python VM) a virtuálními stroji založenými na sadě registrů (mezi tyto virtuální stroje patří Lua VM a taktéž Parrot, tj. VM použitý mj. i v Perlu 6). Minule jsme si taktéž, ovšem bez bližších podrobností, ukázali, jakým způsobem se překládají jazykové konstrukce typu if-then popř. úplné rozvětvení typu if-then-else. Dnes se budeme zabývat způsobem překladu programových smyček do bajtkódů jednotlivých virtuálních strojů. Podobně jako tomu bylo u konstrukcí if-then a if-then-else, i u programových smyček jsou použity instrukce podmíněných a nepodmíněných skoků, popř. instrukce pro přeskočení dalšího instrukčního slova (což může sloužit jako náhrada podmíněného skoku).
Jako příklad typického virtuálního stroje nám dobře poslouží JVM. Tento virtuální stroj obsahuje jedinou instrukci nepodmíněného skoku, jejíž jméno je goto (nikoli jmp, což je možná obvyklejší). Podobně jako podmíněné skoky popsané v následujícím odstavci, má i instrukce goto několik podstatných omezení – skok lze totiž provést pouze v rámci těla jedné metody, není tedy možné skočit na libovolné místo v bajtkódu, což ostatně platí i pro všechny další VM. Toto omezení bylo zavedeno ze dvou důvodů – zajišťuje se tím větší bezpečnost a taktéž se tím zjednodušuje práce JIT překladače, který při optimalizacích generovaného nativního binárního kódu může pracovat s izolovaným stavovým prostorem (má totiž jistotu, že když danou metodu celou přeloží, není nutné vyhledávat, z jakých dalších metod jsou do právě přeložené metody prováděny skoky – jednoduše to není možné). Instrukce goto existuje ve dvou variantách – „krátké“ a „dlouhé“. Tyto varianty se od sebe odlišují pouze počtem bajtů, které se v bajtkódu použijí pro uložení adresy cíle skoku. Buď je možné použít 16bitovou adresu (vyhovuje prakticky všem rozumně dlouhým metodám) nebo adresu 32bitovou (to se obecně příliš často nepoužívá, protože existují další omezení na maximální počet 65536 instrukcí v jedné metodě).
Nyní se již konečně dostáváme k zajímavějšímu tématu – k podmíněným skokům. V instrukčním kódu virtuálního stroje jazyka Java je k dispozici poměrně velké množství typů různých podmíněných skoků. V tomto odstavci si popíšeme skoky, které se provedou resp. neprovedou na základě testu hodnoty jediného operandu, který je uložen na vrcholu zásobníku operandů (TOS). Ve všech případech se přitom musí jednat o operand typu int, který je po provedení testu ze zásobníku operandů odstraněn (samozřejmě nezávisle na tom, jak test ve skutečnosti dopadl). Instrukce podmíněného skoku nejdříve na základě operačního kódu instrukce zjistí, zda je operand nulový, nenulový, větší než nula, menší než nula, větší nebo roven nule popř. naopak menší nebo roven nule. Pokud je daná podmínka splněna, je proveden skok na šestnáctibitovou lokální adresu uloženou za operačním kódem instrukce; v opačném případě se pokračuje v provádění instrukce uložené ihned za podmíněným skokem. Všech šest variant podmíněných skoků pracujících s jediným operandem typu int je vypsáno v následující tabulce:
# | Instrukce | Opkód | Operandy | Podmínka | Operace |
---|---|---|---|---|---|
1 | ifeq | 0×99 | highbyte, lowbyte | TOS=0 | skok na lokální adresu highbyte*256+lowbyte při splnění podmínky |
2 | ifne | 0×9A | highbyte, lowbyte | TOS≠0 | skok na lokální adresu highbyte*256+lowbyte při splnění podmínky |
3 | iflt | 0×9B | highbyte, lowbyte | TOS<0 | skok na lokální adresu highbyte*256+lowbyte při splnění podmínky |
4 | ifge | 0×9C | highbyte, lowbyte | TOS≥0 | skok na lokální adresu highbyte*256+lowbyte při splnění podmínky |
5 | ifgt | 0×9D | highbyte, lowbyte | TOS>0 | skok na lokální adresu highbyte*256+lowbyte při splnění podmínky |
6 | ifle | 0×9E | highbyte, lowbyte | TOS≤0 | skok na lokální adresu highbyte*256+lowbyte při splnění podmínky |
Z teoretického hlediska by podmíněné skoky popsané v předchozím odstavci měly ve všech případech postačovat. V praxi – například při implementaci počítaných programových smyček – je však vhodné umět efektivně provést podmíněný skok na základě porovnání dvou operandů, nikoli na základě porovnání jednoho operandu vůči nule. Samozřejmě je možné nejdříve oba operandy od sebe odečíst a poté provést skok na základě výsledku tohoto rozdílu (což se podobá systému používanému u mnohých typů mikroprocesorů), to však vyžaduje zbytečně dlouhou sekvenci instrukcí. Z tohoto důvodu se v instrukčním souboru JVM nachází i instrukce, které porovnají dvojici operandů typu int uloženou na nejvrchnějších dvou pozicích zásobníku operandů a skok vykonají na základě toho, zda je první operand větší, menší či roven operandu druhému (oba operandy jsou navíc ze zásobníku odstraněny):
# | Instrukce | Opkód | Operandy | Podmínka | Operace |
---|---|---|---|---|---|
1 | if_icmpeq | 0×9F | highbyte, lowbyte | value1=value2 | skok na adresu highbyte*256+lowbyte při splnění podmínky |
2 | if_icmpne | 0×A0 | highbyte, lowbyte | value1≠value2 | skok na adresu highbyte*256+lowbyte při splnění podmínky |
3 | if_icmplt | 0×A1 | highbyte, lowbyte | value1<value2 | skok na adresu highbyte*256+lowbyte při splnění podmínky |
4 | if_icmpge | 0×A2 | highbyte, lowbyte | value1≥value2 | skok na adresu highbyte*256+lowbyte při splnění podmínky |
5 | if_icmpgt | 0×A3 | highbyte, lowbyte | value1>value2 | skok na adresu highbyte*256+lowbyte při splnění podmínky |
6 | if_icmple | 0×A4 | highbyte, lowbyte | value1≤value2 | skok na adresu highbyte*256+lowbyte při splnění podmínky |
Ostatní dva popisované virtuální stroje mají kupodivu mnohem jednodušší instrukční sadu, což ostatně uvidíme i na demonstračních příkladech společně s příslušným popisem.
2. Jednoduchá programová smyčka typu while
Základním a ve skutečnosti i univerzálním typem smyčky je ve strukturovaném programování smyčka typu while. U tohoto typu smyčky se podmínka pro ukončení smyčky kontroluje vždy na začátku každé iterace, což mj. znamená, že se tělo smyčky nemusí provést ani jednou, a to v případě, kdy podmínka není splněna již před provedením první iterace, tj. před vstupem do smyčky. Z tohoto důvodu se konstrukce while používá například v situacích, kdy se mají zpracovávat vstupní data (čtená ze souboru, z databázové tabulky atd.), u nichž není zřejmé, kolik údajů se bude načítat a zda se vůbec nějaký údaj na vstupu bude nacházet. Zajímavé je, že ostatní typy smyček lze většinou přepsat právě na programovou smyčku typu while, i když – jak uvidíme na příkladu Pythonu – se nemusí vždy jednat o elegantní řešení. Pojďme si tedy na velmi jednoduchých příkladech ukázat způsob překladu této programové smyčky do bajtkódu JVM, Lua VM i Python VM. Nejprve si ukážeme překlad smyčky, v níž se pouze snižuje hodnota počitadla kontrolovaného v podmínce pro další iteraci.
Demonstrační příklad Test7.java
/** * Trida s jedinou statickou metodou * pro otestovani zakladnich vlastnosti bajtkodu JVM: * prekladu programove smycky typu while. */ public class Test7 { public static int loop(int x) { // sestupne citani smerem k nule while (x > 0) { x--; } // bude se vracet hodnota 0 return x; } /** * Vse je nutne otestovat. */ public static void main(String[] args) { System.out.println(loop(10)); } }
Demonstrační příklad Test7.lua
-- -- Modul s jedinou funkci pro otestovani -- zakladnich vlastnosti bajtkodu jazyka Lua -- prekladu programove smycky typu while. -- function loop(x) while x > 0 do x = x - 1 end return x end -- -- Vse je nutne otestovat. -- function main() print(loop(10)) end main()
Demonstrační příklad Test7.py
# # Modul s jedinou funkci pro otestovani # zakladnich vlastnosti bajtkodu jazyka Lua # prekladu programove smycky typu while. # def loop(x): while x > 0: x = x - 1 return x # # Vse je nutne otestovat. # def main(): print(loop(10)) # # Vypsani bajkkodu testovane funkce # def disassemble(): from dis import dis print("\nloop:") dis(loop) main() disassemble()
3. Ukázky překladu jednoduché programové smyčky while do bajtkódu
V této kapitole budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test7.java, Test7.lua i Test7.py.
Bajtkód demonstračního příkladu Test7.java
V bajtkódu JVM nalezneme jak nepodmíněný skok goto umístěný na konci smyčky, tak i podmíněný skok ifle umístěný na začátku smyčky. Překlad tedy velmi přesně reflektuje původní zdrojový text, což je vhodné zvláště při ladění a krokování:
public static int loop(int); Code: 0: iload_0 ; načíst (jediný) parametr metody a uložit ho na zásobník 1: ifle 10 ; porovnání s nulou a podmíněný skok na instrukci na indexu 10 4: iinc 0, -1 ; snížení hodnoty počitadla (resp. přičtení hodnoty -1, což je to samé) 7: goto 0 ; nepodmíněný skok na začátek smyčky 10: iload_0 ; opět načíst (jediný) parametr metody a uložit ho na zásobník 11: ireturn ; a vrátit jeho novou hodnotu, což by měla být vždy nula
Bajtkód demonstračního příkladu Test7.lua
Funkčně shodný příklad je v případě Lua VM přeložen zcela odlišným způsobem. Namísto podmíněného skoku, což je v Lua VM neexistující instrukce, se zde využívá dvojice instrukcí LT a JMP. JMP je (relativní) nepodmíněný skok, přičemž hodnota uložená v instrukčním slovu se přičítá k aktuální hodnotě čítače instrukcí (PC – Program Counter). Instrukce LT přeskočí následující instrukci tehdy, pokud je splněna podmínka operand 1 < operand 2 (zde je operand 2 konstantou):
function Test7.lua:7,12 (6 instructions at 0x9f54c88) 1 param, 2 slots, 0 upvalues, 1 local, 2 constants, 0 functions 1 [8] LT 0 -1 0 ; 0 - ; porovnání x s nulou a podmíněné přeskočení další instrukce 2 [8] JMP 0 2 ; to 5 ; nepodmíněný skok na instrukci s indexem 5 (konec smyčky) 3 [9] SUB 0 0 -2 ; - 1 ; snížení hodnoty parametru x (index 0) o jedničku 4 [9] JMP 0 -4 ; to 1 ; nepodmíněný skok na instrukci s indexem 1 (skok na začátek smyčky) 5 [11] RETURN 0 2 ; návrat s použitím jediného parametru jako návratové hodnoty 6 [12] RETURN 0 1 ; automaticky generováno (zde zcela zbytečně)
Bajtkód demonstračního příkladu Test7.py
Bajtkód vytvořený pro virtuální stroj Pythonu je kupodivu nejdelší (což prakticky znamená i pomalejší vyhodnocení v porovnání s Luou). Můžeme zde vidět jak nepodmíněný skok JUMP_ABSOLUTE, tak i podmíněný skok JUMP_IF_FALSE, pro nějž se podmínka vyhodnocuje instrukcí COMPARE_OP. Povšimněte si taktéž nutnosti použití instrukce POP_TOP sloužící pro „uklizení“ obsahu zásobníku operandů:
loop: 8 0 SETUP_LOOP 28 (to 31) ; příprava na provedení smyčky 3 LOAD_FAST 0 (x) ; načíst (jediný) parametr metody a uložit ho na zásobník 6 LOAD_CONST 1 (0) ; načíst konstantu 0 použitou pro porovnání 9 COMPARE_OP 4 (>) ; provést porovnání, výsledek je použit pro podmíněný skok 12 JUMP_IF_FALSE 14 (to 29) ; podmíněný skok při NEsplnění podmínky 15 POP_TOP ; uklizení zásobníku 9 16 LOAD_FAST 0 (x) ; načíst (jediný) parametr metody a uložit ho na zásobník 19 LOAD_CONST 2 (1) ; načíst konstantu 1 použitou pro snížení počitadla 22 BINARY_SUBTRACT ; snížení hodnoty počitadla o 1 23 STORE_FAST 0 (x) ; a uložit novou hodnotu 26 JUMP_ABSOLUTE 3 ; skok na začátek smyčky 29 POP_TOP ; (opět) uklizení zásobníku) 30 POP_BLOCK 10 31 LOAD_FAST 0 (x) ; načíst (jediný) parametr metody a uložit ho na zásobník 34 RETURN_VALUE ; návrat s použitím jediného parametru jako návratové hodnoty
4. Programová smyčka typu while se složitějším tělem
Pro zajímavost se ještě podívejme na poněkud složitější demonstrační příklady, v nichž je opět použita programová smyčka typu while. Tyto příklady slouží k výpočtu exponenciální funkce 2x, popř. y2x. Vzhledem k tomu, že hodnoty x a y nejsou dopředu známé, nemůže překladač provádět prakticky žádné optimalizace smyčky (to mohl teoreticky udělat v předchozím příkladu, což se však, jak již víme, ve skutečnosti nestalo).
Demonstrační příklad Test8.java
/** * Trida s jedinou statickou metodou * pro otestovani zakladnich vlastnosti bajtkodu JVM: * prekladu programove smycky typu while se slozitejsim * vypoctem uvnitr tela smycky. */ public class Test8 { public static int loop(int x, int y) { while (x > 0) { x--; y *= 2; } return y; } /** * Vse je nutne otestovat. */ public static void main(String[] args) { System.out.println(loop(10, 1)); } }
Demonstrační příklad Test8.lua
-- -- Modul s jedinou funkci pro otestovani -- zakladnich vlastnosti bajtkodu jazyka Lua -- prekladu programove smycky typu while. -- function loop(x, y) while x > 0 do x = x - 1 y = y * 2 end return y end -- -- Vse je nutne otestovat. -- function main() print(loop(10, 1)) end main()
Demonstrační příklad Test8.py
# # Modul s jedinou funkci pro otestovani # zakladnich vlastnosti bajtkodu jazyka Lua # prekladu programove smycky typu while. # def loop(x, y): while x > 0: x = x - 1 y = y * 2 return y # # Vse je nutne otestovat. # def main(): print(loop(10, 1)) def disassemble(): from dis import dis print("\nloop:") dis(loop) main() disassemble()
5. Ukázky překladu složitější programové smyčky while do bajtkódu
V této kapitole budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test8.java, Test8.lua i Test8.py.
Bajtkód demonstračního příkladu Test8.java
Způsob překladu do bajtkódu JVM není nijak překvapivý, protože samotná programová smyčka je prakticky shodná s příkladem předchozím:
public static int loop(int, int); Code: 0: iload_0 ; načíst první parametr (x) metody a uložit ho na zásobník 1: ifle 14 ; porovnání s nulou a podmíněný skok na instrukci na indexu 10 4: iinc 0, -1 ; snížení hodnoty počitadla (resp. přičtení hodnoty -1, což je to samé) 7: iload_1 ; načíst druhý parametr (y) metody a uložit ho na zásobník 8: iconst_2 ; uložit na zásobník i konstantu 2 9: imul ; provést aritmetickou operaci násobení s dvojicí operandů na zásobníku 10: istore_1 ; uložit výsledek zpět do parametru y 11: goto 0 ; nepodmíněný skok na začátek smyčky 14: iload_1 ; načíst druhý parametr (y) metody a uložit ho na zásobník 15: ireturn ; a vrátit jeho novou hodnotu, což by měla být vždy nula
Bajtkód demonstračního příkladu Test8.lua
Bajtkód Lua VM je podle očekávání nejkratší, neboť se zde s výhodou využívají vlastnosti registrového virtuálního stroje:
function Test8.lua:7,13 (7 instructions at 0x970fc88) 2 params, 2 slots, 0 upvalues, 2 locals, 3 constants, 0 functions 1 [8] LT 0 -1 0 ; 0 - ; porovnání x s nulou a podmíněné přeskočení další instrukce 2 [8] JMP 0 3 ; to 6 ; nepodmíněný skok na instrukci s indexem 6 (konec smyčky) 3 [9] SUB 0 0 -2 ; - 1 ; snížení hodnoty parametru x (index 0) o jedničku 4 [10] MUL 1 1 -3 ; - 2 ; druhý parametr (y) je vynásoben konstantou 2 5 [10] JMP 0 -5 ; to 1 ; nepodmíněný skok na instrukci s indexem 1 (skok na začátek smyčky) 6 [12] RETURN 1 2 ; návrat s použitím druhého parametru (y) jako návratové hodnoty 7 [13] RETURN 0 1 ; automaticky generováno (zde zcela zbytečně)
Bajtkód demonstračního příkladu Test8.py
V případě bajtkódu Python VM je vygenerovaná sekvence instrukcí opět nejdelší:
loop: 8 0 SETUP_LOOP 38 (to 41) ; příprava na provedení smyčky 3 LOAD_FAST 0 (x) ; načíst první parametr (x) metody a uložit ho na zásobník 6 LOAD_CONST 1 (0) ; načíst konstantu 0 použitou pro porovnání 9 COMPARE_OP 4 (>) ; provést porovnání, výsledek je použit pro podmíněný skok 12 JUMP_IF_FALSE 24 (to 39) ; podmíněný skok při NEsplnění podmínky 15 POP_TOP ; uklizení zásobníku 9 16 LOAD_FAST 0 (x) ; načíst první parametr (x) metody a uložit ho na zásobník 19 LOAD_CONST 2 (1) ; načíst konstantu 1 použitou pro snížení počitadla 22 BINARY_SUBTRACT ; snížení hodnoty počitadla o 1 23 STORE_FAST 0 (x) ; a uložit novou hodnotu 10 26 LOAD_FAST 1 (y) ; načíst druhý parametr (y) metody a uložit ho na zásobník 29 LOAD_CONST 3 (2) ; načíst konstantu 2 použitou pro násobení 32 BINARY_MULTIPLY ; provést aritmetickou operaci násobení 33 STORE_FAST 1 (y) ; uložit výsledek zpět do y 36 JUMP_ABSOLUTE 3 ; skok na začátek smyčky 39 POP_TOP ; (opět) uklizení zásobníku) 40 POP_BLOCK 11 41 LOAD_FAST 1 (y) ; načíst druhý parametr (y) metody a uložit ho na zásobník 44 RETURN_VALUE ; návrat s použitím parametru y jako návratové hodnoty
6. Dvě vnořené smyčky typu while – výpis řady prvočísel
Nastává čas ukázat si způsob překladu algoritmu, v němž se používají dvě vnořené programové smyčky typu while. Zde je již situace zajímavější, protože delší zdrojový kód dává překladači alespoň teoretickou možnost provedení různých optimalizací. Jako příklad jsem vybral výpočet řady prvočísel od 2 do zadané maximální hodnoty, přičemž se pro výpočet používá ta nejjednodušší a současně i nejpomalejší :-) metoda založená na postupném zjišťování, zda je zadaná hodnota n dělitelná nějakým celým číslem v rozsahu 2..n-1 (teoreticky je možné smyčku ukončit dříve, ovšem nechtěl jsem zbytečně do demonstračního algoritmu přidávat volání funkcí).
Demonstrační příklad Test9.java
/** * Trida s jedinou statickou metodou * pro otestovani zakladnich vlastnosti bajtkodu JVM: * prekladu vnorene programove smycky typu while pri * vypisu rady prvocisel. */ public class Test9 { public static void primeNumbers(int min, int max) { int i = min; while (i <= max) { // projit vsechny hodnoty od min do max int j = 2; while (j < i) { // (lze optimalizovat a zkratit smycku!) if (i % j == 0) { // je mozne celociselne delit? break; // - pak ovsem nejde o prvocislo } j++; // vyzkouset dalsiho kandidata na celociselne deleni } if (j == i) { // pokud jsme dosli az k cislu i System.out.println(i); // nedoslo nikdy k celociselnemu deleni } // a tudiz jsme nasli prvocislo i++; // dalsi hodnota v posloupnosti } } /** * Vse je nutne otestovat. */ public static void main(String[] args) { primeNumbers(2, 1000); } }
Demonstrační příklad Test9.lua
-- -- Modul s jedinou funkci pro otestovani -- zakladnich vlastnosti bajtkodu jazyka Lua -- prekladu programove smycky typu while pri -- vypisu rady prvocisel. -- function primeNumbers(min, max) local i = min while i <= max do -- projit vsechny hodnoty od min do max local j = 2 while j < i do -- (lze optimalizovat a zkratit smycku!) if i % j == 0 then -- je mozne celociselne delit? break -- - pak ovsem nejde o prvocislo end j = j + 1 -- vyzkouset dalsiho kandidata na celociselne deleni end if j == i then -- pokud jsme dosli az k cislu i print(i) -- nedoslo nikdy k celociselnemu deleni end -- a tudiz jsme nasli prvocislo i = i + 1 -- dalsi hodnota v posloupnosti end end -- -- Vse je nutne otestovat. -- function main() primeNumbers(2, 1000) end main()
Demonstrační příklad Test9.py
# # Modul s jedinou funkci pro otestovani # zakladnich vlastnosti bajtkodu jazyka Lua # prekladu programove smycky typu while pri # vypoctu rady prvocisel. # def primeNumbers(min, max): i = min while(i <= max): # projit vsechny hodnoty od min do max j = 2 while(j < i): # (lze optimalizovat a zkratit smycku!) if i % j == 0: # je mozne celociselne delit? break # - pak ovsem nejde o prvocislo j = j + 1 # vyzkouset dalsiho kandidata na celociselne deleni if (j == i): # pokud jsme dosli az k cislu i print i # nedoslo nikdy k celociselnemu deleni i = i + 1 # dalsi hodnota v posloupnosti # # Vse je nutne otestovat. # def main(): primeNumbers(2, 1000) def disassemble(): from dis import dis print("\nprimeNumbers:") dis(primeNumbers) main() disassemble()
7. Ukázky překladu vnořených smyček while do bajtkódu
V této kapitole budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test9.java, Test9.lua i Test9.py.
Bajtkód demonstračního příkladu Test9.java
Na přeloženém bajtkódu JVM je asi nejzajímavější fakt, že se plně nevyužívá možností zásobníku operandů, takže se hodnoty neustále načítají z parametrů popř. z lokálních proměnných, i když bajtkód JVM obsahuje „zásobníkové“ instrukce typu DUP, DUP2 či SWAP:
public static void primeNumbers(int, int); Code: 0: iload_0 1: istore_2 2: iload_2 ; začátek vnější smyčky 3: iload_1 4: if_icmpgt 47 ; test na ukončení vnější 7: iconst_2 8: istore_3 9: iload_3 ; začátek vnitřní smyčky 10: iload_2 11: if_icmpge 29 ; test na vnitřní vnější 14: iload_2 15: iload_3 16: irem 17: ifne 23 ; implementace "if" 20: goto 29 23: iinc 3, 1 26: goto 9 ; skok na začátek vnitřní smyčky 29: iload_3 30: iload_2 31: if_icmpne 41 ; implementace "if" 34: getstatic #2; ; Field java/lang/System.out:Ljava/io/PrintStream; 37: iload_2 38: invokevirtual #3; ; Method java/io/PrintStream.println:(I)V 41: iinc 2, 1 44: goto 2 ; skok na začátek vnější smyčky 47: return
Bajtkód demonstračního příkladu Test9.lua
V případě bajtkódu Lua VM je překlad vnořených programových smyček přímočarý – nalezneme zde celkem dva nepodmíněné skoky (na konci smyček) a čtyři dvojice podmínka+skok (začátky smyček a rozhodovací konstrukce „if“):
function Test9.lua:8,23 (19 instructions at 0x842dcb0) 2 params, 6 slots, 1 upvalue, 4 locals, 4 constants, 0 functions 1 [9] MOVE 2 0 2 [10] LE 0 2 1 ; podmínka pro vnější smyčku 3 [10] JMP 0 15 ; to 19 ; skok pro vnější smyčku 4 [11] LOADK 3 -1 ; 2 5 [12] LT 0 3 2 ; podmínka pro vnitřní smyčku 6 [12] JMP 0 5 ; to 12 ; skok pro vnitřní smyčku 7 [13] MOD 4 2 3 8 [13] EQ 1 4 -2 ; - 0 9 [13] JMP 0 2 ; to 12 ; implementace "if" 10 [16] ADD 3 3 -3 ; - 1 11 [16] JMP 0 -7 ; to 5 ; skok na konci vnitřní smyčky 12 [18] EQ 0 3 2 ; implementace "if" 13 [18] JMP 0 3 ; to 17 14 [19] GETTABUP 4 0 -4 ; _ENV "print" ; příprava na volání funkce print() 15 [19] MOVE 5 2 16 [19] CALL 4 2 1 ; vlastní volání funkce print() 17 [21] ADD 2 2 -3 ; - 1 18 [21] JMP 0 -17 ; to 2 ; skok na konci vnější smyčky 19 [23] RETURN 0 1 ; automaticky generováno (nic se nevrací)
Bajtkód demonstračního příkladu Test9.py
Posledním bajtkódem je bajtkód vygenerovaný pro Python VM. Tento bajtkód je již dosti těžkopádný, což souvisí i s relativní pomalostí jeho vykonávání, zejména v porovnání s Lua VM:
primeNumbers: 9 0 LOAD_FAST 0 (min) ; i = min 3 STORE_FAST 2 (i) 10 6 SETUP_LOOP 109 (to 118) ; while(i <= max): 9 LOAD_FAST 2 (i) 12 LOAD_FAST 1 (max) 15 COMPARE_OP 1 (<=) 18 JUMP_IF_FALSE 95 (to 116) 21 POP_TOP 11 22 LOAD_CONST 1 (2) ; j = 2 25 STORE_FAST 3 (j) 12 28 SETUP_LOOP 50 (to 81) ; while(j < i): 31 LOAD_FAST 3 (j) 34 LOAD_FAST 2 (i) 37 COMPARE_OP 0 (<) 40 JUMP_IF_FALSE 36 (to 79) 43 POP_TOP 13 44 LOAD_FAST 2 (i) ; if i % j == 0: 47 LOAD_FAST 3 (j) 50 BINARY_MODULO 51 LOAD_CONST 2 (0) 54 COMPARE_OP 2 (==) 57 JUMP_IF_FALSE 5 (to 65) 60 POP_TOP 14 61 BREAK_LOOP 62 JUMP_FORWARD 1 (to 66) ; break 65 POP_TOP 15 66 LOAD_FAST 3 (j) ; j = j + 1 69 LOAD_CONST 3 (1) 72 BINARY_ADD 73 STORE_FAST 3 (j) 76 JUMP_ABSOLUTE 31 ; konec vnitřní smyčky 79 POP_TOP 80 POP_BLOCK 16 81 LOAD_FAST 3 (j) ; if (j == i): 84 LOAD_FAST 2 (i) 87 COMPARE_OP 2 (==) 90 JUMP_IF_FALSE 9 (to 102) 93 POP_TOP 17 94 LOAD_FAST 2 (i) ; print i 97 PRINT_ITEM 98 PRINT_NEWLINE 99 JUMP_FORWARD 1 (to 103) 102 POP_TOP 18 103 LOAD_FAST 2 (i) ; i = i + 1 106 LOAD_CONST 3 (1) 109 BINARY_ADD 110 STORE_FAST 2 (i) 113 JUMP_ABSOLUTE 9 ; konec vnější smyčky 116 POP_TOP 117 POP_BLOCK 118 LOAD_CONST 0 (None) 121 RETURN_VALUE
8. Jednoduchá programová smyčka typu do-while/repeat-until
Kromě programové smyčky typu while se ve strukturovaném programování velmi často setkáme i se smyčkou typu do-while, popř. s ekvivalentní smyčkou repeat-until. Zatímco se ve smyčce while provádí test na ukončení smyčky před každou iterací, je v případě do-while i repeat-until test prováděn na konci těla smyčky a tedy již po dokončení jedné iterace, což mimochodem znamená, že tělo smyčky bude vždy provedeno alespoň jedenkrát. Rozdíl mezi smyčkami do-while (céčková větev programovacích jazyků) a repeat-until (Pascal, Modula-2, Lua) spočívá pouze v tom, zda je splnění zapsané podmínky považováno za vstup do další iterace či naopak za důvod pro ukončení celé programové smyčky. Zatímco programovací jazyk Java podporuje smyčku do-while, najdeme v jazyku Lua smyčku repeat-until a v Pythonu je nutné tuto smyčku emulovat s využitím smyčky typu while doplněnou o podmínku na konci popř. doplněnou o další lokální proměnnou.
Demonstrační příklad Test10.java
/** * Trida s jedinou statickou metodou * pro otestovani zakladnich vlastnosti bajtkodu JVM: * prekladu jednoduche programove smycky typu do-while. */ public class Test10 { public static int loop(int x) { do { x--; } while (x>0); return x; } /** * Vse je nutne otestovat. */ public static void main(String[] args) { System.out.println(loop(10)); } }
Demonstrační příklad Test10.lua
-- -- Modul s jedinou funkci pro otestovani -- zakladnich vlastnosti bajtkodu jazyka Lua -- prekladu programove smycky typu do-while -- (resp. repeat-until) -- function loop(x) repeat x = x - 1 until x <= 0 return x end -- -- Vse je nutne otestovat. -- function main() print(loop(10)) end main()
Demonstrační příklad Test10.py
# # Modul s jedinou funkci pro otestovani # zakladnich vlastnosti bajtkodu jazyka Lua # prekladu programove smycky typu do-while. # (presneji receno jeji emulace) # def loop(x): while True: x = x - 1 if x <= 0: break return x # # Vse je nutne otestovat. # def main(): print(loop(10)) # # Vypsani bajkkodu testovane funkce # def disassemble(): from dis import dis print("\nloop:") dis(loop) main() disassemble()
9. Ukázky překladu jednoduché programové smyčky do-while/repeat-until do bajtkódu
V této kapitole budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test10.java, Test10.lua i Test10.py.
Bajtkód demonstračního příkladu Test10.java
Z výpisu bajtkódu JVM je patrné, že se smyčka typu do-while přeložila pouze s využitím jednoho podmíněného skoku umístěného na konci smyčky:
public static int loop(int); Code: 0: iinc 0, -1 ; snížení hodnoty počitadla (resp. přičtení hodnoty -1, což je to samé) 3: iload_0 ; načíst první parametr (x) metody a uložit ho na zásobník 4: ifgt 0 ; porovnání s nulou a podmíněný skok na začátek smyčky 7: iload_0 ; načíst první parametr (x) metody a uložit ho na zásobník 8: ireturn ; a vrátit jeho novou hodnotu, což by měla být vždy nula
Bajtkód demonstračního příkladu Test10.lua
Bajtkód určený pro Lua VM je opět podle očekávání velmi jednoduchý a přímočarý, pouze se namísto instrukce LT používá instrukce LE (less or equal):
function Test10.lua:8,13 (5 instructions at 0x8ae2c88) 1 param, 2 slots, 0 upvalues, 1 local, 2 constants, 0 functions 1 [10] SUB 0 0 -1 ; - 1 ; snížení hodnoty parametru x (index 0) o jedničku 2 [11] LE 0 0 -2 ; - 0 ; porovnání x s nulou a podmíněné přeskočení další instrukce 3 [11] JMP 0 -3 ; to 1 ; nepodmíněný skok na instrukci s indexem 1 (skok na začátek smyčky) 4 [12] RETURN 0 2 ; návrat s použitím prvního parametru (x) jako návratové hodnoty 5 [13] RETURN 0 1 ; automaticky generováno (zde zcela zbytečně)
Bajtkód demonstračního příkladu Test10.py
V případě Pythonu je smyčka do-while ve skutečnosti pouze emulována, čemuž odpovídá i (relativně přímočarý) překlad do bajtkódu:
loop: 9 0 SETUP_LOOP 40 (to 43) ; příprava na provedení smyčky 3 LOAD_GLOBAL 0 (True) ; nekonečná smyčka typu while 6 JUMP_IF_FALSE 32 (to 41) ; podmíněný skok při NEsplnění podmínky 9 POP_TOP ; uklizení zásobníku 10 10 LOAD_FAST 0 (x) ; načíst (jediný) parametr metody a uložit ho na zásobník 13 LOAD_CONST 1 (1) ; načíst konstantu 1 použitou pro snížení počitadla 16 BINARY_SUBTRACT ; snížení hodnoty počitadla o 1 17 STORE_FAST 0 (x) ; a uložit novou hodnotu 11 20 LOAD_FAST 0 (x) ; načíst (jediný) parametr metody a uložit ho na zásobník 23 LOAD_CONST 2 (0) ; načíst konstantu 0 použitou pro porovnání 26 COMPARE_OP 1 (<=) ; provést porovnání, výsledek je použit pro podmíněný skok 29 JUMP_IF_FALSE 5 (to 37) ; podmíněný skok při NEsplnění podmínky 32 POP_TOP ; uklizení zásobníku 33 BREAK_LOOP ; ukončení smyčky 34 JUMP_ABSOLUTE 3 ; skok na začátek smyčky 37 POP_TOP ; uklizení zásobníku 38 JUMP_ABSOLUTE 3 ; skok na začátek smyčky 41 POP_TOP ; uklizení zásobníku 42 POP_BLOCK 12 43 LOAD_FAST 0 (x) ; načíst (jediný) parametr metody a uložit ho na zásobník 46 RETURN_VALUE ; návrat s použitím jediného parametru jako návratové hodnoty
10. Dvě vnořené smyčky typu do-while – výpis řady prvočísel
Pro zajímavost se pokusíme přepsat výše uvedené demonstrační příklady pro výpočet řady prvočísel takovým způsobem, aby se místo vnořených programových smyček typu while používala buď dvojice vnořených smyček typu do-while v případě programovacího jazyka Java popř. dvojice vnořených smyček typu repeat-until programovacího jazyka Lua. Tyto příklady sice nejsou zcela ekvivalentní původním demonstračním příkladům, ovšem základní způsob výpočtu zůstává zachován. Vzhledem k tomu, že programovací jazyk Python tento typ smyček vůbec nepodporuje, nebyl program přepsán (protože to zrovna u tohoto algoritmu nedává žádný velký smysl a vygenerovaný bajtkód by byl ještě horší než u algoritmu v původní podobě).
Demonstrační příklad Test11.java
/** * Trida s jedinou statickou metodou * pro otestovani zakladnich vlastnosti bajtkodu JVM: * prekladu vnorene programove smycky typu do-while pri * vypisu rady prvocisel. */ public class Test11 { public static void primeNumbers(int min, int max) { int i = min; do { // projit vsechny hodnoty od min do max int j = 2; do { if (i % j == 0) { // je mozne celociselne delit? break; // - pak ovsem nejde o prvocislo } j++; // vyzkouset dalsiho kandidata na celociselne deleni } while (j < i); // (lze optimalizovat a zkratit smycku!) if (j == i) { // pokud jsme dosli az k cislu i System.out.println(i); // nedoslo nikdy k celociselnemu deleni } // a tudiz jsme nasli prvocislo i++; // dalsi hodnota v posloupnosti } while (i <= max); } /** * Vse je nutne otestovat. */ public static void main(String[] args) { primeNumbers(2, 1000); } }
Demonstrační příklad Test11.lua
-- -- Modul s jedinou funkci pro otestovani -- zakladnich vlastnosti bajtkodu jazyka Lua -- prekladu programove smycky typu repeat-until -- pri vypisu rady prvocisel. -- function primeNumbers(min, max) local i = min repeat -- projit vsechny hodnoty od min do max local j = 2 repeat -- (lze optimalizovat a zkratit smycku!) if i % j == 0 then -- je mozne celociselne delit? break -- - pak ovsem nejde o prvocislo end j = j + 1 -- vyzkouset dalsiho kandidata na celociselne deleni until j > i if j == i then -- pokud jsme dosli az k cislu i print(i) -- nedoslo nikdy k celociselnemu deleni end -- a tudiz jsme nasli prvocislo i = i + 1 -- dalsi hodnota v posloupnosti until i > max end -- -- Vse je nutne otestovat. -- function main() primeNumbers(2, 1000) end main()
11. Ukázky překladu vnořených smyček do-while do bajtkódu
Bajtkód demonstračního příkladu Test11.java
V případě programovacího jazyka Java došlo ke zkrácení bajtkódu na 41 bajtů oproti původním 47 bajtům při použití smyček typu while:
public static void primeNumbers(int, int); Code: 0: iload_0 1: istore_2 2: iconst_2 ; začátek vnější smyčky 3: istore_3 4: iload_2 ; začátek vnitřní smyčky 5: iload_3 6: irem 7: ifne 13 ; implementace "if" 10: goto 21 13: iinc 3, 1 16: iload_3 17: iload_2 18: if_icmplt 4 ; skok na konci vnitřní smyčky 21: iload_3 22: iload_2 23: if_icmpne 33 ; implementace "if" 26: getstatic #2; ; Field java/lang/System.out:Ljava/io/PrintStream; 29: iload_2 30: invokevirtual #3; ; Method java/io/PrintStream.println:(I)V 33: iinc 2, 1 36: iload_2 37: iload_1 38: if_icmple 2 ; skok na konci vnější smyčky 41: return
Bajtkód demonstračního příkladu Test11.lua
Zatímco demonstrační příklad Test9.lua byl přeložen pomocí devatenácti instrukcí, zde si překladač vystačil s pouhými sedmnácti instrukcemi, a to opět z toho důvodu, že se test provádí až na konci smyčky, ušetří se tedy minimálně dva nepodmíněné skoky:
function Test11.lua:8,23 (17 instructions at 0x9ee0cb0) 2 params, 6 slots, 1 upvalue, 4 locals, 4 constants, 0 functions 1 [9] MOVE 2 0 2 [11] LOADK 3 -1 ; 2 3 [13] MOD 4 2 3 4 [13] EQ 1 4 -2 ; - 0 5 [13] JMP 0 3 ; to 9 ; implementace "if" 6 [16] ADD 3 3 -3 ; - 1 7 [17] LT 0 2 3 8 [17] JMP 0 -6 ; to 3 ; skok pro vnitřní smyčku 9 [18] EQ 0 3 2 10 [18] JMP 0 3 ; to 14 ; implementace "if" 11 [19] GETTABUP 4 0 -4 ; _ENV "print" 12 [19] MOVE 5 2 13 [19] CALL 4 2 1 14 [21] ADD 2 2 -3 ; - 1 15 [22] LT 0 1 2 16 [22] JMP 0 -15 ; to 2 ; skok pro vnější smyčku 17 [23] RETURN 0 1 ; automaticky generováno (nic se nevrací)
12. Obsah následující části seriálu
V následující části tohoto seriálu se budeme věnovat již poněkud pokročilejším tématům. Bude se jednat o způsob překladu programových smyček typu for (počítaná programová smyčka) a foreach (průchod kolekcí popř. využití takzvaných iterátorů), protože některé popisované virtuální stroje obsahují specializované instrukce pro tento typ velmi často používaných programových smyček. Kromě toho si taktéž ukážeme, jakým způsobem se v generovaném bajtkódu volají funkce a/nebo metody, což je problematika, která velmi úzce souvisí se způsobem předávání parametrů volaným metodám/funkcím i se způsobem předávaní návratové hodnoty či dokonce většího množství návratových hodnot.
13. 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:
14. Odkazy na Internetu
- 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 - Programovací jazyk Lua
http://palmknihy.cz/web/kniha/programovaci-jazyk-lua-12651.htm - 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