Pohled pod kapotu JVM – překlad dalších řídicích struktur do bajtkódů JVM, Lua VM a Python VM

10. 6. 2014
Doba čtení: 38 minut

Sdílet

V dnešní části seriálu Javě se již počtvrté budeme zabývat porovnáváním vlastností bajtkódů JVM, Python VM i Lua VM. Ukážeme si způsob překladu příkazu „return“ a zejména pak překlad počítaných programových smyček typu „for“ (řekneme si i o historii tohoto klíčového slova).

Obsah

1. Pohled pod kapotu JVM – překlad dalších řídicích struktur do bajtkódů JVM, Lua VM a Python VM

2. Počítaná programová smyčka for – prapředek všech strukturovaných programových smyček

3. Příkaz return – ukončení běhu funkce/metody s předáním návratové hodnoty

4. Ukázky překladu příkazu return do bajtkódu

5. Počítaná programová smyčka for

6. Ukázky překladu jednoduché počítané smyčky typu for do bajtkódu

7. Složitější programová smyčka typu for – výpočet faktoriálu

8. Překlad vnořených počítaných smyček typu for do bajtkódu

9. Příkazy breakcontinue, popř. jejich ekvivalenty

10. Překlad příkazů typu breakcontinue do bajtkódu

11. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů

12. Odkazy na Internetu

1. Pohled pod kapotu JVM – překlad dalších řídicích struktur do bajtkódů JVM, Lua VM a Python VM

V dnešní části seriálu o programovacím jazyku Java i o virtuálním stroji Javy si nejprve ukážeme, jakým způsobem se překládají příkazy return do bajtkódu JVM, Lua VM i Python VM. Posléze se budeme věnovat zajímavějšímu tématu – způsobu překladu počítaných programových smyček typu for, protože tento typ programových smyček je (ve své původní variantě) součástí poměrně velkého množství algoritmů, především numerických algoritmů, kde se pracuje s vektory (jednorozměrnými poli) a maticemi (dvourozměrnými poli). Ostatně právě z tohoto důvodu se s tímto typem smyček můžeme setkat už ve třetí generaci programovacích jazyků (v čele s FORTRANem), kde se dokonce původně jednalo o jeden ze dvou způsobů tvorby programových smyček (první způsob využíval příkaz GOTO pro provedení skoku).

2. Počítaná programová smyčka for – prapředek všech strukturovaných programových smyček

U počítané programové smyčky for se na chvíli zastavme, protože historie jejího vzniku je velmi zajímavá a sahá vlastně až do let 1945 a 1946. V této době dokončil slavný konstruktér počítačů Konrad Zuse návrh svého programovacího jazyka nazvaného Plankalkül (slovo „plan“ zde mělo význam podobný slovu „program“, takže například Zusem navrhované „podplány“ byly vlastně „podprogramy/subrutiny/funkce“). Původně sice nebyl tento programovací jazyk skutečně implementován (na to si museli nadšenci počkat ještě zhruba padesát let), ovšem Plankalkül ovlivnil dalšího evropského průkopníka IT – Heinze Rutishausera, který v padesátých letech minulého století navrhl vyšší programovací jazyk nazvaný Superplan. A právě v tomto dnes již polozapomenutém programovacím jazyku se poprvé objevilo klíčové slovo für (tedy německá varianta for), zatímco tvůrci FORTRANu použili klíčové slovo do, jenž má dnes většinou poněkud jiný význam.

Heinz Rutishauser se později podílel na vzniku návrhu programovacího jazyka ALGOL 58, kde se pro počítanou programovou smyčku objevilo (v anglické verzi tohoto jazyka!) klíčové slovo for. ALGOL 58 sice nebyl příliš úspěšný, ovšem jeho nástupce ALGOL 60 již ano a právě odtud se slovo for dostalo jak do „pascalské větve“ (Pascal, Modula, Lua), tak i do „céčkové větve“ (C, C++, Java, JavaScript…) programovacích jazyků.

3. Příkaz return – ukončení běhu funkce/metody s předáním návratové hodnoty

Nejprve si ukážeme, jakým způsobem se do bajtkódu JVM, Lua VM a Python VM překládá příkaz pro návrat z funkce či metody. Tento příkaz se ve všech třech jazycích (Java, Lua i Python) zapisuje klíčovým slovem return, což vlastně není příliš překvapivé, protože toto slovo se v prakticky stejném významu používá v programovacích jazycích již zhruba po dobu padesáti let. Svůj původ má v podobně pojmenované strojové instrukci pro návrat ze subrutiny a podobně se chová i ve vyšších programovacích jazycích (zde se však liší návratové typy a některé jazyky mají sémantiku složitější kvůli existenci uzávěrů – closures). Podívejme se však na demonstrační příklady, z nichž bude patrný i rozdíl mezi všemi třemi popisovanými jazyky.

Demonstrační příklad Test12.java

V programovacím jazyku Java lze příkaz return uvést bez výrazu, ovšem pouze v případě, že se jedná o metodu typu void, tj. metodu bez návratové hodnoty. V opačném případě se musí za klíčové slovo return zapsat výraz odpovídající návratovému typu metody – což může být jeden z primitivních datových typů (boolean, char, byte, short, int, long, float, double) či referenční datový typ, tj. objekt:

/**
 * Ukazka zpusobu predavani navratovych hodnot
 * ze statickych metod.
 */
public class Test12 {
 
    /**
     * Navratova hodnota typu void.
     */
    static void returnVoid() {
        return;
    }
 
    /**
     * Navratova hodnota typu boolean.
     */
    static boolean returnBooleanTrue() {
        return true;
    }
 
    /**
     * Navratova hodnota typu boolean.
     */
    static boolean returnBooleanFalse() {
        return false;
    }
 
    /**
     * Navratova hodnota typu byte.
     */
    static byte returnByte() {
        return -1;
    }
 
    /**
     * Navratova hodnota typu char.
     */
    static char returnChar() {
        return 'a';
    }
 
    /**
     * Navratova hodnota typu short.
     */
    static short returnShort() {
        return 0;
    }
 
    /**
     * Navratova hodnota typu int.
     */
    static int returnInt() {
        return 1;
    }
 
    /**
     * Navratova hodnota typu long.
     */
    static long returnLong() {
        return 2L;
    }
 
    /**
     * Navratova hodnota typu float.
     */
    static float returnFloat() {
        return 3.0f;
    }
 
    /**
     * Navratova hodnota typu double.
     */
    static double returnDouble() {
        return 4.0;
    }
 
    /**
     * Navratova hodnota typu reference.
     */
    static Object returnReference() {
        return null;
    }
 
    /**
     * Vse je nutne otestovat.
     */
    public static void main(String[] args) {
        returnVoid();
        System.out.println(returnBooleanTrue());
        System.out.println(returnBooleanFalse());
        System.out.println(returnByte());
        System.out.println(returnChar());
        System.out.println(returnShort());
        System.out.println(returnInt());
        System.out.println(returnLong());
        System.out.println(returnFloat());
        System.out.println(returnDouble());
        System.out.println(returnReference());
    }
}

Demonstrační příklad Test12.lua

U programovacího jazyka Lua se díky dynamickému typování nemusí uvádět návratové typy funkcí, takže je použití příkazu return v tomto případě poněkud volnější, než tomu bylo v Javě. Příkaz lze uvést bez výrazu, s jedním výrazem či dokonce s několika výrazy. Výrazy mohou být jakéhokoli podporovaného typu, tj. nil (datový typ a současně i jeho jediná povolená hodnota), pravdivostní typ, číslo (celé i reálné), řetězec, tabulka (i asociativní pole) a posledním zajímavým typem je funkce:

--
-- Ukazka zpusobu predavani navratovych hodnot
-- z funkci
--
 
 
 
--
-- Funkce bez navratove hodnoty
--
function returnVoid()
    return
end
 
--
-- Funkce vracejici nil
--
function returnNil()
    return nil
end
 
--
-- Navratova hodnota typu Boolean.
--
function returnBooleanTrue()
    return true
end
 
--
-- Navratova hodnota typu Boolean.
--
function returnBooleanFalse()
    return false
end
 
--
-- Navratova hodnota Number.
--
function returnNumber1()
    return 42
end
 
--
-- Navratova hodnota Number.
--
function returnNumber2()
    return 42.0
end
 
--
-- Navratova hodnota typu String.
--
function returnString()
    return "Hello"
end
 
--
-- Navratova hodnota typu table.
--
function returnTable()
    return {1,2,3}
end
 
--
-- Navratova hodnota typu function.
--
function returnFunction()
    return function() print("Hello world!") end
end
 
--
-- Vse je nutne otestovat.
--
function main()
    print(returnVoid())
    print(returnNil())
    print(returnBooleanTrue())
    print(returnBooleanFalse())
    print(returnNumber1())
    print(returnNumber2())
    print(returnString())
    print(returnTable())
    print(returnFunction())
end
 
main()

Demonstrační příklad Test12.py

Pro programovací jazyk Python platí podobná pravidla pro použití příkazu return, jako tomu bylo v Lue. Zajímavé je, že lze vracet i strukturované datové typy seznam či n-tice a dokonce i lambda funkce (což na druhou stranu není tak překvapivé, ovšem v Javě jsme si museli na podobnou sémantiku počkat téměř dvacet let :-):

--
-- Ukazka zpusobu predavani navratovych hodnot
-- z funkci
--
 
 
 
--
-- Funkce bez navratove hodnoty
--
def returnVoid():
    return
 
--
-- Funkce vracejici None
--
def returnNone():
    return None
 
--
-- Navratova hodnota typu Boolean.
--
def returnBooleanTrue():
    return True
 
--
-- Navratova hodnota typu Boolean.
--
def returnBooleanFalse():
    return False
 
--
-- Navratova hodnota Number.
--
def returnNumber1():
    return 42
 
--
-- Navratova hodnota Number.
--
def returnNumber2():
    return 42.0
 
--
-- Navratova hodnota typu String.
--
def returnString():
    return "Hello"
 
--
-- Navratova hodnota typu tuple.
--
def returnTuple():
    return (1,2,3)
 
--
-- Navratova hodnota typu lambda (anonymni funkce).
--
def returnLambda():
    return lambda arg1, arg2: arg1 + arg2
 
--
-- Vse je nutne otestovat.
--
def main():
    print(returnVoid())
    print(returnNone())
    print(returnBooleanTrue())
    print(returnBooleanFalse())
    print(returnNumber1())
    print(returnNumber2())
    print(returnString())
    print(returnTuple())
    print(returnLambda())
 
--
-- Vypsani bajkkodu testovane funkce
--
def disassemble():
    from dis import dis
 
    print("\nreturnVoid:")
    dis(returnVoid)
 
    print("\nreturnNone:")
    dis(returnNone)
 
    print("\nreturnBooleanTrue:")
    dis(returnBooleanTrue)
 
    print("\nreturnBooleanFalse:")
    dis(returnBooleanFalse)
 
    print("\nreturnNumber1:")
    dis(returnNumber1)
 
    print("\nreturnNumber2:")
    dis(returnNumber2)
 
    print("\nreturnString:")
    dis(returnString)
 
    print("\nreturnTuple:")
    dis(returnTuple)
 
    print("\nreturnLambda:")
    dis(returnLambda)
 
main()
 
disassemble()

4. Ukázky překladu příkazu return do bajtkódu

V této kapitole budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test12.java, Test12.luaTest12.py.

Bajtkód demonstračního příkladu Test12.java

V bajtkódu JVM existuje několik instrukcí pro ukončení metody s případným předáním návratové hodnoty volající metodě (caller). Po provedení těchto instrukcí dojde ke zrušení celého zásobníkového rámce metody, z níž se vyskakuje, a řízení se předá volající metodě. Připomeňme si, že volající metoda si může návratovou hodnotu vyzvednout z vrcholu svého zásobníku operandů. Použití dále vypsaných instrukcí typu *return je jedinou možností, jak může volaná metoda modifikovat obsah zásobníku operandů metody volající – v ostatních případech jsou totiž zásobníky operandů (i datová oblast) obou metod od sebe izolovány, což přispívá jak k větší bezpečnosti, tak i k oddělení jednotlivých částí kódu. To samozřejmě zjednodušuje práci just-in-time překladače při provádění optimalizací. Ukončení metody s uložením návratové hodnoty zabezpečuje šestice instrukcí *return, která je vypsaná v následující tabulce:

# Instrukce Opkód Datový typ na TOS Operace
1 ireturn 0×AC int získání návratové hodnoty typu int z TOS zásobníku operandů + návrat z metody
2 lreturn 0×AD long získání návratové hodnoty typu long z TOS zásobníku operandů + návrat z metody
3 freturn 0×AE float získání návratové hodnoty typu float z TOS zásobníku operandů + návrat z metody
4 dreturn 0×AF double získání návratové hodnoty typu double z TOS zásobníku operandů + návrat z metody
5 areturn 0×B0 reference získání návratové hodnoty typu reference na objekt z TOS zásobníku operandů + návrat z metody
6 return 0×B1 × pouze návrat z metody, žádná hodnota se nevrací

Zajímavé je „přetížení“ instrukce ireturn i pro datové typy boolean, char, byte a short, což je ostatně patrné i z následujícího kódu:

Compiled from "Test12.java"
public class Test12 extends java.lang.Object{
 
static void returnVoid();
  Code:
   0:   return        // instrukce pro návrat z metody bez vrácení hodnoty
 
static boolean returnBooleanTrue();
  Code:
   0:   iconst_1      // uložení konstanty 1 (int) na zásobník operandů
   1:   ireturn       // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku
 
static boolean returnBooleanFalse();
  Code:
   0:   iconst_0      // uložení konstanty 0 (int) na zásobník operandů
   1:   ireturn       // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku
 
static byte returnByte();
  Code:
   0:   iconst_m1     // uložení konstanty -1 (int) na zásobník operandů
   1:   ireturn       // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku
 
static char returnChar();
  Code:
   0:   bipush  97    // uložení konstanty 97 (int) na zásobník operandů
   2:   ireturn       // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku
 
static short returnShort();
  Code:
   0:   iconst_0      // uložení konstanty 0 (int) na zásobník operandů
   1:   ireturn       // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku
 
static int returnInt();
  Code:
   0:   iconst_1      // uložení konstanty 1 (int) na zásobník operandů
   1:   ireturn       // instrukce pro návrat z metody s vrácením hodnoty typu int z vrcholu zásobníku
 
static long returnLong();
  Code:
   0:   ldc2_w  #2;   // konstanta typu long umístěná v constant poolu
   3:   lreturn       // instrukce pro návrat z metody s vrácením hodnoty typu long z vrcholu zásobníku
 
static float returnFloat();
  Code:
   0:   ldc     #4;   // konstanta typu float umístěná v constant poolu
   2:   freturn       // instrukce pro návrat z metody s vrácením hodnoty typu float z vrcholu zásobníku
 
static double returnDouble();
  Code:
   0:   ldc2_w  #5;   // konstanta typu double umístěná v constant poolu
   3:   dreturn       // instrukce pro návrat z metody s vrácením hodnoty typu double z vrcholu zásobníku
 
static java.lang.Object returnReference();
  Code:
   0:   aconst_null   // speciální instrukce pro uložení "null" na vrchol zásobníku
   1:   areturn       // instrukce pro návrat z metody s vrácením hodnoty typu reference z vrcholu zásobníku
 

Bajtkód demonstračního příkladu Test12.lua

V bajtkódu programovacího jazyka Lua je situace jednodušší, neboť se zde pro návrat z funkce používá jediná instrukce RETURN kompatibilní se všemi datovými typy. Nejprve je nutné načíst hodnotu příslušného typu do registru a posléze zavolat instrukci RETURN, které se předá mj. i počet registrů, jejichž hodnota se má předat volající funkci:

function <Test12.lua:11,13> (2 instructions at 0x9e8fc88)
0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions
        1       [12]    RETURN          0 1   // explicitní vrácení "ničeho" :-)
        2       [13]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:18,20> (3 instructions at 0x9e8fe38)
0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions
        1       [19]    LOADNIL         0 0   // pro hodnotu nil existuje specializovaná instrukce
        2       [19]    RETURN          0 2
        3       [20]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:25,27> (3 instructions at 0x9e8ff68)
0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions
        1       [26]    LOADBOOL        0 1 0 // hodnota false
        2       [26]    RETURN          0 2
        3       [27]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:32,34> (3 instructions at 0x9e8fde0)
0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions
        1       [33]    LOADBOOL        0 0 0 // hodnota true
        2       [33]    RETURN          0 2
        3       [34]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:39,41> (3 instructions at 0x9e90280)
0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions
        1       [40]    LOADK           0 -1  // číselná konstanta 42
        2       [40]    RETURN          0 2
        3       [41]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:46,48> (3 instructions at 0x9e90428)
0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions
        1       [47]    LOADK           0 -1  // číselná konstanta 42
        2       [47]    RETURN          0 2
        3       [48]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:53,55> (3 instructions at 0x9e90480)
0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions
        1       [54]    LOADK           0 -1  // řetězcová konstanta
        2       [54]    RETURN          0 2
        3       [55]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:60,62> (7 instructions at 0x9e90000)
0 params, 4 slots, 0 upvalues, 0 locals, 3 constants, 0 functions
        1       [61]    NEWTABLE        0 3 0 // konstruktor tabulky
        2       [61]    LOADK           1 -1    ; 1
        3       [61]    LOADK           2 -2    ; 2
        4       [61]    LOADK           3 -3    ; 3
        5       [61]    SETLIST         0 3 1 // přidání prvků do tabulky
        6       [61]    RETURN          0 2   // vrácení tabulky
        7       [62]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:67,69> (3 instructions at 0x9e906e8)
0 params, 2 slots, 1 upvalue, 0 locals, 0 constants, 1 function
        1       [68]    CLOSURE         0 0   // vrácení uzávěru
        2       [68]    RETURN          0 2
        3       [69]    RETURN          0 1   // vkládáno automaticky
 
function <Test12.lua:68,68> (4 instructions at 0x9e90740)
0 params, 2 slots, 1 upvalue, 0 locals, 2 constants, 0 functions
        1       [68]    GETTABUP        0 0 -1 // tělo uzávěru
        2       [68]    LOADK           1 -2    ; "Hello world!"
        3       [68]    CALL            0 2 1
        4       [68]    RETURN          0      // vkládáno automaticky

Bajtkód demonstračního příkladu Test12.py

Bajtkód Python VM taktéž používá univerzální instrukci RETURN_VALUE, nezávisle na datovém typu vrácené hodnoty:

returnVoid:
 12           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE
 
returnNone:
 18           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE
 
returnBooleanTrue:
 24           0 LOAD_GLOBAL              0 (True)
              3 RETURN_VALUE
 
returnBooleanFalse:
 30           0 LOAD_GLOBAL              0 (False)
              3 RETURN_VALUE
 
returnNumber1:
 36           0 LOAD_CONST               1 (42)
              3 RETURN_VALUE
 
returnNumber2:
 42           0 LOAD_CONST               1 (42.0)
              3 RETURN_VALUE
 
returnString:
 48           0 LOAD_CONST               1 ('Hello')
              3 RETURN_VALUE
 
returnTuple:
 54           0 LOAD_CONST               4 ((1, 2, 3)) // n-tice reprezentovaná konstantou
              3 RETURN_VALUE
 
returnLambda:
 60           0 LOAD_CONST               1 (code object lambda at 0xb773f968, file "Test12.py", line 60)
              3 MAKE_FUNCTION            0 // z kodu se vytvorila skutecna funkce
              6 RETURN_VALUE

5. Počítaná programová smyčka for

Nyní se budeme zabývat způsobem překladu počítané programové smyčky typu for o jejíž historii vzniku jsme se zmínili ve druhé kapitole. Rozdíly mezi jednotlivými programovacími jazyky budou napsány v navazujících podkapitolách:

Demonstrační příklad Test13.java

V programovacím jazyku Java je počítaná smyčka for realizována způsobem převzatým z programovacího jazyka C, tj. lze zadat jak inicializační výraz (výrazy), tak i podmínku ukončení smyčky a iterační příkaz:

/**
 * Jednoducha pocitana smycka typu for.
 */
public class Test13 {
 
    /**
     * Metoda s jednoduchou pocitanou smyckou typu for.
     */
    static int testForLoop() {
        int result = 0;
        for (int i = 0; i <= 10; i++) {
            result++;
        }
        return result;
    }
 
    /**
     * Vse je nutne otestovat.
     */
    public static void main(String[] args) {
        System.out.println(testForLoop());
    }
}

Demonstrační příklad Test13.lua

Programovací jazyk Lua se v případě počítané smyčky nechal inspirovat takovými jazyky, jako je Algol, Pascal, Modula či BASIC. Zadává se počáteční a koncová hodnota počitadla, nepovinně i přírůstek (který může být záporný, výchozí hodnota je samozřejmě 1):

--
-- Jednoducha pocitana smycka typu "for".
--
 
 
 
--
-- Funkce s jednoduchou pocitanou smyckou typu for.
--
function testForLoop()
    local result = 0
    for i = 0, 10 do
        result = result + 1
    end
    return result;
end
 
 
 
--
-- Vse je nutne otestovat.
--
function main()
    print(testForLoop())
end
 
main()

Demonstrační příklad Test13.py

Programovací jazyk Python sice počítanou smyčku for přímo nepodporuje, ale ve skutečnosti to ani není zapotřebí, neboť ji lze nahradit smyčkou typu for-each, které se předá nějaký objekt typu sekvence, typicky vytvořený přes xrange() (v Pythonu 3 pak range):

--
-- Jednoducha pocitana smycka typu for.
--
 
--
-- Funkce s jednoduchou pocitanou smyckou typu for.
--
def testForLoop():
    result = 0;
    for i in xrange(0,11):
        result = result + 1
    return result
 
--
-- Vse je nutne otestovat.
--
def main():
    print(testForLoop())
 
--
-- Vypsani bajkkodu testovane funkce
--
def disassemble():
    from dis import dis
 
    print("\ntestForLoop:")
    dis(testForLoop)
 
main()
 
disassemble()

6. Ukázky překladu jednoduché počítané smyčky typu for do bajtkódu

Nyní se podívejme na to, jakým způsobem se jednotlivé implementace počítané smyčky typu for přeložily do bajtkódu.

Bajtkód demonstračního příkladu Test13.java

U JVM je překlad proveden způsobem, s nímž jsme se již setkali minule při popisu smyček typu while, tj. s využitím nízkoúrovňových podmíněných i nepodmíněných skoků:

Compiled from "Test13.java"
public class Test13 extends java.lang.Object{
 
static int testForLoop();
  Code:
   0:   iconst_0               // počáteční hodnota proměnné result
   1:   istore_0
   2:   iconst_0               // počáteční hodnota počitadla
   3:   istore_1
   4:   iload_1                // začátek smyčky
   5:   bipush  10             // hodnota horní meze
   7:   if_icmpgt       19     // při překročení horní meze skok ZA konec smyčky
   10:  iinc    0, 1           // zvýšit hodnotu proměnné result
   13:  iinc    1, 1           // zvýšit hodnotu počitadla
   16:  goto    4              // nepodmíněný skok na začátek smyčky
   19:  iload_0
   20:  ireturn                // vrátit hodnotu proměnné result

Bajtkód demonstračního příkladu Test13.lua

Pravděpodobně nejzajímavější je bajtkód Lua VM, v němž jsou použity dvě specializované instrukce nazvané FORPREPFORLOOP. První z těchto instrukcí nejprve sníží hodnotu počitadla o krok, takže se například namísto počáteční hodnoty 0 bude v počitadle nacházet hodnota –1. Současně se po provedení této instrukce přesune řízení na instrukci FORLOOP (to není žádná magie, protože relativní adresa skoku je součástí instrukčního slova FORPREP). Celá smyčka je pak realizována instrukcí FORLOOP, která zvýší hodnotu počitadla o krok, provede porovnání aktuální hodnoty počitadla s horní mezí a popř. provede skok na začátek smyčky, tedy za instrukci nacházející se těsně za FORPREP. Výsledkem je velmi elegantní bajtkód:

function <Test13.lua:10,16> (9 instructions at 0x9f49c88)
0 params, 5 slots, 0 upvalues, 5 locals, 3 constants, 0 functions
        1       [11]    LOADK           0 -1    ; 0    // počáteční hodnota proměnné result
        2       [12]    LOADK           1 -1    ; 0    // počáteční hodnota počitadla
        3       [12]    LOADK           2 -2    ; 10   // hodnota horní meze
        4       [12]    LOADK           3 -3    ; 1    // krok smyčky
        5       [12]    FORPREP         1 1     ; to 7 // příprava na smyčku snížení hodnoty počitadla o krok
                                                       // a skok na iterační příkaz
        6       [13]    ADD             0 0 -3  ; - 1  // zvýšit hodnotu proměnné result
        7       [12]    FORLOOP         1 -2    ; to 6 // provedení iterace - zvýšení hodnoty počitadla
                                                       // test a případný skok na instrukci číslo 6
        8       [15]    RETURN          0 2            // vrátit hodnotu proměnné result
        9       [16]    RETURN          0 1            // automaticky generovaný návrat z funkce

Bajtkód demonstračního příkladu Test13.py

U bajtkódu programovacího jazyka Python jsou taktéž použity specializované instrukce bajtkódu nazvané GET_ITERFOR_ITER. Ty jsou použity ve všech typech smyčky for-each, zde konkrétně pro práci s objektem vytvořeným funkcí/konstruktorem xrange:

testForLoop:
  9           0 LOAD_CONST               1 (0)        // počáteční hodnota proměnné result
              3 STORE_FAST               0 (result)
 
 10           6 SETUP_LOOP              33 (to 42)    // konstrukce programové smyčky
              9 LOAD_GLOBAL              0 (xrange)   // příprava na volání xrange()
             12 LOAD_CONST               1 (0)        // dolní mez
             15 LOAD_CONST               2 (11)       // horní mez
             18 CALL_FUNCTION            2            // zavolání xrange()
             21 GET_ITER
             22 FOR_ITER                16 (to 41)    // vlastní smyčka
             25 STORE_FAST               1 (i)
 
 11          28 LOAD_FAST                0 (result)   // *
             31 LOAD_CONST               3 (1)        // * result = result + 1
             34 BINARY_ADD                            // *
             35 STORE_FAST               0 (result)   // *
             38 JUMP_ABSOLUTE           22            // další iterace (skok na začátek smyčky)
             41 POP_BLOCK                             // úklid po ukončení smyčky
 
 12          42 LOAD_FAST                0 (result)
             45 RETURN_VALUE                          // vrátit hodnotu proměnné result

7. Složitější programová smyčka typu for – výpočet faktoriálu

Počítaná smyčka for použitá v předchozích demonstračních příkladech vlastně představovala nejjednodušší formu této řídicí struktury. Nyní se podíváme na praktičtější příklad – výpočet faktoriálu. Zde je již nutné, aby se uvnitř smyčky využívala aktuální hodnota počitadla.

Demonstrační příklad Test14.java

Implementace výpočtu faktoriálu s využitím iterační smyčky je v Javě přímočará:

/**
 * Jednoducha pocitana smycka typu "for"
 * pouzita pro vypocet faktorialu.
 */
public class Test14 {
 
    /**
     * Vypocet faktorialu pocitanou smyckou
     * typu "for".
     */
    static int factorial(int n) {
        int result = 1;
        for (int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }
 
    /**
     * Vse je nutne otestovat.
     */
    public static void main(String[] args) {
        for (int n = 0; n <= 10; n++) {
            System.out.println(n + "\t" + factorial(n));
        }
    }
}

Demonstrační příklad Test14.lua

Totéž platí i pro programovací jazyk Lua:

--
-- Jednoducha pocitana smycka typu "for"
-- pouzita pro vypocet faktorialu.
--
 
 
 
--
-- Vypocet faktorialu pocitanou smyckou
-- typu "for".
--
function factorial(n)
    local result = 1
    for i = 2, n do
        result = result * i
    end
    return result;
end
 
 
 
--
-- Vse je nutne otestovat.
--
function main()
    for n = 0, 10 do
        print(n .. "\t" .. factorial(n))
    end
end
 
main()

Demonstrační příklad Test14.py

Ani v případě programovacího jazyka Python není zapotřebí používat žádné složitější jazykové konstrukce:

--
-- Jednoducha pocitana smycka typu for
-- pouzita pro vypocet faktorialu.
--
 
--
-- Vypocet faktorialu pocitanou smyckou
-- typu "for".
--
def factorial(n):
    result = 1;
    for i in xrange(2, n+1):
        result = result * i
    return result
 
--
-- Vse je nutne otestovat.
--
def main():
    for n in xrange(0, 11):
        print "%d\t%d" % (n, factorial(n))
 
--
-- Vypsani bajkkodu testovane funkce
--
def disassemble():
    from dis import dis
 
    print("\nfactorial:")
    dis(factorial)
main()
 
disassemble()

V dalším textu budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test14.java, Test14.luaTest14.py.

Bajtkód demonstračního příkladu Test14.java

U JVM se výpočet faktoriálu provádí v bajtkódu opět s využitím nízkoúrovňových podmíněných i nepodmíněných skoků:

Compiled from "Test14.java"
public class Test14 extends java.lang.Object{
 
static int factorial(int);
  Code:
   0:   iconst_1               // počáteční hodnota proměnné result
   1:   istore_1
   2:   iconst_2               // počáteční hodnota počitadla
   3:   istore_2
   4:   iload_2                // začátek smyčky
   5:   iload_0                // hodnota horní meze je předána v parametru
   6:   if_icmpgt       19     // při překročení horní meze skok ZA konec smyčky
   9:   iload_1
   10:  iload_2
   11:  imul                   // vynásobit hodnotu proměnné result aktuální hodnotou počitadla
   12:  istore_1
   13:  iinc    2, 1           // zvýšit hodnotu počitadla
   16:  goto    4              // nepodmíněný skok na začátek smyčky
   19:  iload_1
   20:  ireturn                // vrátit hodnotu proměnné result

Bajtkód demonstračního příkladu Test14.lua

U programovacího jazyka Lua nalezneme v bajtkódu podle očekávání instrukce FORPREPFORLOOP:

function <Test14.lua:12,18> (9 instructions at 0x869ec88)
1 param, 6 slots, 0 upvalues, 6 locals, 2 constants, 0 functions
        1       [13]    LOADK           1 -1    ; 1    // počáteční hodnota proměnné result
        2       [14]    LOADK           2 -2    ; 2    // počáteční hodnota počitadla
        3       [14]    MOVE            3 0            // přesun parametru (horní mez) do registru 3
        4       [14]    LOADK           4 -1    ; 1    // krok smyčky
        5       [14]    FORPREP         2 1     ; to 7 // příprava na smyčku snížení hodnoty počitadla o krok
                                                       // a skok na iterační příkaz
        6       [15]    MUL             1 1 5          // tělo smyčky zkrácené na jedinou instrukci
        7       [14]    FORLOOP         2 -2    ; to 6 // provedení iterace - zvýšení hodnoty počitadla
                                                       // test a případný skok na instrukci číslo 6
        8       [17]    RETURN          1 2            // vrátit hodnotu proměnné result
        9       [18]    RETURN          0 1            // automaticky generovaný návrat z funkce

Bajtkód demonstračního příkladu Test14.py

V případě bajtkódu Pythonu se pro konstrukci smyčky používají speciální instrukce GET_ITERFOR_ITER:

factorial:
 11           0 LOAD_CONST               1 (1)        // počáteční hodnota proměnné result
              3 STORE_FAST               1 (result)
 
 12           6 SETUP_LOOP              37 (to 46)    // konstrukce programové smyčky
              9 LOAD_GLOBAL              0 (xrange)   // příprava na volání xrange()
             12 LOAD_CONST               2 (2)        // dolní mez
             15 LOAD_FAST                0 (n)        // horní mez
             18 LOAD_CONST               1 (1)        // (n+1)
             21 BINARY_ADD
             22 CALL_FUNCTION            2            // zavolání xrange()
             25 GET_ITER
             26 FOR_ITER                16 (to 45)    // vlastní smyčka
             29 STORE_FAST               2 (i)
 
 13          32 LOAD_FAST                1 (result)   // *
             35 LOAD_FAST                2 (i)        // * result = result * n
             38 BINARY_MULTIPLY                       // *
             39 STORE_FAST               1 (result)   // *
             42 JUMP_ABSOLUTE           26            // další iterace (skok na začátek smyčky)
             45 POP_BLOCK                             // úklid po ukončení smyčky
 
 14          46 LOAD_FAST                1 (result)
             49 RETURN_VALUE                          // vrátit hodnotu proměnné result

8. Překlad vnořených počítaných smyček typu for do bajtkódu

Dalším typickým příkladem z praxe je použití dvou vnořených počítaných smyček typu for. V dnešním třetím demonstračním příkladu se bude jednat o velmi jednoduchý (a v případě výpisu výsledků i naivní) algoritmus pro tisk malé násobilky.

Demonstrační příklad Test15.java

V případě Javy je tento algoritmus přímočarý (pro jednoduchost ignorujme znak [TAB] na konci každého řádku):

/**
 * Vnorene smycky typu "for".
 */
public class Test15 {
 
    /**
     * Staticka metoda s dvojici vnorenych
     * programovych smycek typu "for".
     */
    static void testNestedForLoops() {
        for (int j = 1; j <= 10; j++) {
            for (int i = 1; i <= 10; i++) {
                System.out.print(i * j);
                System.out.print('\t');
            }
            System.out.println();
        }
    }
 
    /**
     * Vse je nutne otestovat.
     */
    public static void main(String[] args) {
        testNestedForLoops();
    }
}

Demonstrační příklad Test15.lua

V programovacím jazyku Lua je nutné pro tisk bez odřádkování použít funkci io.write() namísto print():

--
-- Vnorene smycky typu "for".
--
 
 
 
--
-- Funkce s dvojici vnorenych
-- programovych smycek typu "for".
--
function testNestedForLoops()
    for j = 1,10 do
        for i = 1,10 do
            io.write(i * j)
            io.write('\t')
        end
        print()
    end
end
 
 
 
--
-- Vse je nutne otestovat.
--
function main()
    testNestedForLoops();
end
 
main()

Demonstrační příklad Test15.py

Podobně je tomu v programovacím jazyku Python, kde se namísto příkazu/funkce print() musí použít například sys.stdout.write():

--
-- Vnorene smycky typu "for".
--
 
import sys
 
--
-- Funkce s dvojici vnorenych
-- programovych smycek typu "for".
--
def testNestedForLoops():
    for j in xrange(1,11):
        for i in xrange(1,11):
            sys.stdout.write(str(i * j))
            sys.stdout.write("\t")
        print("")
 
--
-- Vse je nutne otestovat.
--
def main():
    testNestedForLoops();
 
--
-- Vypsani bajkkodu testovane funkce
--
def disassemble():
    from dis import dis
 
    print("\ntestNestedForLoops:")
    dis(testNestedForLoops)
main()
 
disassemble()

V dalším textu budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test15.java, Test15.luaTest15.py.

Bajtkód demonstračního příkladu Test15.java

V bajtkódu JVM je jasně viditelná struktura obou programových smyček:

Compiled from "Test15.java"
public class Test15 extends java.lang.Object{
public Test15();
 
static void testNestedForLoops();
  Code:
   0:   iconst_1
   1:   istore_0
   2:   iload_0             // začátek vnější smyčky
   3:   bipush  10          // hodnota horní meze vnější smyčky
   5:   if_icmpgt       51  // při překročení horní meze skok ZA konec smyčky
   8:   iconst_1
   9:   istore_1
   10:  iload_1             // začátek vnitřní smyčky
   11:  bipush  10          // hodnota horní meze vnitřní smyčky
   13:  if_icmpgt       39  // při překročení horní meze skok ZA konec smyčky
   16:  getstatic       #2; // Field java/lang/System.out:Ljava/io/PrintStream;
   19:  iload_1
   20:  iload_0
   21:  imul
   22:  invokevirtual   #3; // Method java/io/PrintStream.print:(I)V
   25:  getstatic       #2; // Field java/lang/System.out:Ljava/io/PrintStream;
   28:  bipush  9
   30:  invokevirtual   #4; // Method java/io/PrintStream.print:(C)V
   33:  iinc    1, 1        // zvýšit hodnotu počitadla vnitřní smyčky
   36:  goto    10          // nepodmíněný skok na začátek vnitřní smyčky
   39:  getstatic       #2; // Field java/lang/System.out:Ljava/io/PrintStream;
   42:  invokevirtual   #5; // Method java/io/PrintStream.println:()V
   45:  iinc    0, 1        // zvýšit hodnotu počitadla vnější smyčky
   48:  goto    2           // nepodmíněný skok na začátek vnější smyčky
   51:  return              // návrat z metody

Bajtkód demonstračního příkladu Test15.lua

I v případě bajtkódu Lua VM získáme přehledně strukturovaný bajtkód:

function <Test15.lua:11,19> (21 instructions at 0x9356cb0)
0 params, 10 slots, 1 upvalue, 8 locals, 6 constants, 0 functions
        1       [12]    LOADK           0 -1    ; 1         // počáteční hodnota počitadla
        2       [12]    LOADK           1 -2    ; 10        // horní mez vnější smyčky
        3       [12]    LOADK           2 -1    ; 1         // krok vnější smyčky
        4       [12]    FORPREP         0 15    ; to 20     // přípravný krok pro vnější smyčku
        5       [13]    LOADK           4 -1    ; 1         // počáteční hodnota počitadla
        6       [13]    LOADK           5 -2    ; 10        // horní mez vnitřní smyčky
        7       [13]    LOADK           6 -1    ; 1         // krok vnitřní smyčky
        8       [13]    FORPREP         4 8     ; to 17     // přípravný krok pro vnitřní smyčku
        9       [14]    GETTABUP        8 0 -3  ; _ENV "io"
        10      [14]    GETTABLE        8 8 -4  ; "write"
        11      [14]    MUL             9 7 3
        12      [14]    CALL            8 2 1               // zavolání funkce io.write()
        13      [15]    GETTABUP        8 0 -3  ; _ENV "io"
        14      [15]    GETTABLE        8 8 -4  ; "write"
        15      [15]    LOADK           9 -5    ; "\t"
        16      [15]    CALL            8 2 1               // zavolání funkce io.write()
        17      [13]    FORLOOP         4 -9    ; to 9      // vnitřní smyčka – začátek další iterace
        18      [17]    GETTABUP        4 0 -6  ; _ENV "print"
        19      [17]    CALL            4 1 1               // zavolání funkce print()
        20      [12]    FORLOOP         0 -16   ; to 5      // vnější smyčka – začátek další iterace
        21      [19]    RETURN          0 1                 // automaticky generovaný návrat z funkce

Bajtkód demonstračního příkladu Test14.py

Nyní se podívejme na bajtkód vygenerovaný pro Python VM:

testNestedForLoops:
 12           0 SETUP_LOOP              96 (to 99)    // konstrukce vnější programové smyčky
              3 LOAD_GLOBAL              0 (xrange)
              6 LOAD_CONST               1 (1)        // dolní mez
              9 LOAD_CONST               2 (11)       // horní mez
             12 CALL_FUNCTION            2            // zavolání xrange()
             15 GET_ITER
             16 FOR_ITER                79 (to 98)    // vlastní vnější smyčka
             19 STORE_FAST               0 (j)
 
 13          22 SETUP_LOOP              65 (to 90)    // konstrukce vnitřní programové smyčky
             25 LOAD_GLOBAL              0 (xrange)
             28 LOAD_CONST               1 (1)        // dolní mez
             31 LOAD_CONST               2 (11)       // horní mez
             34 CALL_FUNCTION            2            // zavolání xrange()
             37 GET_ITER
             38 FOR_ITER                48 (to 89)    // vlastní vnitřní smyčka
             41 STORE_FAST               1 (i)
 
 14          44 LOAD_GLOBAL              1 (sys)
             47 LOAD_ATTR                2 (stdout)
             50 LOAD_ATTR                3 (write)
             53 LOAD_GLOBAL              4 (str)
             56 LOAD_FAST                1 (i)
             59 LOAD_FAST                0 (j)
             62 BINARY_MULTIPLY
             63 CALL_FUNCTION            1            // zavolání str()
             66 CALL_FUNCTION            1            // zavolání sys.stdout.write()
             69 POP_TOP
 
 15          70 LOAD_GLOBAL              1 (sys)
             73 LOAD_ATTR                2 (stdout)
             76 LOAD_ATTR                3 (write)
             79 LOAD_CONST               3 ('\t')
             82 CALL_FUNCTION            1            // zavolání sys.stdout.write()
             85 POP_TOP
             86 JUMP_ABSOLUTE           38            // další iterace (skok na začátek vnitřní smyčky)
             89 POP_BLOCK                             // úklid po ukončení smyčky
 
 16          90 LOAD_CONST               4 ('')
             93 PRINT_ITEM
             94 PRINT_NEWLINE                         // zavolání print()
             95 JUMP_ABSOLUTE           16            // další iterace (skok na začátek vnější smyčky)
             98 POP_BLOCK                             // úklid po ukončení smyčky
             99 LOAD_CONST               0 (None)
            102 RETURN_VALUE                          // návrat se speciální hodnotou None

9. Příkazy breakcontinue, popř. jejich ekvivalenty

S programovými smyčkami všech typů (počítané i nepočítané) poměrně úzce souvisí i příkazy breakcontinue sloužící buď k ukončení běhu smyčky popř. k přeskočení zbytku těla smyčky a zahájení nové iterace. Oba zmíněné příkazy jsou podporovány v Javě a Pythonu, ovšem v případě programovacího jazyka Lua je nutné příkaz continue nahradit programovou logikou, v současné verzi jazyka velmi pravděpodobně příkazem goto.

Demonstrační příklad Test16.java

Následující demonstrační příklad pouze ukazuje možnosti příkazů breakcontinue, protože implementovaný algoritmus ve skutečnosti nemá žádný větší význam:

/**
 * Vnorene smycky typu "for"
 * spolecne s prikazy "break" a "continue".
 */
public class Test16 {
 
    /**
     * Staticka metoda s dvojici vnorenych
     * programovych smycek typu "for".
     */
    static void testNestedForLoops() {
        for (int y = 0; y < 10; y++) {
            if (y < 5) continue;
            for (int x = 0; x < 10; x++) {
                if (x == 5) break;
            }
        }
    }
}

Demonstrační příklad Test16.lua

Implementace téhož algoritmu v programovacím jazyku Lua vyžaduje použití příkazu goto na návěští umístěné na konci těla smyčky. Návěští se podle upravené syntaxe zapisuje se „čtyřtečkou“ na začátku i na konci jeho jména:

--
-- Vnorene smycky typu "for"
-- spolecne s prikazy "break" a "continue".
--
 
--
-- Funlkce s dvojici vnorenych
-- programovych smycek typu "for".
--/
function testNestedForLoops()
    for y = 0, 9 do
        if y < 5 then
            goto continue
        end
        for x = 0, 9 do
            if x == 5 then
                break
            end
        end
        ::continue::
    end
end

Demonstrační příklad Test16.py

Implementace původního algoritmu v Pythonu je prakticky stejná jako tomu bylo v Javě, pokud tedy odhlédneme od použití funkce xrange() a poněkud odlišné (elegantnější :-) syntaxe:

--
-- Vnorene smycky typu "for"
-- spolecne s prikazy "break" a "continue".
--
 
--
-- Funkce s dvojici vnorenych
-- programovych smycek typu "for".
--
def testNestedForLoops():
    for y in xrange(1,11):
        if y ==5:
            continue
        for x in xrange(1,11):
            if x == 5:
                break
 
--
-- Vypsani bajkkodu testovane funkce
--
def disassemble():
    from dis import dis
 
    print("\ntestNestedForLoops:")
    dis(testNestedForLoops)
 
disassemble()

10. Překlad příkazů typu breakcontinue do bajtkódu

V této kapitole budou ukázány okomentované bajtkódy získané překladem demonstračních příkladů Test16.java, Test16.luaTest16.py.

Bajtkód demonstračního příkladu Test16.java

V bajtkódu vytvořeného pro JVM můžeme vidět použití nepodmíněných i podmíněných skoků; takto generovaný bajtkód do značné míry připomíná strojový kód mnoha typů mikroprocesorů:

static void testNestedForLoops();
  Code:
   0:   iconst_0        // inicializace počitadla vnější smyčky
   1:   istore_0        // jedná se o první lokální proměnnou (s viditelností jen uvnitř smyčky)
 
   2:   iload_0         // podmínka ukončení vnější smyčky
   3:   bipush  10      // konstanta představující hodnotu počitadla, při jejímž dosažení se smyčka ukončí
   5:   if_icmpge   44  // počitadlo dosáhlo mezní hodnoty - skok ZA konec vnější smyčky
 
   8:   iload_0         // implementace podmínky "if (y < 5) continue;"
   9:   iconst_5        // konstanta, s níž je hodnota počitadla srovnávána
   10:  if_icmpge   16
   13:  goto    38      // skok ZA konec vnitřní smyčky
 
   16:  iconst_0        // inicializace počitadla vnitřní smyčky
   17:  istore_1        // jedná se o druhou lokální proměnnou (s viditelností jen uvnitř smyčky)
 
   18:  iload_1         // podmínka ukončení vnitřní smyčky
   19:  bipush  10      // konstanta představující hodnotu počitadla, při jejímž dosažení se smyčka ukončí
   21:  if_icmpge   38  // počitadlo dosáhlo mezní hodnoty - skok ZA konec vnitřní smyčky 
 
   24:  iload_1         // implementace podmínky "if (x == 5) break;"
   25:  iconst_5        // konstanta, s níž je hodnota počitadla srovnávána
   26:  if_icmpne   32
   29:  goto    38      // skok ZA konec vnitřní smyčky
 
   32:  iinc    1, 1    // zvýšení počitadla vnitřní smyčky
   35:  goto    18      // další iterace vnitřní smyčky
 
   38:  iinc    0, 1    // zvýšení počitadla vnější smyčky
   41:  goto    2       // další iterace vnější smyčky
 
   44:  return

Bajtkód demonstračního příkladu Test16.lua

V případě programovacího jazyka Lua je do sekvence instrukcí s dvojicí do sebe vnořených programových smyček vložena i dvojice skoků; první pro implementaci continue, druhý pro implementaci break:

ict ve školství 24

function <Test16.lua:10,22> (15 instructions at 0x8862cb0)
0 params, 8 slots, 0 upvalues, 8 locals, 4 constants, 0 functions
        1       [11]    LOADK           0 -1    ; 0         // počáteční hodnota počitadla
        2       [11]    LOADK           1 -2    ; 9         // horní mez vnější smyčky
        3       [11]    LOADK           2 -3    ; 1         // krok vnější smyčky
        4       [11]    FORPREP         0 9     ; to 14     // přípravný krok pro vnější smyčku
        5       [12]    LT              1 3 -4  ; - 5
        6       [12]    JMP             0 7     ; to 14     // implementace "continue"
        7       [15]    LOADK           4 -1    ; 0         // počáteční hodnota počitadla
        8       [15]    LOADK           5 -2    ; 9         // horní mez vnitřní smyčky
        9       [15]    LOADK           6 -3    ; 1         // krok vnitřní smyčky
        10      [15]    FORPREP         4 2     ; to 13     // přípravný krok pro vnitřní smyčku
        11      [16]    EQ              1 7 -4  ; - 5
        12      [16]    JMP             0 1     ; to 14     // implementace "break"
        13      [15]    FORLOOP         4 -3    ; to 11     // vnitřní smyčka – začátek další iterace
        14      [11]    FORLOOP         0 -10   ; to 5      // vnější smyčka – začátek další iterace
        15      [22]    RETURN          0 1                 // automaticky generovaný návrat z funkce

Bajtkód demonstračního příkladu Test16.py

Podobně je tomu i v případě bajtkódu vytvořeného pro Python VM:

testNestedForLoops:
 11           0 SETUP_LOOP              87 (to 90)    // konstrukce vnější programové smyčky
              3 LOAD_GLOBAL              0 (xrange)
              6 LOAD_CONST               1 (1)        // dolní mez
              9 LOAD_CONST               2 (11)       // horní mez
             12 CALL_FUNCTION            2            // zavolání xrange()
             15 GET_ITER
             16 FOR_ITER                70 (to 89)    // vlastní vnější smyčka
             19 STORE_FAST               0 (y)
 
 12          22 LOAD_FAST                0 (y)
             25 LOAD_CONST               3 (5)
             28 COMPARE_OP               2 (==)
             31 JUMP_IF_FALSE            7 (to 41)    // implementace "continue"
             34 POP_TOP
 
 13          35 JUMP_ABSOLUTE           16
             38 JUMP_FORWARD             1 (to 42)
             41 POP_TOP
 
 14          42 SETUP_LOOP              41 (to 86)    // konstrukce vnitřní programové smyčky
             45 LOAD_GLOBAL              0 (xrange)
             48 LOAD_CONST               1 (1)        // dolní mez
             51 LOAD_CONST               2 (11)       // horní mez
             54 CALL_FUNCTION            2            // zavolání xrange()
             57 GET_ITER
             58 FOR_ITER                24 (to 85)    // vlastní vnitřní smyčka
             61 STORE_FAST               1 (x)
 
 15          64 LOAD_FAST                1 (x)
             67 LOAD_CONST               3 (5)
             70 COMPARE_OP               2 (==)
             73 JUMP_IF_FALSE            5 (to 81)    // implementace "break"
             76 POP_TOP
 
 16          77 BREAK_LOOP
             78 JUMP_ABSOLUTE           58
             81 POP_TOP
             82 JUMP_ABSOLUTE           58
             85 POP_BLOCK                             // úklid po ukončení smyčky
             86 JUMP_ABSOLUTE           16
             89 POP_BLOCK                             // úklid po ukončení smyčky
             90 LOAD_CONST               0 (None)
             93 RETURN_VALUE                          // návrat se speciální hodnotou None

11. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů

Všechny dnes popsané a využité demonstrační příklady (naprogramované v Javě, Lue i Pythonu) byly uloženy do Mercurial repositáře umístěného na adrese http://icedtea.classpath.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 Test12.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/26b4e0c08aec/by­tecode/Java/Test12.java
2 Test12.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/aebd1be349ad/by­tecode/Lua/Test12.lua
3 Test12.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ec224922e4b/by­tecode/Python/Test12.py
     
4 Test13.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ecb2c719334/by­tecode/Java/Test13.java
5 Test13.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/aebd1be349ad/by­tecode/Lua/Test13.lua
6 Test13.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ec224922e4b/by­tecode/Python/Test13.py
     
7 Test14.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ecb2c719334/by­tecode/Java/Test14.java
8 Test14.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/aebd1be349ad/by­tecode/Lua/Test14.lua
9 Test14.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ec224922e4b/by­tecode/Python/Test14.py
     
10 Test15.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ecb2c719334/by­tecode/Java/Test15.java
11 Test15.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/aebd1be349ad/by­tecode/Lua/Test15.lua
12 Test15.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ec224922e4b/by­tecode/Python/Test15.py
     
13 Test16.java http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ecb2c719334/by­tecode/Java/Test16.java
14 Test16.lua http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/aebd1be349ad/by­tecode/Lua/Test16.lua
15 Test16.py http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/file/1ec224922e4b/by­tecode/Python/Test16.py

12. Odkazy na Internetu

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

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.