Pohled pod kapotu JVM – překlad programových smyček do bajtkódů JVM, Lua VM a Python VM

Pavel Tišnovský 3. 6. 2014

V dnešní části seriálu o programovacím jazyku Java i o virtuálním stroji Javy se již potřetí budeme zabývat porovnáváním vlastností bajtkódů JVM, Python VM i Lua VM. Zaměříme se především na způsob překladu programových smyček typu „while“ a „do-while“ (popř. „repeat-until“) do bajtkódu.

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ů

14. Odkazy na Internetu

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-thenif-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.luaTest7.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í LTJMP. 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 xy 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.luaTest8.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.luaTest9.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-whilerepeat-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.luaTest10.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:

widgety

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.or­g/people/ptisnovs/jvm-tools/. Odkazy na prozatím poslední verze těchto příkladů naleznete v tabulce pod tímto odstavcem:

# Zdrojový kód Umístění
1 Test7.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/9f1d8c533dd2/by­tecode/Java/Test7.java
2 Test7.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/8d82717323ec/by­tecode/Lua/Test7.lua
3 Test7.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/dc752058181f/by­tecode/Python/Test7.py
     
4 Test8.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/9f1d8c533dd2/by­tecode/Java/Test8.java
5 Test8.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/8d82717323ec/by­tecode/Lua/Test8.lua
6 Test8.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/dc752058181f/by­tecode/Python/Test8.py
     
7 Test9.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/9f1d8c533dd2/by­tecode/Java/Test9.java
8 Test9.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/8d82717323ec/by­tecode/Lua/Test9.lua
9 Test9.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/dc752058181f/by­tecode/Python/Test9.py
     
10 Test10.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/9f1d8c533dd2/by­tecode/Java/Test10.java
11 Test10.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/8d82717323ec/by­tecode/Lua/Test10.lua
12 Test10.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/dc752058181f/by­tecode/Python/Test10.py
     
13 Test11.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/9f1d8c533dd2/by­tecode/Java/Test11.java
14 Test11.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/8d82717323ec/by­tecode/Lua/Test11.lua

14. Odkazy na Internetu

  1. Parrot
    http://www.parrot.org/
  2. Parrot languages
    http://www.parrot.org/languages
  3. Parrot Primer
    http://docs.parrot.org/pa­rrot/latest/html/docs/intro­.pod.html
  4. Parrot Opcodes
    http://docs.parrot.org/pa­rrot/latest/html/ops.html
  5. Parrot VM
    http://en.wikibooks.org/wi­ki/Parrot_Virtual_Machine
  6. Parrot Assembly Language
    http://www.perl6.org/archi­ve/pdd/pdd06_pasm.html
  7. Parrot Reference: Chapter 11 – Perl 6 and Parrot Essentials
    http://oreilly.com/perl/excerpts/perl-6-and-parrot-essentials/parrot-reference.html
  8. Python Bytecode: Fun With Dis
    http://akaptur.github.io/blog/2013/08/14/pyt­hon-bytecode-fun-with-dis/
  9. Python's Innards: Hello, ceval.c!
    http://tech.blog.aknin.na­me/category/my-projects/pythons-innards/
  10. Byterun
    https://github.com/nedbat/byterun
  11. Python Byte Code Instructions
    http://document.ihg.uni-duisburg.de/Documentation/Pyt­hon/lib/node56.html
  12. Python Byte Code Instructions
    https://docs.python.org/3­.2/library/dis.html#python-bytecode-instructions
  13. Programovací jazyk Lua
    http://palmknihy.cz/web/kni­ha/programovaci-jazyk-lua-12651.htm
  14. Lua 5.2 sources
    http://www.lua.org/source/5.2/
  15. Lua 5.2 sources – lopcodes.h
    http://www.lua.org/source/5­.2/lopcodes.h.html
  16. Lua 5.2 sources – lopcodes.c
    http://www.lua.org/source/5­.2/lopcodes.c.html
  17. dis – Python module
    https://docs.python.org/2/li­brary/dis.html
  18. Comparison of Python virtual machines
    http://polishlinux.org/ap­ps/cli/comparison-of-python-virtual-machines/
  19. O-code
    http://en.wikipedia.org/wiki/O-code_machine
  20. BCPL
    http://en.wikipedia.org/wiki/BCPL
  21. The BCPL Cintcode System and Cintpos User Guide by Martin Richards
    http://www.cl.cam.ac.uk/u­sers/mr/bcplman.pdf
  22. Bootstrapping the BCPL Compiler using INTCODE
    http://www.gtoal.com/langu­ages/bcpl/amiga/bcpl/bootin­g.txt
  23. p-code machine
    http://en.wikipedia.org/wiki/P-code_machine
  24. ucsd-psystem-vm 0.11 (a portable virtual machine for the UCSD p-System)
    http://ucsd-psystem-vm.sourceforge.net/
  25. Introduction to Smalltalk bytecodes
    http://marianopeck.wordpres­s.com/2011/05/21/introduc­tion-to-smalltalk-bytecodes/
  26. Audio File Formats.
    http://sox.sourceforge.net/Au­dioFormats-11.html
  27. TestSounds.com: pure digital sounds to test your audio
    http://www.testsounds.com/
  28. Test Tones (20hz – 20khz)
    http://mdf1.tripod.com/test-tones.html
  29. WAV (Wikipedia)
    http://en.wikipedia.org/wiki/WAV
  30. WAVE PCM soundfile format
    https://ccrma.stanford.edu/cou­rses/422/projects/WaveFor­mat/
  31. Audio Interchange File Format
    http://en.wikipedia.org/wiki/Aiff
  32. Musical Instrument Digital Interface,
    http://en.wikipedia.org/wi­ki/Musical_Instrument_Digi­tal_Interface
  33. A MIDI Pedalboard Encode,
    http://www.pykett.org.uk/a_mi­di_pedalboard_encoder.htm
  34. MIDI Note Number, Frequency Table,
    http://tonalsoft.com/pub/news/pitch-bend.aspx
  35. Note names, MIDI numbers and frequencies,
    http://www.phys.unsw.edu.au­/jw/notes.html
  36. The MIDI Specification,
    http://www.gweep.net/~pre­fect/eng/reference/protocol/mi­dispec.html
  37. Essentials of the MIDI protocol,
    http://ccrma.stanford.edu/~cra­ig/articles/linuxmidi/mis­c/essenmidi.html
  38. General MIDI,
    http://en.wikipedia.org/wi­ki/General_MIDI
  39. Obecné MIDI (General MIDI),
    http://www-kiv.zcu.cz/~herout/html_sbo/mi­di/5.html
  40. Custom Chips: Paula
    http://www.amiga-hardware.com/showhardware­.cgi?HARDID=1460
  41. Big Book of Amiga Hardware
    http://www.amiga-resistance.info/bboahfaq/
  42. Amiga Hardware Database
    http://amiga.resource.cx/
  43. ExoticA
    http://www.exotica.org.uk/wi­ki/Main_Page
  44. The absolute basics of Amiga audio
    http://www.sufo.estates.co­.uk/amiga/amimus.html
  45. Wikipedia: Tracker
    http://en.wikipedia.org/wiki/Tracker
  46. Wikipedia: Trackers
    http://en.wikipedia.org/wiki/Trackers
  47. Ultimate Soundtracker
    http://en.wikipedia.org/wi­ki/Ultimate_Soundtracker
  48. Protracker
    http://en.wikipedia.org/wi­ki/ProTracker
  49. Impulse Tracker
    http://en.wikipedia.org/wi­ki/Impulse_Tracker
  50. Scream Tracker
    http://en.wikipedia.org/wi­ki/ScreamTracker
  51. MikMod for Java
    http://jmikmod.berlios.de/
  52. List of audio trackers
    http://en.wikipedia.org/wi­ki/List_of_audio_trackers
  53. Wikipedia: Module File
    http://en.wikipedia.org/wi­ki/Module_file
  54. Wikipedia: Chiptune
    http://en.wikipedia.org/wiki/Chiptune
  55. SDL_mixer 2.0
    http://www.libsdl.org/pro­jects/SDL_mixer/
  56. SDLJava: package sdljava.ttf
    http://sdljava.sourceforge­.net/docs/api/sdljava/ttf/pac­kage-summary.html#package_description
  57. SDLJava: class sdljava.ttf.SDLTTF
    http://sdljava.sourceforge­.net/docs/api/sdljava/ttf/SDLTTF­.html
  58. SDLJava: class sdljava.ttf.SDLTrueTypeFont
    http://sdljava.sourceforge­.net/docs/api/sdljava/ttf/SDLTru­eTypeFont.html
  59. SDL_ttf Documentation
    http://www.libsdl.org/pro­jects/SDL_ttf/docs/
  60. SDL_ttf 2.0 (není prozatím součástí SDLJava)
    http://www.libsdl.org/pro­jects/SDL_ttf/
  61. SDL_ttf doc
    http://www.libsdl.org/pro­jects/SDL_ttf/docs/SDL_ttf_fra­me.html
  62. SDL 1.2 Documentation: SDL_Surface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html
  63. SDL 1.2 Documentation: SDL_PixelFormat
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html
  64. SDL 1.2 Documentation: SDL_LockSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html
  65. SDL 1.2 Documentation: SDL_UnlockSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html
  66. SDL 1.2 Documentation: SDL_LoadBMP
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html
  67. SDL 1.2 Documentation: SDL_SaveBMP
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html
  68. SDL 1.2 Documentation: SDL_BlitSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html
  69. SDL 1.2 Documentation: SDL_VideoInfo
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html
  70. SDL 1.2 Documentation: SDL_GetVideoInfo
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html
  71. glDrawArrays
    http://www.opengl.org/sdk/doc­s/man4/xhtml/glDrawArrays­.xml
  72. glDrawElements
    http://www.opengl.org/sdk/doc­s/man4/xhtml/glDrawElemen­ts.xml
  73. glDrawArraysInstanced
    http://www.opengl.org/sdk/doc­s/man4/xhtml/glDrawArraysIn­stanced.xml
  74. glDrawElementsInstanced
    http://www.opengl.org/sdk/doc­s/man4/xhtml/glDrawElemen­tsInstanced.xml
  75. Root.cz: Seriál Grafická knihovna OpenGL
    http://www.root.cz/serialy/graficka-knihovna-opengl/
  76. 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/
  77. Best Practices for Working with Vertex Data
    https://developer.apple.com/li­brary/ios/documentation/3ddra­wing/conceptual/opengles_pro­grammingguide/Techniquesfor­WorkingwithVertexData/Techni­quesforWorkingwithVertexDa­ta.html
  78. Class BufferStrategy
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/i­mage/BufferStrategy.html
  79. Class Graphics
    http://docs.oracle.com/ja­vase/1.5.0/docs/api/java/aw­t/Graphics.html
  80. Double Buffering and Page Flipping
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/doublebuf.html
  81. BufferStrategy and BufferCapabilities
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/bufferstrategy.html
  82. Java:Tutorials:Double Buffering
    http://content.gpwiki.org/in­dex.php/Java:Tutorials:Dou­ble_Buffering
  83. Double buffer in standard Java AWT
    http://www.codeproject.com/Ar­ticles/2136/Double-buffer-in-standard-Java-AWT
  84. Java 2D: Hardware Accelerating – Part 1 – Volatile Images
    http://www.javalobby.org/fo­rums/thread.jspa?threadID=16840&tstar­t=0
  85. Java 2D: Hardware Accelerating – Part 2 – Buffer Strategies
    http://www.javalobby.org/ja­va/forums/t16867.html
  86. How does paintComponent work?
    http://stackoverflow.com/qu­estions/15544549/how-does-paintcomponent-work
  87. A Swing Architecture Overview
    http://www.oracle.com/technet­work/java/architecture-142923.html
  88. Class javax.swing.JComponent
    http://docs.oracle.com/ja­vase/6/docs/api/javax/swin­g/JComponent.html
  89. Class java.awt.Component
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/Com­ponent.html
  90. Class java.awt.Component.BltBufferStrategy
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/Com­ponent.BltBufferStrategy.html
  91. Class java.awt.Component.FlipBufferStrategy
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/Com­ponent.FlipBufferStrategy­.html
  92. Metoda java.awt.Component.isDoubleBuffered()
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/Com­ponent.html#isDoubleBuffe­red()
  93. Metoda javax.swing.JComponent.is­DoubleBuffered()
    http://docs.oracle.com/ja­vase/6/docs/api/javax/swin­g/JComponent.html#isDouble­Buffered()
  94. Metoda javax.swing.JComponent.set­DoubleBuffered()
    http://docs.oracle.com/ja­vase/6/docs/api/javax/swin­g/JComponent.html#setDouble­Buffered(boolean)
  95. Javadoc – třída GraphicsDevice
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsDevice.html
  96. Javadoc – třída GraphicsEnvironment
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsEnvironment.html
  97. Javadoc – třída GraphicsConfiguration
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsConfiguration.html
  98. Javadoc – třída DisplayMode
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Dis­playMode.html
  99. Lesson: Full-Screen Exclusive Mode API
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/
  100. Full-Screen Exclusive Mode
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/exclusivemode.html
  101. Display Mode
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/displaymode.html
  102. Using the Full-Screen Exclusive Mode API in Java
    http://www.developer.com/ja­va/other/article.php/3609776/U­sing-the-Full-Screen-Exclusive-Mode-API-in-Java.htm
  103. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  104. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  105. MultiMedia eXtensions
    http://softpixel.com/~cwrig­ht/programming/simd/mmx.phpi
  106. SSE (Streaming SIMD Extentions)
    http://www.songho.ca/misc/sse/sse­.html
  107. Timothy A. Chagnon: SSE and SSE2
    http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf
  108. Intel corporation: Extending the Worldr's Most Popular Processor Architecture
    http://download.intel.com/techno­logy/architecture/new-instructions-paper.pdf
  109. SIMD architectures:
    http://arstechnica.com/ol­d/content/2000/03/simd.ar­s/
  110. GC safe-point (or safepoint) and safe-region
    http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html
  111. Safepoints in HotSpot JVM
    http://blog.ragozin.info/2012/10/sa­fepoints-in-hotspot-jvm.html
  112. Java theory and practice: Synchronization optimizations in Mustang
    http://www.ibm.com/develo­perworks/java/library/j-jtp10185/
  113. How to build hsdis
    http://hg.openjdk.java.net/jdk7/hot­spot/hotspot/file/tip/src/sha­re/tools/hsdis/README
  114. Java SE 6 Performance White Paper
    http://www.oracle.com/technet­work/java/6-performance-137236.html
  115. Lukas Stadler's Blog
    http://classparser.blogspot­.cz/2010/03/hsdis-i386dll.html
  116. How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
    http://dropzone.nfshost.com/hsdis.htm
  117. PrintAssembly
    https://wikis.oracle.com/dis­play/HotSpotInternals/Prin­tAssembly
  118. The Java Virtual Machine Specification: 3.14. Synchronization
    http://docs.oracle.com/ja­vase/specs/jvms/se7/html/jvms-3.html#jvms-3.14
  119. The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4
  120. The Java Virtual Machine Specification: 17.4. Memory Model
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.4
  121. The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.7
  122. Open Source ByteCode Libraries in Java
    http://java-source.net/open-source/bytecode-libraries
  123. ASM Home page
    http://asm.ow2.org/
  124. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2.org/users.html
  125. ObjectWeb ASM (Wikipedia)
    http://en.wikipedia.org/wi­ki/ObjectWeb_ASM
  126. Java Bytecode BCEL vs ASM
    http://james.onegoodcooki­e.com/2005/10/26/java-bytecode-bcel-vs-asm/
  127. BCEL Home page
    http://commons.apache.org/bcel/
  128. Byte Code Engineering Library (před verzí 5.0)
    http://bcel.sourceforge.net/
  129. Byte Code Engineering Library (verze >= 5.0)
    http://commons.apache.org/pro­per/commons-bcel/
  130. BCEL Manual
    http://commons.apache.org/bcel/ma­nual.html
  131. Byte Code Engineering Library (Wikipedia)
    http://en.wikipedia.org/wiki/BCEL
  132. BCEL Tutorial
    http://www.smfsupport.com/sup­port/java/bcel-tutorial!/
  133. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
  134. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2.org/eclipse/index.html
  135. Javassist
    http://www.jboss.org/javassist/
  136. Byteman
    http://www.jboss.org/byteman
  137. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ibm.com/develo­perworks/java/library/j-dyn0414/
  138. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  139. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  140. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  141. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  142. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  143. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  144. aspectj (Eclipse)
    http://www.eclipse.org/aspectj/
  145. Aspect-oriented programming (Wikipedia)
    http://en.wikipedia.org/wi­ki/Aspect_oriented_program­ming
  146. AspectJ (Wikipedia)
    http://en.wikipedia.org/wiki/AspectJ
  147. EMMA: a free Java code coverage tool
    http://emma.sourceforge.net/
  148. Cobertura
    http://cobertura.sourceforge.net/
  149. jclasslib bytecode viewer
    http://www.ej-technologies.com/products/jclas­slib/overview.html
Našli jste v článku chybu?
Lupa.cz: Patička e-mailu závazná jako vlastnoruční podpis?

Patička e-mailu závazná jako vlastnoruční podpis?

Vitalia.cz: dTest odhalil ten nejlepší kečup

dTest odhalil ten nejlepší kečup

Lupa.cz: Jak levné procesory změnily svět?

Jak levné procesory změnily svět?

DigiZone.cz: Skylink Samsung EVO-S příští týden

Skylink Samsung EVO-S příští týden

Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

Tahák, jak vyzrát nad zápachem z úst

Podnikatel.cz: Instalatér, malíř a elektrikář. "Vymřou"?

Instalatér, malíř a elektrikář. "Vymřou"?

Podnikatel.cz: EET pro e-shopy? Postavené na hlavu

EET pro e-shopy? Postavené na hlavu

Lupa.cz: Aukro.cz mění majitele. Vrací se do českých rukou

Aukro.cz mění majitele. Vrací se do českých rukou

Podnikatel.cz: Kalousek chce odklad EET. Předvolební tah?

Kalousek chce odklad EET. Předvolební tah?

Vitalia.cz: Když všichni seli řepku, on vsadil na dýně

Když všichni seli řepku, on vsadil na dýně

Vitalia.cz: Jak Ondra o astma přišel

Jak Ondra o astma přišel

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip

Podnikatel.cz: Udělali jsme velkou chybu, napsal Čupr

Udělali jsme velkou chybu, napsal Čupr

Vitalia.cz: Test dětských svačinek: Tyhle ne!

Test dětských svačinek: Tyhle ne!

DigiZone.cz: Nova opět stahuje „milionáře“

Nova opět stahuje „milionáře“

Vitalia.cz: Jsou vegani a vyrábějí nemléko

Jsou vegani a vyrábějí nemléko

Vitalia.cz: 5 důvodů, proč jet na výlov rybníka

5 důvodů, proč jet na výlov rybníka

Podnikatel.cz: Dva měsíce na EET. Budou stačit?

Dva měsíce na EET. Budou stačit?

Vitalia.cz: Inspekce našla nelegální sklad v SAPĚ. Zase

Inspekce našla nelegální sklad v SAPĚ. Zase

DigiZone.cz: Funbox 4K v DVB-T2 má ostrý provoz

Funbox 4K v DVB-T2 má ostrý provoz