Pohled pod kapotu JVM – složené datové typy a programová smyčka typu for-each v JVM

Pavel Tišnovský 15. 7. 2014

V dnešní části seriálu o JVM i o programovacím jazyku Java si řekneme, jakým způsobem se do bajtkódu virtuálního stroje Javy překládá programová smyčka typu „for-each“. Použití této smyčky si ukážeme na čtveřici demonstračních příkladů využívajících pole, seznamy, množiny i mapy.

Obsah

1. Pohled pod kapotu JVM – složené datové typy a programová smyčka typu „for-each“ v JVM, Lua VM a Python VM

2. Programová smyčka typu „for-each“ v programovacím jazyku Java

3. Demonstrační příklad Test23.java: pole a smyčka typu „for-each“ v JVM

4. Okomentovaný bajtkód demonstračního příkladu Test23.java

5. Demonstrační příklad Test24.java: seznamy a programová smyčka typu „for-each“ v JVM

6. Okomentovaný bajtkód demonstračního příkladu Test24.java

7. Demonstrační příklad Test25.java: množiny a programová smyčka typu „for-each“ v JVM

8. Okomentovaný bajtkód demonstračního příkladu Test25.java

9. Demonstrační příklad Test26.java: mapy a programová smyčka typu „for-each“ v JVM

10. Okomentovaný bajtkód demonstračního příkladu Test26.java

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

12. Odkazy na Internetu

1. Pohled pod kapotu JVM – složené datové typy a programová smyčka typu „for-each“ v JVM, Lua VM a Python VM

V předchozích dvou částech seriálu o programovacím jazyce Java i o JVM jsme si řekli, jakým způsobem se do bajtkódů virtuálních strojů Javy, Pythonu i jazyka Lua překládají základní operace se složenými datovými typy. Jedná se především o operace pro čtení a popř. i zápis prvků složených datových typů (polí, tabulek, seznamů, n-tic) a taktéž o operaci získání celkového počtu prvků daného složeného datového typu. V některých demonstračních příkladech jsme si taktéž ukázali způsob použití počítané programové smyčky typu for při přístupu k prvkům složených datových typů. Ve skutečnosti se ovšem velké množství operací (pravděpodobně většina operací) se složenými datovými typy neprovádí s využitím počítané smyčky typu for, ale spíše s použitím smyčky typu for-each, která je v určité podobě implementována ve všech třech virtuálních strojích (JVM, Lua VM i Python VM).

Dnes si na čtveřici demonstračních příkladů ukážeme, jakým způsobem se programová smyčka typu for-each používá a překládá v Javě. V navazující části tohoto seriálu na dnešní díl navážeme, protože si ukážeme ekvivalentní příklady, ovšem naprogramované v Pythonu, programovacím jazyce Lua a nově taktéž v Perlu 6.

2. Programová smyčka typu „for-each“ v programovacím jazyku Java

Programová smyčka typu for-each se v programovacím jazyku Java objevila ve verzi/specifikaci 5.0. Jednalo se o jedno z několika rozšíření tohoto jazyka, které bylo vyžadováno jak komunitou vývojářů, tak i de facto vynuceno situací na trhu, na němž se začaly ve větší míře prosazovat konkurenční programovací jazyky, především C# a taktéž dosti velká skupina vysokoúrovňových skriptovacích jazyků (Python, Ruby, …). Smyčku typu for-each lze v Javě využít pro postupné procházení všech prvků polí. Syntaxe v tomto případě vypadá následovně:

for (type variable : array) {
    tělo smyčky
}

Výše uvedený zápis smyčky je do značné míry ekvivalentní počítané smyčce typu for, ovšem s tím rozdílem, že programátor nemá v předchozí verzi smyčky přístup k počitadlu i (hodnotu počitadla lze využít například při tvorbě tabulek atd.):

for (int i = 0; i < array.length; i++) {
    type variable = array[i];
    tělo smyčky
}

Kromě polí je možné programovou smyčku typu for-each použít i pro procházení všemi prvky kolekcí. Zápis je v tomto případě prakticky shodný se zápisem smyčky pro průchod všemi prvky pole:

for (type variable : collection) {
    tělo smyčky
}

Tento zápis je ekvivalentní následujícímu zápisu; ovšem opět s tím rozdílem, že ve zkrácené for-each variantě nemá programátor přímý přístup k iterátoru, což může v některých případech komplikovat zápis algoritmu:

for (Iterator<type> iterator = collection.iterator(); iterator.hasNext(); ) {
    type variable = iterator.next();
    tělo smyčky
}

Ve skutečnosti se však použití smyčky for-each neomezuje pouze na pole a kolekce, ale lze ji využít pro instance všech tříd implementujících rozhraní Iterable<T>, tj. pro ty třídy, v nichž je implementována metoda Iterator<T> iterator(). Díky tomuto rozšíření sémantiky smyčky for-each lze implementovat například různé typy průchodů binárními stromy atd.

3. Demonstrační příklad Test23.java: pole a smyčka typu „for-each“ v JVM

Způsob překladu programové smyčky typu for-each do bajtkódu JVM si nejlépe ukážeme na několika demonstračních příkladech. V prvním demonstračním příkladu, který nese název Test23.java, je implementována přetížená metoda sum(), v jejímž těle se vypočítá suma/součet všech prvků pole, které je do této metody předáno (jako reference). Metoda je přetížená pro všech šest primitivních numerických datových typů – byte, short, int, long, float i double. Navíc je v tomto příkladu implementována i metoda hashsum(), v níž se vypočte součet hešovacích kódů všech objektů uložených v poli předaném do této metody. Ve všech zmíněných metodách je využita smyčka typu for-each pro průchod všemi prvky pole, nezávisle na typu prvků:

/**
 * Demonstracni priklad cislo 23.
 *
 * Pole a programova smycka typu for-each.
 */
public class Test23 {
 
    /**
     * Vypocet souctu vsech prvku pole typu byte[].
     */
    static int sum(byte[] array) {
        int sum = 0;
        for (byte item : array) {
            sum += item;
        }
        return sum;
    }
 
    /**
     * Vypocet souctu vsech prvku pole typu short[].
     */
    static int sum(short[] array) {
        int sum = 0;
        for (short item : array) {
            sum += item;
        }
        return sum;
    }
 
    /**
     * Vypocet souctu vsech prvku pole typu int[].
     */
    static int sum(int[] array) {
        int sum = 0;
        for (int item : array) {
            sum += item;
        }
        return sum;
    }
 
    /**
     * Vypocet souctu vsech prvku pole typu long[].
     */
    static long sum(long[] array) {
        long sum = 0;
        for (long item : array) {
            sum += item;
        }
        return sum;
    }
 
    /**
     * Vypocet souctu vsech prvku pole typu float[].
     */
    static float sum(float[] array) {
        float sum = 0;
        for (float item : array) {
            sum += item;
        }
        return sum;
    }
 
    /**
     * Vypocet souctu vsech prvku pole typu double[].
     */
    static double sum(double[] array) {
        double sum = 0;
        for (double item : array) {
            sum += item;
        }
        return sum;
    }
 
    /**
     * Vypocet souctu hesovacich kodu vsech prvku pole typu Object[].
     */
    static int hashsum(Object[] array) {
        int sum = 0;
        for (Object item : array) {
            sum += item.hashCode();
        }
        return sum;
    }
 
    /**
     * Test demonstracnich metod.
     */
    public static void main(String[] args) {
        byte[]   byteArray   = {1, 2, 3, 4};
        short[]  shortArray  = {1, 2, 3, 4};
        int[]    intArray    = {1, 2, 3, 4};
        long[]   longArray   = {1L,2L,3L,4L};
        float[]  floatArray  = {1f,2f,3f,4f};
        double[] doubleArray = {1.,2.,3.,4.};
        String[] stringArray = {"1","2","3","4"};
 
        System.out.println(sum(byteArray));
        System.out.println(sum(shortArray));
        System.out.println(sum(intArray));
        System.out.println(sum(longArray));
        System.out.println(sum(floatArray));
        System.out.println(sum(doubleArray));
        System.out.println(hashsum(stringArray));
    }
}

4. Okomentovaný bajtkód demonstračního příkladu Test23.java

Podívejme se nyní na způsob překladu jednotlivých metod z demonstračního příkladu Test23.java do bajtkódu JVM. První metoda sum(byte[]) využívá pět pozic (slotů) na zásobníkovém rámci, které jsou vyhrazeny pro lokální proměnné, ať již proměnné explicitně zapsané programátorem, nebo pomocné proměnné využívané interpretrem bajtkódu:

Pozice Lokální proměnná
1 lokální proměnná sum
2 reference na zpracovávané pole
3 délka zpracovávaného pole
4 hodnota počitadla smyčky for, nazvěme počitadlo i
5 hodnota právě zpracovávaného prvku pole (i-tý prvek)

Z výpisu bajtkódu je patrné, že i když byla použita programová smyčka typu for-each, provedl se překlad takovým způsobem, jakoby programátor ve skutečnosti použil počítanou programovou smyčku typu for:

static int sum(byte[]);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
   3:   astore_2                // reference na zpracovávané pole je umístěna do druhé lokální proměnné
   4:   aload_2
   5:   arraylength             // vypočítat délku pole a uložit na TOS
   6:   istore_3                // uložit délku pole do třetí lokální proměnné
   7:   iconst_0                // počáteční hodnota počitadla
   8:   istore  4               // uložit do čtvrté lokální proměnné
 
   10:  iload   4               // začátek programové smyčky "for"
   12:  iload_3                 // porovnat hodnotu počitadla s délkou pole
   13:  if_icmpge       33      // test na ukončení programové smyčky
   16:  aload_2                 // načíst referenci na pole
   17:  iload   4               // hodnota počitadla je použita jako index
   19:  baload                  // získat i-tý prvek z pole typu byte[] (i=hodnota počitadla)
   20:  istore  5               // uložit hodnotu prvku do páté lokální proměnné
 
   22:  iload_1                 // lokální proměnná "sum" na TOS
   23:  iload   5
   25:  iadd                    // přičíst k proměnné "sum" hodnotu i-tého prvku pole
   26:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   27:  iinc    4, 1            // zvýšit hodnotu počitadla o jedničku
   30:  goto    10              // skok na začátek programové smyčky
 
   33:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   34:  ireturn                 // a vrátit ji jako výsledek metody

Prakticky stejný překlad byl proveden pro metodu sum(short[]), pouze s tím rozdílem, že se namísto instrukce baload použila pro čtení prvku pole instrukce saload:

static int sum(short[]);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
   3:   astore_2                // reference na zpracovávané pole je umístěna do druhé lokální proměnné
   4:   aload_2
   5:   arraylength             // vypočítat délku pole a uložit na TOS
   6:   istore_3                // uložit délku pole do třetí lokální proměnné
   7:   iconst_0                // počáteční hodnota počitadla
   8:   istore  4               // uložit do čtvrté lokální proměnné
 
   10:  iload   4               // začátek programové smyčky "for"
   12:  iload_3                 // porovnat hodnotu počitadla s délkou pole
   13:  if_icmpge       33      // test na ukončení programové smyčky
   16:  aload_2                 // načíst referenci na pole
   17:  iload   4               // hodnota počitadla je použita jako index
   19:  saload                  // získat i-tý prvek z pole typu short[] (i=hodnota počitadla)
   20:  istore  5               // uložit hodnotu prvku do páté lokální proměnné
 
   22:  iload_1                 // lokální proměnná "sum" na TOS
   23:  iload   5
   25:  iadd                    // přičíst k proměnné "sum" hodnotu i-tého prvku pole
   26:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   27:  iinc    4, 1            // zvýšit hodnotu počitadla o jedničku
   30:  goto    10              // skok na začátek programové smyčky
 
   33:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   34:  ireturn                 // a vrátit ji jako výsledek metody

Totéž platí i pro překlad metody sum(int[]), jen se namísto baload/saload využívá – podle očekávání – instrukce iaload:

static int sum(int[]);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
   3:   astore_2                // reference na zpracovávané pole je umístěna do druhé lokální proměnné
   4:   aload_2
   5:   arraylength             // vypočítat délku pole a uložit na TOS
   6:   istore_3                // uložit délku pole do třetí lokální proměnné
   7:   iconst_0                // počáteční hodnota počitadla
   8:   istore  4               // uložit do čtvrté lokální proměnné
 
   10:  iload   4               // začátek programové smyčky "for"
   12:  iload_3                 // porovnat hodnotu počitadla s délkou pole
   13:  if_icmpge       33      // test na ukončení programové smyčky
   16:  aload_2                 // načíst referenci na pole
   17:  iload   4               // hodnota počitadla je použita jako index
   19:  iaload                  // získat i-tý prvek z pole typu int[] (i=hodnota počitadla)
   20:  istore  5               // uložit hodnotu prvku do páté lokální proměnné
 
   22:  iload_1                 // lokální proměnná "sum" na TOS
   23:  iload   5
   25:  iadd                    // přičíst k proměnné "sum" hodnotu i-tého prvku pole
   26:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   27:  iinc    4, 1            // zvýšit hodnotu počitadla o jedničku
   30:  goto    10              // skok na začátek programové smyčky
 
   33:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   34:  ireturn                 // a vrátit ji jako výsledek metody

Překlad metody sum(long[]) je poněkud odlišný, a to zejména proto, že lokální proměnné typu long jsou uloženy ve dvou pozicích/slotech. Celkový počet obsazených slotů na zásobníkovém rámci je tedy o dvě vyšší než u předchozích tří variant metody sum():

Pozice Lokální proměnná
1+2 lokální proměnná sum
3 reference na zpracovávané pole
4 délka zpracovávaného pole
5 hodnota počitadla smyčky for, nazvěme počitadlo i
6 hodnota právě zpracovávaného prvku pole (i-tý prvek)

Bajtkód přeložené metody sum(long[]):

static long sum(long[]);
  Code:
   0:   lconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   lstore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
   3:   astore_3                // reference na zpracovávané pole je umístěna do třetí lokální proměnné
   4:   aload_3
   5:   arraylength             // vypočítat délku pole a uložit na TOS
   6:   istore  4               // uložit délku pole do čtvrté lokální proměnné
   8:   iconst_0                // počáteční hodnota počitadla
   9:   istore  5               // uložit do páté lokální proměnné
 
   11:  iload   5               // začátek programové smyčky "for"
   13:  iload   4               // porovnat hodnotu počitadla s délkou pole
   15:  if_icmpge       35      // test na ukončení programové smyčky
   18:  aload_3                 // načíst referenci na pole
   19:  iload   5               // hodnota počitadla je použita jako index
   21:  laload                  // získat i-tý prvek z pole typu long[] (i=hodnota počitadla)
   22:  lstore  6               // uložit hodnotu prvku do šesté lokální proměnné
 
   24:  lload_1                 // lokální proměnná "sum" na TOS
   25:  lload   6
   27:  ladd                    // přičíst k proměnné "sum" hodnotu i-tého prvku pole
   28:  lstore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   29:  iinc    5, 1            // zvýšit hodnotu počitadla o jedničku
   32:  goto    11              // skok na začátek programové smyčky
 
   35:  lload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   36:  lreturn                 // a vrátit ji jako výsledek metody

Metoda sum(float[]) je přeložena podobně, jako tomu bylo u metody sum(int[]), samozřejmě až na rozdíly v některých instrukcích (iconst0/fconst0, iload1/fload1, iadd/fadd atd.):

static float sum(float[]);
  Code:
   0:   fconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   fstore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
   3:   astore_2                // reference na zpracovávané pole je umístěna do druhé lokální proměnné
   4:   aload_2
   5:   arraylength             // vypočítat délku pole a uložit na TOS
   6:   istore_3                // uložit délku pole do třetí lokální proměnné
   7:   iconst_0                // počáteční hodnota počitadla
   8:   istore  4               // uložit do čtvrté lokální proměnné
 
   10:  iload   4               // začátek programové smyčky "for"
   12:  iload_3                 // porovnat hodnotu počitadla s délkou pole
   13:  if_icmpge       33      // test na ukončení programové smyčky
   16:  aload_2                 // načíst referenci na pole
   17:  iload   4               // hodnota počitadla je použita jako index
   19:  faload                  // získat i-tý prvek z pole typu float[] (i=hodnota počitadla)
   20:  fstore  5               // uložit hodnotu prvku do páté lokální proměnné
 
   22:  fload_1                 // lokální proměnná "sum" na TOS
   23:  fload   5
   25:  fadd                    // přičíst k proměnné "sum" hodnotu i-tého prvku pole
   26:  fstore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   27:  iinc    4, 1            // zvýšit hodnotu počitadla o jedničku
   30:  goto    10              // skok na začátek programové smyčky
 
   33:  fload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   34:  freturn                 // a vrátit ji jako výsledek metody

U metody sum(double[]) platí stejná poznámka, jaká byla uvedena v případě sum(long[]), tj. proměnné typu longdouble obsazují vždy dvě pozice/sloty na zásobníkovém rámci:

static double sum(double[]);
  Code:
   0:   dconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   dstore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
   3:   astore_3                // reference na zpracovávané pole je umístěna do třetí lokální proměnné
   4:   aload_3
   5:   arraylength             // vypočítat délku pole a uložit na TOS
   6:   istore  4               // uložit délku pole do čtvrté lokální proměnné
   8:   iconst_0                // počáteční hodnota počitadla
   9:   istore  5               // uložit do páté lokální proměnné
 
   11:  iload   5               // začátek programové smyčky "for"
   13:  iload   4               // porovnat hodnotu počitadla s délkou pole
   15:  if_icmpge       35      // test na ukončení programové smyčky
   18:  aload_3                 // načíst referenci na pole
   19:  iload   5               // hodnota počitadla je použita jako index
   21:  daload                  // získat i-tý prvek z pole typu double[] (i=hodnota počitadla)
   22:  dstore  6               // uložit hodnotu prvku do šesté lokální proměnné
 
   24:  dload_1                 // lokální proměnná "sum" na TOS
   25:  dload   6
   27:  dadd                    // přičíst k proměnné "sum" hodnotu i-tého prvku pole
   28:  dstore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   29:  iinc    5, 1            // zvýšit hodnotu počitadla o jedničku
   32:  goto    11              // skok na začátek programové smyčky
 
   35:  dload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   36:  dreturn                 // a vrátit ji jako výsledek metody
static int hashsum(java.lang.Object[]);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
   3:   astore_2                // reference na zpracovávané pole je umístěna do druhé lokální proměnné
   4:   aload_2
   5:   arraylength             // vypočítat délku pole a uložit na TOS
   6:   istore_3                // uložit délku pole do třetí lokální proměnné
   7:   iconst_0                // počáteční hodnota počitadla
   8:   istore  4               // uložit do čtvrté lokální proměnné
 
   10:  iload   4               // začátek programové smyčky "for"
   12:  iload_3                 // porovnat hodnotu počitadla s délkou pole
   13:  if_icmpge       33      // test na ukončení programové smyčky
   16:  aload_2                 // načíst referenci na pole
   17:  iload   4               // hodnota počitadla je použita jako index
   19:  aaload                  // získat i-tý prvek (=referenci) z pole typu Object[] (i=hodnota počitadla)
   20:  astore  5               // uložit hodnotu prvku (=referenci) do páté lokální proměnné
 
   22:  iload_1                 // lokální proměnná "sum" na TOS
   23:  aload   5
                                // výpočet hešovacího kódu
   25:  invokevirtual   #2;     // Method java/lang/Object.hashCode:()I
   28:  iadd                    // přičíst k proměnné "sum" hodnotu hešovacího kódu i-tého prvku pole
   29:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   30:  iinc    4, 1            // zvýšit hodnotu počitadla o jedničku
   33:  goto    10              // skok na začátek programové smyčky
 
   36:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   37:  ireturn                 // a vrátit ji jako výsledek metody

5. Demonstrační příklad Test24.java: seznamy a programová smyčka typu „for-each“ v JVM

V dnešním druhém demonstračním příkladu s názvem Test24.java je na dvojici metod pojmenovaných sum()hashsum() ukázáno použití programové smyčky typu for-each při průchodu všemi prvky uloženými do seznamu, tj. do kolekce implementující rozhraní List. V metodě sum() se předpokládá, že všechny prvky seznamu budou typu Integer, což je kontrolováno jak při překladu, tak i při běhu aplikace (protože překladač nedokáže kvůli dynamickému linkování zaručit, jak bude metoda sum() přesně volána):

/**
 * Demonstracni priklad cislo 24.
 *
 * Seznamy a programova smycka typu for-each.
 */
 
import java.util.List;
 
public class Test24 {
 
    /**
     * Vypocet souctu vsech prvku seznamu typu List<Integer>.
     */
    static int sum(List<Integer> list) {
        int sum = 0;
        for (int item : list) {
            sum += item;
        }
        return sum;
    }
 
    /**
     * Vypocet souctu hesovacich kodu vsech prvku seznamu typu List<? extends Object>.
     */
    static int hashsum(List<? extends Object> list) {
        int sum = 0;
        for (Object item : list) {
            sum += item.hashCode();
        }
        return sum;
    }
 
    /**
     * Test demonstracnich metod.
     */
    public static void main(String[] args) {
        List<Integer> integerList = java.util.Arrays.asList(1,2,3,4);
        List<? extends Object>  objectList = java.util.Arrays.asList("1","2","3","4");
        System.out.println(sum(integerList));
        System.out.println(hashsum(objectList));
    }
}

6. Okomentovaný bajtkód demonstračního příkladu Test24.java

Metoda sum(java.util.List) (povšimněte si, že se při překladu „vytratila“ informace o typu prvků seznamů, což však přesně odpovídá specifikaci Javy) využívá na zásobníkovém rámci kupodivu pouze tři pozice/sloty, což je značný rozdíl oproti předchozímu příkladu, v němž se používalo většinou pět slotů:

Pozice Lokální proměnná
1 lokální proměnná sum
2 reference na iterátor získaný pro seznam
3 hodnota právě zpracovávaného prvku seznamu

Překlad metody sum(java.util.List) je přímočarý a odpovídá očekávání. Nejprve se získá iterátor pro seznam a posléze se volají metody Iterator.hasNext() pro test ukončení smyčky a Iterator.next() pro přečtení dalšího prvku. Zajímavá je však instrukce checkcast pro otestování typu každého prvku v seznamu, což je důležité, neboť již víme, že se tato informace „vytratila“ z hlavičky metody (je jen součástí metadat):

static int sum(java.util.List);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
                                // získat iterátor pro kolekci (zde konkrétně seznam)
   3:   invokeinterface #2,  1; // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   8:   astore_2                // uložit iterátor do druhé lokální proměnné
 
   9:   aload_2                 // začátek programové smyčky
                                // test na ukončení programové smyčky
   10:  invokeinterface #3,  1; // InterfaceMethod java/util/Iterator.hasNext:()Z
   15:  ifeq    38              // po dosažení konce kolekce se programová smyčka ukončí
   18:  aload_2                 // načíst iterátor na TOS
                                // čtení prvku z kolekce
   19:  invokeinterface #4,  1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
                                // test, zda je prvek skutečně typu Integer
   24:  checkcast       #5;     // class java/lang/Integer
                                // převod z Integer na int
   27:  invokevirtual   #6;     // Method java/lang/Integer.intValue:()I
 
   30:  istore_3                // hodnotu prvku uložit do třetí lokální proměnné
   31:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   32:  iload_3                 // načíst hodnotu prvku z kolekce
   33:  iadd                    // přičíst k proměnné "sum" hodnotu prvku kolekce
   34:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   35:  goto    9               // skok na začátek programové smyčky
 
   38:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   39:  ireturn                 // a vrátit ji jako výsledek metody

Podobným způsobem je zkonstruován i bajtkód metody hashsum(), v níž se však namísto čtení a zpracování objektů typu Integer volá pro všechny objekty nalezené v seznamu metoda Object.hashCode(). I z tohoto důvodu zde již nenalezneme použití instrukce checkcast:

static int hashsum(java.util.List);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
                                // získat iterátor pro kolekc (zde konkrétně pro seznam)
   3:   invokeinterface #2,  1; // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   8:   astore_2                // uložit iterátor do druhé lokální proměnné
 
   9:   aload_2                 // začátek programové smyčky
                                // test na ukončení programové smyčky
   10:  invokeinterface #3,  1; // InterfaceMethod java/util/Iterator.hasNext:()Z
   15:  ifeq    35              // po dosažení konce kolekce se programová smyčka ukončí
   18:  aload_2                 // načíst iterátor na TOS
                                // čtení prvku z kolekce
   19:  invokeinterface #4,  1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
 
   24:  astore_3                // hodnotu prvku uložit do třetí lokální proměnné
   25:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   26:  aload_3                 // načíst hodnotu prvku (=referenci) z kolekce
                                // výpočet hešovacího kódu objektu
   27:  invokevirtual   #7;     // Method java/lang/Object.hashCode:()I
   30:  iadd                    // přičíst k proměnné "sum" hodnotu prvku kolekce
   31:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   32:  goto    9               // skok na začátek programové smyčky
 
   35:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   36:  ireturn                 // a vrátit ji jako výsledek metody

7. Demonstrační příklad Test25.java: množiny a programová smyčka typu „for-each“ v JVM

Další, dnes již třetí demonstrační příklad se jmenuje Test25.java. Jeho zdrojový kód se do značné míry podobá zdrojovému kódu předchozího demonstračního příkladu Test24.java, až na ten rozdíl, že se namísto prvků uložených do seznamů prochází všemi prvky množiny, tj. jakékoli kolekce implementující rozhraní Set. Povšimněte si, že těla metod jsou shodná s předchozím demonstračním příkladem, což vlastně není příliš překvapivé, když si uvědomíme, že jak seznamy, tak i množiny implementují rozhraní Iterable a programová smyčka typu for-each je určena mj. právě pro využití iterátorů:

/**
 * Demonstracni priklad cislo 25.
 *
 * Mnoziny a programova smycka typu for-each.
 */
 
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
 
public class Test25 {
 
    /**
     * Vypocet souctu vsech prvku mnoziny typu Set<Integer>.
     */
    static int sum(Set<Integer> set) {
        int sum = 0;
        for (int item : set) {
            sum += item;
        }
        return sum;
    }
 
    /**
     * Vypocet souctu hesovacich kodu vsech prvku mnoziny typu Set<Object>.
     */
    static int hashsum(Set<? extends Object> set) {
        int sum = 0;
        for (Object item : set) {
            sum += item.hashCode();
        }
        return sum;
    }
 
    /**
     * Test demonstracnich metod.
     */
    public static void main(String[] args) {
        Set<Integer> integerSet = new TreeSet(Arrays.asList(1,2,3,4));
        Set<? extends Object> objectSet = new TreeSet(Arrays.asList("1","2","3","4"));
        System.out.println(sum(integerSet));
        System.out.println(hashsum(objectSet));
    }
}

8. Okomentovaný bajtkód demonstračního příkladu Test25.java

Bajtkód vzniklý překladem demonstračního příkladu Test25.java je až na několik malých rozdílů prakticky stejný jako bajtkód předchozího příkladu Test24.java. Nejprve si ukažme, jakým způsobem jsou využity pozice/sloty alokované v zásobníkovém rámci (stack frame):

Pozice Lokální proměnná
1 lokální proměnná sum
2 reference na iterátor získaný pro množinu
3 hodnota právě zpracovávaného prvku množiny

Nyní již následuje okomentovaný výpis bajtkódu příkladu Test25.java:

static int sum(java.util.Set);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
                                // získat iterátor pro kolekci (zde konkrétně množinu)
   3:   invokeinterface #2,  1; // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator;
   8:   astore_2                // uložit iterátor do druhé lokální proměnné
 
   9:   aload_2                 // začátek programové smyčky
                                // test na ukončení programové smyčky
   10:  invokeinterface #3,  1; // InterfaceMethod java/util/Iterator.hasNext:()Z
   15:  ifeq    38              // po dosažení konce kolekce se programová smyčka ukončí
   18:  aload_2                 // načíst iterátor na TOS
                                // čtení prvku z kolekce
   19:  invokeinterface #4,  1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
                                // test, zda je prvek skutečně typu Integer
   24:  checkcast       #5;     // class java/lang/Integer
                                // převod z Integer na int
   27:  invokevirtual   #6;     // Method java/lang/Integer.intValue:()I
 
   30:  istore_3                // hodnotu prvku uložit do třetí lokální proměnné
   31:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   32:  iload_3                 // načíst hodnotu prvku z kolekce
   33:  iadd                    // přičíst k proměnné "sum" hodnotu prvku kolekce
   34:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   35:  goto    9               // skok na začátek programové smyčky
 
   38:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   39:  ireturn                 // a vrátit ji jako výsledek metody
static int hashsum(java.util.Set);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
                                // získat iterátor pro kolekc (zde konkrétně pro množinu)
   3:   invokeinterface #2,  1; // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator;
   8:   astore_2                // uložit iterátor do druhé lokální proměnné
 
   9:   aload_2                 // začátek programové smyčky
                                // test na ukončení programové smyčky
   10:  invokeinterface #3,  1; // InterfaceMethod java/util/Iterator.hasNext:()Z
   15:  ifeq    35              // po dosažení konce kolekce se programová smyčka ukončí
   18:  aload_2                 // načíst iterátor na TOS
                                // čtení prvku z kolekce
   19:  invokeinterface #4,  1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
 
   24:  astore_3                // hodnotu prvku uložit do třetí lokální proměnné
   25:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   26:  aload_3                 // načíst hodnotu prvku (=referenci) z kolekce
                                // výpočet hešovacího kódu objektu
   27:  invokevirtual   #7;     // Method java/lang/Object.hashCode:()I
   30:  iadd                    // přičíst k proměnné "sum" hodnotu prvku kolekce
   31:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   32:  goto    9               // skok na začátek programové smyčky
 
   35:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   36:  ireturn                 // a vrátit ji jako výsledek metody

9. Demonstrační příklad Test26.java: mapy a programová smyčka typu „for-each“ v JVM

V dnešním posledním demonstračním příkladu, který nese název Test26.java, se ve dvojici metod sum1()sum2() prochází mapou, tj. takovou datovou strukturou, v níž jsou uloženy dvojice klíč:hodnota, přičemž klíče musí být v rámci jedné mapy jednoznačné a unikátní. V metodě sum1() se sčítají celočíselné klíče, zatímco v metodě sum2() dochází k součtu (taktéž celočíselných) hodnot. V obou zmíněných metodách je samozřejmě využita programová smyčka typu for-each pro procházení prvky množiny typu Map.Entry:

/**
 * Demonstracni priklad cislo 26.
 *
 * Mapy a programova smycka typu for-each.
 */
 
import java.util.Map;
import java.util.TreeMap;
 
public class Test26 {
 
    /**
     * Vypocet souctu klicu vsech prvku mapy typu Map<Integer,Integer>.
     */
    static int sum1(Map<Integer,Integer> map) {
        int sum = 0;
        for (Map.Entry<Integer,Integer> item : map.entrySet()) {
            sum += item.getKey();
        }
        return sum;
    }
 
    /**
     * Vypocet souctu hodnot vsech prvku mapy typu Map<Integer,Integer>.
     */
    static int sum2(Map<Integer,Integer> map) {
        int sum = 0;
        for (Map.Entry<Integer,Integer> item : map.entrySet()) {
            sum += item.getValue();
        }
        return sum;
    }
 
    /**
     * Test demonstracnich metod.
     */
    public static void main(String[] args) {
        Map<Integer, Integer> map = new TreeMap<Integer,Integer>();
        for (int i=0; i<=4; i++) {
            map.put(i,i);
        }
        System.out.println(sum1(map));
        System.out.println(sum2(map));
    }
}

10. Okomentovaný bajtkód demonstračního příkladu Test26.java

Před popisem bajtkódu demonstračního příkladu Test26.java se podívejme, podobně jako tomu bylo u všech tří předchozích demonstračních příkladů, na obsazení zásobníkového rámce:

Pozice Lokální proměnná
1 lokální proměnná sum
2 reference na iterátor získaný pro mapu s prvky typu Map.Entry
3 hodnota právě zpracovávaného prvku mapy (typ Map.Entry)

Bajtkód metody sum1() je poměrně dlouhý, a to především z toho důvodu, že se pro průchod mapou musí nejdříve získat množina s prvky Map.Entry, a to konkrétně s využitím metody Map.entrySet(). Následně se získá iterátor pro tuto množinu a při průchodu všemi prvky vracenými iterátorem se (zbytečně) provádí test na jejich typ s využitím instrukce checkcast. Stejná instrukce je použita pro testování typu klíče – opět se zde ukazuje, jaké problémy způsobuje fakt, že typ prvků/klíčů/hodnot není jednoznačnou součástí popisu datového typu kolekce:

static int sum1(java.util.Map);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
                                // získat objekt typu Map.Entry
   3:   invokeinterface #2,  1; // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set;
                                // získat iterátor pro kolekci (zde konkrétně množinu)
   8:   invokeinterface #3,  1; // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator;
   13:  astore_2                // uložit iterátor do druhé lokální proměnné
 
   14:  aload_2                 // začátek programové smyčky
                                // test na ukončení programové smyčky
   15:  invokeinterface #4,  1; // InterfaceMethod java/util/Iterator.hasNext:()Z
   20:  ifeq    51              // po dosažení konce kolekce se programová smyčka ukončí
   23:  aload_2                 // načíst iterátor na TOS
                                // čtení prvku z kolekce
   24:  invokeinterface #5,  1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
                                // test, zda je prvek skutečně typu Map.Entry (to musí být celkem zbytečná konstrukce)
   29:  checkcast       #6;     // class java/util/Map$Entry
   32:  astore_3                // uložit objekt vrácený iterátorem z TOS do třetí lokální proměnné
   33:  iload_1                 // načíst hodnotu lokální proměnné "sum"
   34:  aload_3                 // uložit objekt vrácený iterátorem na TOS
                                // získat klíč z dvojice Map.Entry
   35:  invokeinterface #7,  1; // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object;
                                // test, zda je klíč typu Integer
   40:  checkcast       #8;     // class java/lang/Integer
                                // převod z Integer na int
   43:  invokevirtual   #9;     // Method java/lang/Integer.intValue:()I
   46:  iadd                    // přičíst k proměnné "sum" hodnotu prvku kolekce
   47:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   48:  goto    14              // skok na začátek programové smyčky
 
   51:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   52:  ireturn                 // a vrátit ji jako výsledek metody

Bajtkód metody sum2() se od bajtkódu metody sum1() liší pouze v jednom ohledu – získávají a zpracovávají se zde hodnoty, nikoli klíče, tj. pro objekty typu Map.Entry se volá metoda getValue() a nikoli metoda getKey():

static int sum2(java.util.Map);
  Code:
   0:   iconst_0                // počáteční hodnota lokální proměnné "sum"
   1:   istore_1                // inicializace lokální proměnné "sum"
   2:   aload_0                 // uložit první (jediný) parametr metody na zásobník
                                // získat objekt typu Map.Entry
   3:   invokeinterface #2,  1; // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set;
                                // získat iterátor pro kolekci (zde konkrétně množinu)
   8:   invokeinterface #3,  1; // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator;
   13:  astore_2                // uložit iterátor do druhé lokální proměnné
 
   14:  aload_2                 // začátek programové smyčky
                                // test na ukončení programové smyčky
   15:  invokeinterface #4,  1; // InterfaceMethod java/util/Iterator.hasNext:()Z
   20:  ifeq    51              // po dosažení konce kolekce se programová smyčka ukončí
   23:  aload_2                 // načíst iterátor na TOS
                                // čtení prvku z kolekce
   24:  invokeinterface #5,  1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
                                // test, zda je prvek skutečně typu Map.Entry (to musí být celkem zbytečná konstrukce)
   29:  checkcast       #6;     // class java/util/Map$Entry
   32:  astore_3                // uložit objekt vrácený iterátorem z TOS do třetí lokální proměnné
   33:  iload_1                 // načíst hodnotu lokální proměnné "sum"
   34:  aload_3                 // uložit objekt vrácený iterátorem na TOS
                                // získat hodnotu (value) z dvojice Map.Entry
   35:  invokeinterface #10,  1;// InterfaceMethod java/util/Map$Entry.getValue:()Ljava/lang/Object;
                                // test, zda je hodnota typu Integer
   40:  checkcast       #8;     // class java/lang/Integer
                                // převod z Integer na int
   43:  invokevirtual   #9;     // Method java/lang/Integer.intValue:()I
   46:  iadd                    // přičíst k proměnné "sum" hodnotu prvku kolekce
   47:  istore_1                // přenos hodnoty z TOS do lokální proměnné "sum"
 
   48:  goto    14              // skok na začátek programové smyčky
 
   51:  iload_1                 // načíst aktuální hodnotu lokální proměnné "sum"
   52:  ireturn                 // a vrátit ji jako výsledek metody

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

Všechny čtyři dnes popsané a využité demonstrační příklady (naprogramované v Javě, protože příklady pro jazyky Python a Lua budou popsány příště) 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:

12. Odkazy na Internetu

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

Ohodnoťte jako ve škole:

Průměrná známka 1,00

Našli jste v článku chybu?
Zasílat nově přidané názory e-mailem
120na80.cz: 10 nej přípravků na holení

10 nej přípravků na holení

Podnikatel.cz: Když už je sexy, tak ať taky funguje

Když už je sexy, tak ať taky funguje

Podnikatel.cz: Podání k DPH jinak než online jsou neúčinná

Podání k DPH jinak než online jsou neúčinná

Vitalia.cz: Muži kouří 24 cigaret denně, ženy o dost míň

Muži kouří 24 cigaret denně, ženy o dost míň

120na80.cz: Tady se vaří padělané léky

Tady se vaří padělané léky

Vitalia.cz: Před, nebo po snídani? Kdy je lepší čistit si zuby

Před, nebo po snídani? Kdy je lepší čistit si zuby

120na80.cz: 10 dezinfekcí: Vede „starý dobrý“ peroxid

10 dezinfekcí: Vede „starý dobrý“ peroxid

Vitalia.cz: Syndrom počítačového vidění: stačí dvě hodiny denně

Syndrom počítačového vidění: stačí dvě hodiny denně

Vitalia.cz: Taky ji kupujete? Je šizená

Taky ji kupujete? Je šizená

Lupa.cz: Jak EET vidí ajťák aneb Drahá vražda UX

Jak EET vidí ajťák aneb Drahá vražda UX

Podnikatel.cz: Alza radí e-shopům, jak opustit Heureku

Alza radí e-shopům, jak opustit Heureku

120na80.cz: Jak si udržet zdravou vaginu

Jak si udržet zdravou vaginu

Vitalia.cz: Proč máme prasklý chléb nejraději?

Proč máme prasklý chléb nejraději?

Root.cz: DDoS útoky aneb když vám zahltí dráty

DDoS útoky aneb když vám zahltí dráty

Vitalia.cz: Mražené ryby z Makra byly falšované

Mražené ryby z Makra byly falšované

Lupa.cz: Nová podoba Instagramu? Katastrofa

Nová podoba Instagramu? Katastrofa

120na80.cz: Co jí dělá? Sklerotizaci

Co jí dělá? Sklerotizaci

DigiZone.cz: Mafra varuje před stíháním za pomluvu

Mafra varuje před stíháním za pomluvu

Vitalia.cz: SÚKL: vakcíny jsou bezpečné a s autismem nesouvisí

SÚKL: vakcíny jsou bezpečné a s autismem nesouvisí

120na80.cz: Zjistěte, zda je vaše klíště infikované

Zjistěte, zda je vaše klíště infikované