Obsah
1. Pohled pod kapotu JVM – práce s parametry funkcí a složené datové typy v JVM, Lua VM a Python VM
2. Předávání parametrů metodám v JVM
3. Demonstrační příklad Test17.java: předávání parametrů typu int
4. Demonstrační příklad Test18.java: předávání parametrů typu float
5. Předávání parametrů funkcím v Lua VM: demonstrační příklad Test17.lua
6. Předávání parametrů funkcím v Python VM: demonstrační příklad Test17.py
7. Složené datové typy v JVM, Lua VM a Python VM
8. Demonstrační příklad Test19.java: konstrukce jednorozměrných polí
9. Demonstrační příklad Test20.java: konstrukce vícerozměrných polí
10. Demonstrační příklad Test19.lua: vytvoření tabulky
11. Demonstrační příklad Test20.lua: vytvoření asociativního pole
12. Demonstrační příklad Test19.py: vytvoření seznamu
13. Demonstrační příklad Test20.py: vytvoření n-tice
14. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – práce s parametry funkcí a složené datové typy v JVM, Lua VM a Python VM
V posledních několika částech seriálu o programovacím jazyce Java i o vlastnostech virtuálního stroje tohoto jazyka jsme si na mnoha demonstračních příkladech ukázali, jakým způsobem se do instrukcí bajtkódu JVM, Python VM i Lua VM překládají některé základní programové konstrukce, konkrétně aritmetické i logické výrazy, rozhodovací (větvící) konstrukce typu if-then i if-then-else, programové smyčky typu while (s podmínkou vyhodnocovanou na začátku každé iterace) i do-while/repeat-until (s podmínkou vyhodnocovanou na konci každé iterace) a konečně počítané programové smyčky typu for. Prozatím jsme si však podrobněji nevysvětlili další důležitou součást virtuálních strojů – postup použitý při předávání parametrů funkcím nebo metodám a následné zpracování těchto parametrů. Touto problematikou se budeme zabývat v první polovině dnešního článku (kapitoly 2 až 6).
Druhá polovina dnešního článku (konkrétně kapitola 7 a samozřejmě taktéž navazující kapitoly) bude věnována sice dosti odlišnému, ovšem taktéž důležitému tématu. Budeme se v ní totiž zabývat způsobem práce se složenými datovými typy a podporou těchto typů v jednotlivých bajtkódech. V případě JVM je podporován datový typ pole, zatímco Python VM naproti tomu podporuje seznamy i n-tice a Lua VM tabulky jakožto zobecnění původních polí. Toto téma tedy bude dosti zajímavé, protože se zde opět ukážou významné rozdíly mezi jednotlivými virtuálními stroji. Tyto rozdíly samozřejmě poměrně úzce souvisí i se sémantikou programovacích jazyků, které tyto virtuální stroje primárně využívají.
2. Předávání parametrů metodám v JVM
Nejprve si popíšeme způsob předávání parametrů volaným metodám. Začneme popisem JVM. Zde je při volání metod použit zásobník operandů, na nějž se ve volající metodě uloží všechny potřebné parametry. V metodě volané se k těmto parametrům přistupuje jako k lokálním proměnným, což konkrétně znamená, že prvních n lokálních proměnných odpovídá n parametrům metody (u nestatických metod je prvním parametrem samozřejmě this). Záleží jen na konkrétní implementaci virtuálního stroje Javy, jakým způsobem dojde při volání metody ke konverzi mezi zásobníkem operandů volající metody a lokálními parametry metody volané.
Z hlediska bajtkódu se pro další práci s lokálními proměnnými používají instrukce sloužící pro přesuny dat mezi lokálními proměnnými a případnými parametry metody na jedné straně a zásobníkem operandů na straně druhé. Je pravděpodobně zřejmé, že způsob adresace dat bude odlišný na straně lokálních proměnných i na straně zásobníku operandů. V případě lokálních proměnných+parametrů je totiž každý prvek určen svým indexem, který je nedílnou součástí instrukce (způsob práce s lokálními parametry tedy připomíná práci s polem, jehož prvky lze snadno indexovat). U zásobníku operandů se vždy pracuje s prvkem umístěným na vrcholu zásobníku (TOS=Top Of Stack); ostatní prvky umístěné pod TOS jsou nedostupné.
Všechny instrukce tohoto typu se jmenují *load# popř. *store#, přičemž za hvězdičku se doplňuje první písmeno datového typu a za křížek se v některých případech udává index do oblasti lokálních proměnných – to ovšem jen v případě těch instrukcí, u nichž je index součástí instrukčního slova. V opačném případě je index uložen ve formě jednoho bajtu ihned za instrukčním kódem. Pokud je nutné adresovat prvek s indexem větším než 255 (typicky u začátečnických programů v velkým množstvím lokálních proměnných v jediné metodě :-)), lze před instrukci typu load/store vložit prefix wide – poté lze použít šestnáctibitový index namísto indexu osmibitového. Nyní nás budou zajímat pouze instrukce pro načtení hodnoty parametru/lokální proměnné a její uložení na zásobník operandů:
# | Instrukce | Opkód | Data1 | Typ dat | Popis |
---|---|---|---|---|---|
01 | iload | 15 | index | int | načtení lokální proměnné typu int z pozice „index“ a její uložení na TOS |
02 | lload | 16 | index | long | načtení lokální proměnné typu long z pozice „index“ a její uložení na TOS |
03 | fload | 17 | index | float | načtení lokální proměnné typu float z pozice „index“ a její uložení na TOS |
04 | dload | 18 | index | double | načtení lokální proměnné typu double z pozice „index“ a její uložení na TOS |
05 | aload | 19 | index | reference | načtení lokální proměnné typu reference na objekt z pozice „index“ a její uložení na TOS |
06 | iload0 | 1A | int | načtení lokální proměnné typu int z pozice číslo 0 a její uložení na TOS | |
07 | iload1 | 1B | int | načtení lokální proměnné typu int z pozice číslo 1 a její uložení na TOS | |
08 | iload2 | 1C | int | načtení lokální proměnné typu int z pozice číslo 2 a její uložení na TOS | |
09 | iload3 | 1D | int | načtení lokální proměnné typu int z pozice číslo 3 a její uložení na TOS | |
10 | lload0 | 1E | long | načtení lokální proměnné typu long z pozice číslo 0 a její uložení na TOS | |
11 | lload1 | 1F | long | načtení lokální proměnné typu long z pozice číslo 1 a její uložení na TOS | |
12 | lload2 | 20 | long | načtení lokální proměnné typu long z pozice číslo 2 a její uložení na TOS | |
13 | lload3 | 21 | long | načtení lokální proměnné typu long z pozice číslo 3 a její uložení na TOS | |
14 | fload0 | 22 | float | načtení lokální proměnné typu float z pozice číslo 0 a její uložení na TOS | |
15 | fload1 | 23 | float | načtení lokální proměnné typu float z pozice číslo 1 a její uložení na TOS | |
16 | fload2 | 24 | float | načtení lokální proměnné typu float z pozice číslo 2 a její uložení na TOS | |
17 | fload3 | 25 | float | načtení lokální proměnné typu float z pozice číslo 3 a její uložení na TOS | |
18 | dload0 | 26 | double | načtení lokální proměnné typu double z pozice číslo 0 a její uložení na TOS | |
19 | dload1 | 27 | double | načtení lokální proměnné typu double z pozice číslo 1 a její uložení na TOS | |
20 | dload2 | 28 | double | načtení lokální proměnné typu double z pozice číslo 2 a její uložení na TOS | |
21 | dload3 | 29 | double | načtení lokální proměnné typu double z pozice číslo 3 a její uložení na TOS | |
22 | aload0 | 2A | reference | načtení lokální proměnné typu reference na objekt z pozice číslo 0 a její uložení na TOS | |
23 | aload1 | 2B | reference | načtení lokální proměnné typu reference na objekt z pozice číslo 1 a její uložení na TOS | |
24 | aload2 | 2C | reference | načtení lokální proměnné typu reference na objekt z pozice číslo 2 a její uložení na TOS | |
25 | aload3 | 2D | reference | načtení lokální proměnné typu reference na objekt z pozice číslo 3 a její uložení na TOS |
Zajímavé je, že většina výše zmíněných instrukcí vlastně existuje pouze proto, aby došlo k redukci celkové velikosti bajtkódu, a to zejména při práci s metodami majícími malý počet parametrů i malý počet lokálních proměnných (ušetří se vždy jeden bajt za operačním kódem instrukce).
3. Demonstrační příklad Test17.java: předávání parametrů typu int
Vzhledem k tomu, že JVM, jakožto i programovací jazyk Java, používá statické typování, ukážeme si způsob předávání parametrů volaným metodám na dvojici demonstračních příkladů. V prvním demonstračním příkladu se budou metodám předávat parametry typu int. Za povšimnutí stojí především již zmíněný způsob optimalizace, konkrétně použití instrukcí iload_x pro načtení prvních (až čtyř) parametrů:
/** * Ukazka predavani parametru typu int do volanych statickych metod. */ public class Test17 { /** * Metoda bez parametru. */ public static int test0i() { return 42; } /** * Metoda s jednim parametrem typu int. */ public static int test1i(int a) { return a; } /** * Metoda se dvema parametry typu int */ public static int test2i(int a, int b) { return a + b; } /** * Metoda se tremi parametry typu int */ public static int test3i(int a, int b, int c) { return a + b + c; } /** * Metoda se ctyrmi parametry typu int */ public static int test4i(int a, int b, int c, int d) { return a + b + c + d; } /** * Metoda s peti parametry typu int */ public static int test5i(int a, int b, int c, int d, int e) { return a + b + c + d + e; } /** * Metoda se sesti parametry typu int */ public static int test6i(int a, int b, int c, int d, int e, int f) { return a + b + c + d + e + f; } /** * Vse je nutne otestovat. */ public static void main(String[] args) { System.out.println(test0i()); System.out.println(test1i(1)); System.out.println(test2i(1, 2)); System.out.println(test3i(1, 2, 3)); System.out.println(test4i(1, 2, 3, 4)); System.out.println(test5i(1, 2, 3, 4, 5)); System.out.println(test6i(1, 2, 3, 4, 5, 6)); } }
Podívejme se nyní na vygenerovaný a okomentovaný bajtkód:
Compiled from "Test17.java" public class Test17 extends java.lang.Object{ public static int test0i(); Code: 0: bipush 42 // uložení celočíselné konstanty 42 na TOS 2: ireturn // vrácení hodnoty typu int uložené na TOS public static int test1i(int); Code: 0: iload_0 // uložení hodnoty prvního parametru na zásobník 1: ireturn // vrácení hodnoty typu int uložené na TOS public static int test2i(int, int); Code: 0: iload_0 // uložení hodnoty prvního parametru na zásobník 1: iload_1 // uložení hodnoty druhého parametru na zásobník 2: iadd 3: ireturn // vrácení hodnoty typu int uložené na TOS public static int test3i(int, int, int); Code: 0: iload_0 // uložení hodnoty prvního parametru na zásobník 1: iload_1 // uložení hodnoty druhého parametru na zásobník 2: iadd 3: iload_2 // uložení hodnoty třetího parametru na zásobník 4: iadd 5: ireturn // vrácení hodnoty typu int uložené na TOS public static int test4i(int, int, int, int); Code: 0: iload_0 // uložení hodnoty prvního parametru na zásobník 1: iload_1 // uložení hodnoty druhého parametru na zásobník 2: iadd 3: iload_2 // uložení hodnoty třetího parametru na zásobník 4: iadd 5: iload_3 // uložení hodnoty čtvrtého parametru na zásobník 6: iadd 7: ireturn // vrácení hodnoty typu int uložené na TOS public static int test5i(int, int, int, int, int); Code: 0: iload_0 // uložení hodnoty prvního parametru na zásobník 1: iload_1 // uložení hodnoty druhého parametru na zásobník 2: iadd 3: iload_2 // uložení hodnoty třetího parametru na zásobník 4: iadd 5: iload_3 // uložení hodnoty čtvrtého parametru na zásobník 6: iadd 7: iload 4 // uložení hodnoty pátého parametru na zásobník 9: iadd 10: ireturn // vrácení hodnoty typu int uložené na TOS public static int test6i(int, int, int, int, int, int); Code: 0: iload_0 // uložení hodnoty prvního parametru na zásobník 1: iload_1 // uložení hodnoty druhého parametru na zásobník 2: iadd 3: iload_2 // uložení hodnoty třetího parametru na zásobník 4: iadd 5: iload_3 // uložení hodnoty čtvrtého parametru na zásobník 6: iadd 7: iload 4 // uložení hodnoty pátého parametru na zásobník 9: iadd 10: iload 5 // uložení hodnoty šestého parametru na zásobník 12: iadd 13: ireturn // vrácení hodnoty typu int uložené na TOS public static void main(java.lang.String[]); Code: 0: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 3: invokestatic #3; // Method test0i:()I 6: invokevirtual #4; // Method java/io/PrintStream.println:(I)V 9: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 12: iconst_1 // první argument metody na zásobník 13: invokestatic #5; // Method test1i:(I)I 16: invokevirtual #4; // Method java/io/PrintStream.println:(I)V 19: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 22: iconst_1 // první argument metody na zásobník 23: iconst_2 // druhý argument metody na zásobník 24: invokestatic #6; // Method test2i:(II)I 27: invokevirtual #4; // Method java/io/PrintStream.println:(I)V 30: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 33: iconst_1 // první argument metody na zásobník 34: iconst_2 // druhý argument metody na zásobník 35: iconst_3 // třetí argument metody na zásobník 36: invokestatic #7; // Method test3i:(III)I 39: invokevirtual #4; // Method java/io/PrintStream.println:(I)V 42: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 45: iconst_1 // první argument metody na zásobník 46: iconst_2 // druhý argument metody na zásobník 47: iconst_3 // třetí argument metody na zásobník 48: iconst_4 // čtvrtý argument metody na zásobník 49: invokestatic #8; // Method test4i:(IIII)I 52: invokevirtual #4; // Method java/io/PrintStream.println:(I)V 55: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 58: iconst_1 // první argument metody na zásobník 59: iconst_2 // druhý argument metody na zásobník 60: iconst_3 // třetí argument metody na zásobník 61: iconst_4 // čtvrtý argument metody na zásobník 62: iconst_5 // pátý argument metody na zásobník 63: invokestatic #9; // Method test5i:(IIIII)I 66: invokevirtual #4; // Method java/io/PrintStream.println:(I)V 69: getstatic #2; // Field java/lang/System.out:Ljava/io/PrintStream; 72: iconst_1 // první argument metody na zásobník 73: iconst_2 // druhý argument metody na zásobník 74: iconst_3 // třetí argument metody na zásobník 75: iconst_4 // čtvrtý argument metody na zásobník 76: iconst_5 // pátý argument metody na zásobník 77: bipush 6 // šestý argument metody na zásobník 79: invokestatic #10; // Method test6i:(IIIIII)I 82: invokevirtual #4; // Method java/io/PrintStream.println:(I)V 85: return }
4. Demonstrační příklad Test18.java: předávání parametrů typu float
Ve druhém demonstračním příkladu nazvaném Test18.java se budou volaným metodám předávat parametry typu float, což znamená, že překladač vygeneruje instrukce fload_x a nikoli iload_x:
/** * Ukazka predavani parametru typu float do volanych statickych metod. */ public class Test18 { /** * Metoda bez parametru. */ public static float test0i() { return 42.0f; } /** * Metoda s jednim parametrem typu float. */ public static float test1i(float a) { return a; } /** * Metoda se dvema parametry typu float */ public static float test2i(float a, float b) { return a + b; } /** * Metoda se tremi parametry typu float */ public static float test3i(float a, float b, float c) { return a + b + c; } /** * Metoda se ctyrmi parametry typu float */ public static float test4i(float a, float b, float c, float d) { return a + b + c + d; } /** * Metoda s peti parametry typu float */ public static float test5i(float a, float b, float c, float d, float e) { return a + b + c + d + e; } /** * Metoda se sesti parametry typu float */ public static float test6i(float a, float b, float c, float d, float e, float f) { return a + b + c + d + e + f; } /** * Vse je nutne otestovat. */ public static void main(String[] args) { System.out.print(test0i()); System.out.print(test1i(1.0f)); System.out.print(test2i(1.0f, 2.0f)); System.out.print(test3i(1.0f, 2.0f, 3.0f)); System.out.print(test4i(1.0f, 2.0f, 3.0f, 4.0f)); System.out.print(test5i(1.0f, 2.0f, 3.0f, 4.0f, 5.0f)); System.out.print(test6i(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f)); } }
Opět se podívejme na výsledek překladu tohoto demonstračního příkladu a na rozdíly oproti bajtkódu příkladu předchozího:
Compiled from "Test18.java" public class Test18 extends java.lang.Object{ public static float test0i(); Code: 0: ldc #2; // uložení reálné konstanty 42.0f na TOS 2: freturn // vrácení hodnoty typu float uložené na TOS public static float test1i(float); Code: 0: fload_0 // uložení hodnoty prvního parametru na zásobník 1: freturn // vrácení hodnoty typu float uložené na TOS public static float test2i(float, float); Code: 0: fload_0 // uložení hodnoty prvního parametru na zásobník 1: fload_1 // uložení hodnoty druhého parametru na zásobník 2: fadd 3: freturn // vrácení hodnoty typu float uložené na TOS public static float test3i(float, float, float); Code: 0: fload_0 // uložení hodnoty prvního parametru na zásobník 1: fload_1 // uložení hodnoty druhého parametru na zásobník 2: fadd 3: fload_2 // uložení hodnoty třetího parametru na zásobník 4: fadd 5: freturn // vrácení hodnoty typu float uložené na TOS public static float test4i(float, float, float, float); Code: 0: fload_0 // uložení hodnoty prvního parametru na zásobník 1: fload_1 // uložení hodnoty druhého parametru na zásobník 2: fadd 3: fload_2 // uložení hodnoty třetího parametru na zásobník 4: fadd 5: fload_3 // uložení hodnoty čtvrtého parametru na zásobník 6: fadd 7: freturn // vrácení hodnoty typu float uložené na TOS public static float test5i(float, float, float, float, float); Code: 0: fload_0 // uložení hodnoty prvního parametru na zásobník 1: fload_1 // uložení hodnoty druhého parametru na zásobník 2: fadd 3: fload_2 // uložení hodnoty třetího parametru na zásobník 4: fadd 5: fload_3 // uložení hodnoty čtvrtého parametru na zásobník 6: fadd 7: fload 4 // uložení hodnoty pátého parametru na zásobník 9: fadd 10: freturn // vrácení hodnoty typu float uložené na TOS public static float test6i(float, float, float, float, float, float); Code: 0: fload_0 // uložení hodnoty prvního parametru na zásobník 1: fload_1 // uložení hodnoty druhého parametru na zásobník 2: fadd 3: fload_2 // uložení hodnoty třetího parametru na zásobník 4: fadd 5: fload_3 // uložení hodnoty čtvrtého parametru na zásobník 6: fadd 7: fload 4 // uložení hodnoty pátého parametru na zásobník 9: fadd 10: fload 5 // uložení hodnoty šestého parametru na zásobník 12: fadd 13: freturn // vrácení hodnoty typu float uložené na TOS public static void main(java.lang.String[]); Code: 0: getstatic #3; // Field java/lang/System.out:Ljava/io/PrintStream; 3: invokestatic #4; // Method test0i:()F 6: invokevirtual #5; // Method java/io/PrintStream.print:(F)V 9: getstatic #3; // Field java/lang/System.out:Ljava/io/PrintStream; 12: fconst_1 // první argument metody na zásobník 13: invokestatic #6; // Method test1i:(F)F 16: invokevirtual #5; // Method java/io/PrintStream.print:(F)V 19: getstatic #3; // Field java/lang/System.out:Ljava/io/PrintStream; 22: fconst_1 // první argument metody na zásobník 23: fconst_2 // druhý argument metody na zásobník 24: invokestatic #7; // Method test2i:(FF)F 27: invokevirtual #5; // Method java/io/PrintStream.print:(F)V 30: getstatic #3; // Field java/lang/System.out:Ljava/io/PrintStream; 33: fconst_1 // první argument metody na zásobník 34: fconst_2 // druhý argument metody na zásobník 35: ldc #8; // třetí argument metody na zásobník 37: invokestatic #9; // Method test3i:(FFF)F 40: invokevirtual #5; // Method java/io/PrintStream.print:(F)V 43: getstatic #3; // Field java/lang/System.out:Ljava/io/PrintStream; 46: fconst_1 // první argument metody na zásobník 47: fconst_2 // druhý argument metody na zásobník 48: ldc #8; // třetí argument metody na zásobník 50: ldc #10; // čtvrtý argument metody na zásobník 52: invokestatic #11; // Method test4i:(FFFF)F 55: invokevirtual #5; // Method java/io/PrintStream.print:(F)V 58: getstatic #3; // Field java/lang/System.out:Ljava/io/PrintStream; 61: fconst_1 // první argument metody na zásobník 62: fconst_2 // druhý argument metody na zásobník 63: ldc #8; // třetí argument metody na zásobník 65: ldc #10; // čtvrtý argument metody na zásobník 67: ldc #12; // pátý argument metody na zásobník 69: invokestatic #13; // Method test5i:(FFFFF)F 72: invokevirtual #5; // Method java/io/PrintStream.print:(F)V 75: getstatic #3; // Field java/lang/System.out:Ljava/io/PrintStream; 78: fconst_1 // první argument metody na zásobník 79: fconst_2 // druhý argument metody na zásobník 80: ldc #8; // třetí argument metody na zásobník 82: ldc #10; // čtvrtý argument metody na zásobník 84: ldc #12; // pátý argument metody na zásobník 86: ldc #14; // šestý argument metody na zásobník 88: invokestatic #15; // Method test6i:(FFFFFF)F 91: invokevirtual #5; // Method java/io/PrintStream.print:(F)V 94: return }
5. Předávání parametrů funkcím v Lua VM: demonstrační příklad Test17.lua
Předávání parametrů funkcím v Lua VM i Python VM se liší od JVM především v tom ohledu, že se využívá dynamického typování, což mj. znamená, že počet potřebných typů instrukcí bajtkódu je mnohem menší. Nejprve se podívejme na Lua VM a demonstrační příklad Test17.lua:
-- -- Ukazka predavani parametru do volanych funkci. -- -- -- Funkce bez parametru. -- function test0() return 42 end -- -- Funkce s jednim parametrem -- function test1(a) return a end -- -- Funkce se dvema parametry -- function test2(a, b) return a + b end -- -- Funkce se tremi parametry -- function test3(a, b, c) return a + b + c end -- -- Funkce se ctyrmi parametry -- function test4(a, b, c, d) return a + b + c + d end -- -- Funkce s peti parametry -- function test5(a, b, c, d, e) return a + b + c + d + e end -- -- Funkce se sesti parametry -- function test6(a, b, c, d, e, f) return a + b + c + d + e + f end -- -- Test. -- function main() print(test0()) print(test1(1)) print(test2(1, 2)) print(test3(1, 2, 3)) print(test4(1, 2, 3, 4)) print(test5(1, 2, 3, 4, 5)) print(test6(1, 2, 3, 4, 5, 6)) end main()
Z výpisu bajtkódu je patrné, že se pro předávání parametrů používají registry, což vede (mj. i díky tříadresovým kódům) k mnohem kratšímu bajtkódu, než jsme viděli v případě JVM (povšimněte si druhého řádku hlavičky každé funkce):
function <Test17.lua:10,12> (3 instructions at 0x90efc88) 0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions 1 [11] LOADK 0 -1 // načtení konstanty 42 do registru 0 2 [11] RETURN 0 2 // vrácení konstanty uložené v registru 0 3 [12] RETURN 0 1 // implicitně vkládáno překladačem function <Test17.lua:17,19> (2 instructions at 0x90efe60) 1 param, 2 slots, 0 upvalues, 1 local, 0 constants, 0 functions 1 [18] RETURN 0 2 // vrácení konstanty uložené v registru 0 2 [19] RETURN 0 1 // implicitně vkládáno překladačem function <Test17.lua:24,26> (3 instructions at 0x90effc0) 2 params, 3 slots, 0 upvalues, 2 locals, 0 constants, 0 functions 1 [25] ADD 2 0 1 // do registru 2 se uloží součet registrů 0 a 1 2 [25] RETURN 2 2 // vrácení konstanty uložené v registru 2 3 [26] RETURN 0 1 // implicitně vkládáno překladačem function <Test17.lua:31,33> (4 instructions at 0x90efe08) 3 params, 4 slots, 0 upvalues, 3 locals, 0 constants, 0 functions 1 [32] ADD 3 0 1 // do registru 3 se uloží součet registrů 0 a 1 2 [32] ADD 3 3 2 // k registru 3 se připočte obsah registru 2 3 [32] RETURN 3 2 // vrácení konstanty uložené v registru 3 4 [33] RETURN 0 1 // implicitně vkládáno překladačem function <Test17.lua:38,40> (5 instructions at 0x90f0408) 4 params, 5 slots, 0 upvalues, 4 locals, 0 constants, 0 functions 1 [39] ADD 4 0 1 // do registru 4 se uloží součet registrů 0 a 1 2 [39] ADD 4 4 2 // k registru 4 se připočte obsah registru 2 3 [39] ADD 4 4 3 // k registru 4 se připočte obsah registru 3 4 [39] RETURN 4 2 // vrácení konstanty uložené v registru 4 5 [40] RETURN 0 1 // implicitně vkládáno překladačem function <Test17.lua:45,47> (6 instructions at 0x90f0110) 5 params, 6 slots, 0 upvalues, 5 locals, 0 constants, 0 functions 1 [46] ADD 5 0 1 // do registru 5 se uloží součet registrů 0 a 1 2 [46] ADD 5 5 2 // k registru 5 se připočte obsah registru 2 3 [46] ADD 5 5 3 // k registru 5 se připočte obsah registru 3 4 [46] ADD 5 5 4 // k registru 5 se připočte obsah registru 4 5 [46] RETURN 5 2 // vrácení konstanty uložené v registru 5 6 [47] RETURN 0 1 // implicitně vkládáno překladačem function <Test17.lua:52,54> (7 instructions at 0x90f0658) 6 params, 7 slots, 0 upvalues, 6 locals, 0 constants, 0 functions 1 [53] ADD 6 0 1 // do registru 6 se uloží součet registrů 0 a 1 2 [53] ADD 6 6 2 // k registru 6 se připočte obsah registru 2 3 [53] ADD 6 6 3 // k registru 6 se připočte obsah registru 3 4 [53] ADD 6 6 4 // k registru 6 se připočte obsah registru 4 5 [53] ADD 6 6 5 // k registru 6 se připočte obsah registru 5 6 [53] RETURN 6 2 // vrácení konstanty uložené v registru 6 7 [54] RETURN 0 1 // implicitně vkládáno překladačem function <Test17.lua:59,67> (50 instructions at 0x90f0760) 0 params, 8 slots, 1 upvalue, 0 locals, 14 constants, 0 functions 1 [60] GETTABUP 0 0 -1 // příprava na volání funkce "print" 2 [60] GETTABUP 1 0 -2 // příprava na volání funkce "test0" 3 [60] CALL 1 1 0 // zavolání funkce "test0" 4 [60] CALL 0 0 1 // zavolání funkce "print" 5 [61] GETTABUP 0 0 -1 // příprava na volání funkce "print" 6 [61] GETTABUP 1 0 -3 // příprava na volání funkce "test1" 7 [61] LOADK 2 -4 // vložit do registru 2 parametr číslo 1 8 [61] CALL 1 2 0 // zavolání funkce "test1" 9 [61] CALL 0 0 1 // zavolání funkce "print" 10 [62] GETTABUP 0 0 -1 // příprava na volání funkce "print" 11 [62] GETTABUP 1 0 -5 // příprava na volání funkce "test2" 12 [62] LOADK 2 -4 // vložit do registru 2 parametr číslo 1 13 [62] LOADK 3 -6 // vložit do registru 3 parametr číslo 2 14 [62] CALL 1 3 0 // zavolání funkce "test2" 15 [62] CALL 0 0 1 // zavolání funkce "print" 16 [63] GETTABUP 0 0 -1 // příprava na volání funkce "print" 17 [63] GETTABUP 1 0 -7 // příprava na volání funkce "test3" 18 [63] LOADK 2 -4 // vložit do registru 2 parametr číslo 1 19 [63] LOADK 3 -6 // vložit do registru 3 parametr číslo 2 20 [63] LOADK 4 -8 // vložit do registru 4 parametr číslo 3 21 [63] CALL 1 4 0 // zavolání funkce "test3" 22 [63] CALL 0 0 1 // zavolání funkce "print" 23 [64] GETTABUP 0 0 -1 // příprava na volání funkce "print" 24 [64] GETTABUP 1 0 -9 // příprava na volání funkce "test4" 25 [64] LOADK 2 -4 // vložit do registru 2 parametr číslo 1 26 [64] LOADK 3 -6 // vložit do registru 3 parametr číslo 2 27 [64] LOADK 4 -8 // vložit do registru 4 parametr číslo 3 28 [64] LOADK 5 -10 // vložit do registru 5 parametr číslo 4 29 [64] CALL 1 5 0 // zavolání funkce "test4" 30 [64] CALL 0 0 1 // zavolání funkce "print" 31 [65] GETTABUP 0 0 -1 // příprava na volání funkce "print" 32 [65] GETTABUP 1 0 -11 // příprava na volání funkce "test5" 33 [65] LOADK 2 -4 // vložit do registru 2 parametr číslo 1 34 [65] LOADK 3 -6 // vložit do registru 3 parametr číslo 2 35 [65] LOADK 4 -8 // vložit do registru 4 parametr číslo 3 36 [65] LOADK 5 -10 // vložit do registru 5 parametr číslo 4 37 [65] LOADK 6 -12 // vložit do registru 6 parametr číslo 5 38 [65] CALL 1 6 0 // zavolání funkce "test5" 39 [65] CALL 0 0 1 // zavolání funkce "print" 40 [66] GETTABUP 0 0 -1 // příprava na volání funkce "print" 41 [66] GETTABUP 1 0 -13 // příprava na volání funkce "test6" 42 [66] LOADK 2 -4 // vložit do registru 2 parametr číslo 1 43 [66] LOADK 3 -6 // vložit do registru 3 parametr číslo 2 44 [66] LOADK 4 -8 // vložit do registru 4 parametr číslo 3 45 [66] LOADK 5 -10 // vložit do registru 5 parametr číslo 4 46 [66] LOADK 6 -12 // vložit do registru 6 parametr číslo 5 47 [66] LOADK 7 -14 // vložit do registru 7 parametr číslo 6 48 [66] CALL 1 7 0 // zavolání funkce "test6" 49 [66] CALL 0 0 1 // zavolání funkce "print" 50 [67] RETURN 0 1 // implicitně vkládáno překladačem
6. Předávání parametrů funkcím v Python VM: demonstrační příklad Test17.py
Zbývá nám ukázka způsobu předávání parametrů volaným funkcím v Python VM. Nejprve se opět podívejme na zdrojový kód demonstračního příkladu:
# # Ukazka predavani parametru do volanych funkci. # # # Funkce bez parametru. # def test0(): return 42 # # Funkce s jednim parametrem # def test1(a): return a # # Funkce se dvema parametry # def test2(a, b): return a + b # # Funkce se tremi parametry # def test3(a, b, c): return a + b + c # # Funkce se ctyrmi parametry # def test4(a, b, c, d): return a + b + c + d # # Funkce s peti parametry # def test5(a, b, c, d, e): return a + b + c + d + e # # Funkce se sesti parametry # def test6(a, b, c, d, e, f): return a + b + c + d + e + f # # Test. # def main(): print(test0()) print(test1(1)) print(test2(1, 2)) print(test3(1, 2, 3)) print(test4(1, 2, 3, 4)) print(test5(1, 2, 3, 4, 5)) print(test6(1, 2, 3, 4, 5, 6)) # # Ukazka disasembleru. # def disassemble(): from dis import dis print("\ntest0:") dis(test0) print("\ntest1:") dis(test1) print("\ntest2:") dis(test2) print("\ntest3:") dis(test3) print("\ntest4:") dis(test4) print("\ntest5:") dis(test5) print("\ntest6:") dis(test6) main() disassemble()
Následuje bajtkód vzniklý překladem tohoto demonstračního příkladu:
test0: 11 0 LOAD_CONST // uložit konstantu 42 na zásobník 3 RETURN_VALUE // návrat z funkce s předáním výsledku test1: 19 0 LOAD_FAST 0 // uložit hodnotu parametru a na zásobník 3 RETURN_VALUE // návrat z funkce s předáním výsledku test2: 27 0 LOAD_FAST 0 // uložit hodnotu parametru a na zásobník 3 LOAD_FAST 1 // uložit hodnotu parametru b na zásobník 6 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 7 RETURN_VALUE // návrat z funkce s předáním výsledku test3: 35 0 LOAD_FAST 0 // uložit hodnotu parametru a na zásobník 3 LOAD_FAST 1 // uložit hodnotu parametru b na zásobník 6 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 7 LOAD_FAST 2 // uložit hodnotu parametru c na zásobník 10 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 11 RETURN_VALUE // návrat z funkce s předáním výsledku test4: 43 0 LOAD_FAST 0 // uložit hodnotu parametru a na zásobník 3 LOAD_FAST 1 // uložit hodnotu parametru b na zásobník 6 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 7 LOAD_FAST 2 // uložit hodnotu parametru c na zásobník 10 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 11 LOAD_FAST 3 // uložit hodnotu parametru d na zásobník 14 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 15 RETURN_VALUE // návrat z funkce s předáním výsledku test5: 51 0 LOAD_FAST 0 // uložit hodnotu parametru a na zásobník 3 LOAD_FAST 1 // uložit hodnotu parametru b na zásobník 6 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 7 LOAD_FAST 2 // uložit hodnotu parametru c na zásobník 10 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 11 LOAD_FAST 3 // uložit hodnotu parametru d na zásobník 14 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 15 LOAD_FAST 4 // uložit hodnotu parametru e na zásobník 18 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 19 RETURN_VALUE // návrat z funkce s předáním výsledku test6: 59 0 LOAD_FAST 0 // uložit hodnotu parametru a na zásobník 3 LOAD_FAST 1 // uložit hodnotu parametru b na zásobník 6 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 7 LOAD_FAST 2 // uložit hodnotu parametru c na zásobník 10 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 11 LOAD_FAST 3 // uložit hodnotu parametru d na zásobník 14 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 15 LOAD_FAST 4 // uložit hodnotu parametru e na zásobník 18 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 19 LOAD_FAST 5 // uložit hodnotu parametru f na zásobník 22 BINARY_ADD // provést součet dvou hodnot uložených na TOS a TOS-1 23 RETURN_VALUE // návrat z funkce s předáním výsledku
7. Složené datové typy v JVM, Lua VM a Python VM
Ve druhé polovině tohoto článku se budeme zabývat podporou složených datových typů v bajtkódech JVM, Lua VM i Python VM. Virtuální stroj jazyka Java podporuje jako (doposud) jediný složený datový typ pouze pole, a to jak pole obsahující primitivní datové typy, tak i pole obsahující reference na objekty. Pole může mít jednu dimenzi či větší počet dimenzí.
V případě programovacího jazyka Lua a tím pádem i Lua VM se namísto polí používají tabulky, které lze používat dvěma způsoby – buď jako skutečné pole nebo jako asociativní pole. V prvním případě jsou prvky pole indexovány od jedničky, což má ve vysokoúrovňovém jazyce větší smysl, než indexace od nuly (ta byla vynucena v céčku kvůli ukazatelové aritmetice, z céčka se pak tento způsob dostal i do Javy a dokonce i do JavaScriptu). Ve druhém případě se do tabulky ukládají dvojice klíč:hodnota, kde klíč musí být unikátní a nesmí mít hodnotu nil.
V Python VM se taktéž nepoužívají klasická pole; namísto toho nabízí tento programovací jazyk poněkud flexibilnější seznamy a taktéž n-tice (které jsou neměnitelné).
Podívejme se nyní na základní instrukce bajtkódu sloužící pro práci se zmíněnými složenými datovými typy:
Java | Instrukce | Význam |
---|---|---|
1 | newarray | konstrukce jednorozměrného pole |
2 | multianewarray | konstrukce vícerozměrného pole |
Lua | Instrukce | Význam |
1 | NEWTABLE | vytvoření tabulky o zadané kapacitě |
2 | SETLIST | inicializace více položek tabulky |
3 | SETTABLE | vložení nové hodnoty či dvojice klíč:hodnota do tabulky |
Python | Instrukce | Význam |
1 | BUILD_LIST | vytvoření seznamu |
2 | BUILD_TUPLE | vytvoření n-tice |
8. Demonstrační příklad Test19.java: konstrukce jednorozměrných polí
Způsob použití instrukce newarray si ukážeme na jednoduchém demonstračním příkladu, v jehož třídě je deklarována jediná (statická) metoda, po jejímž zavolání se vytvoří osm lokálních proměnných, přičemž každá proměnná je referencí na pole zadané délky. Zdrojový kód tohoto demonstračního příkladu je skutečně velmi jednoduchý:
/** * Vytvareni (konstrukce) poli. */ public class Test19 { static void createArrays(int size) { boolean[] booleanArray = new boolean[size]; char[] charArray = new char[size]; byte[] byteArray = new byte[size]; short[] shortArray = new short[size]; int[] intArray = new int[size]; long[] longArray = new long[size]; float[] floatArray = new float[size]; double[] doubleegerArray = new double[size]; } }
Překladač javac vygeneruje bajtkód, v němž jsou použity instrukce pro vytvoření všech osmi lokálních proměnných, i když ve skutečnosti nejsou tyto proměnné nikde použity. Z výpisu je patrné, že každé pole je vytvořeno s využitím pouze třech instrukcí – uložení počtu prvků vytvářeného pole na zásobník, vlastní vytvoření (konstrukce) pole a nakonec uložení reference do lokální proměnné:
static void createArrays(int); Code: 0: iload_0 // na TOS zásobníku operandů se uloží délka vytvářeného pole 1: newarray boolean // vytvoření pole s prvky typu boolean 3: astore_1 // reference na pole se uloží do lokální proměnné 4: iload_0 // na TOS zásobníku operandů se uloží délka vytvářeného pole 5: newarray char // vytvoření pole s prvky typu char 7: astore_2 // reference na pole se uloží do lokální proměnné 8: iload_0 // na TOS zásobníku operandů se uloží délka vytvářeného pole 9: newarray byte // vytvoření pole s prvky typu byte 11: astore_3 // reference na pole se uloží do lokální proměnné 12: iload_0 // na TOS zásobníku operandů se uloží délka vytvářeného pole 13: newarray short // vytvoření pole s prvky typu short 15: astore 4 // reference na pole se uloží do lokální proměnné 17: iload_0 // na TOS zásobníku operandů se uloží délka vytvářeného pole 18: newarray int // vytvoření pole s prvky typu int 20: astore 5 // reference na pole se uloží do lokální proměnné 22: iload_0 // na TOS zásobníku operandů se uloží délka vytvářeného pole 23: newarray long // vytvoření pole s prvky typu long 25: astore 6 // reference na pole se uloží do lokální proměnné 27: iload_0 // na TOS zásobníku operandů se uloží délka vytvářeného pole 28: newarray float // vytvoření pole s prvky typu float 30: astore 7 // reference na pole se uloží do lokální proměnné 32: iload_0 // na TOS zásobníku operandů se uloží délka vytvářeného pole 33: newarray double // vytvoření pole s prvky typu double 35: astore 8 // reference na pole se uloží do lokální proměnné 37: return // návrat z metody }
9. Demonstrační příklad Test20.java: konstrukce vícerozměrných polí
I v dalším demonstračním příkladu nazvaném Test20 se budou vytvářet pole, ovšem v tomto případě se bude jednat o pole dvourozměrná, což znamená, že se v bajtkódu využije odlišná instrukce pro konstrukci těchto polí:
/** * Vytvareni (konstrukce) vicerozmernych poli. */ public class Test20 { static void createArrays(int size1, int size2) { boolean[][] booleanArray = new boolean[size1][size2]; char[][] charArray = new char[size1][size2]; byte[][] byteArray = new byte[size1][size2]; short[][] shortArray = new short[size1][size2]; int[][] intArray = new int[size1][size2]; long[][] longArray = new long[size1][size2]; float[][] floatArray = new float[size1][size2]; double[][] doubleArray = new double[size1][size2]; } }
Překladač javac v tomto případě vygeneruje bajtkód, v němž je použita instrukce multianewarray, které se předá jak počet dimenzí vytvářeného pole, tak i rozměry dimenzí (ty jsou uloženy na zásobníku operandů) a typ pole (ten je uložen v constant poolu). Vytvoření každého pole je v tomto případě implementováno ve čtyřech instrukcích bajtkódu:
Compiled from "Test20.java" public class Test20 extends java.lang.Object{ static void createArrays(int, int); Code: 0: iload_0 // rozměr první dimenze pole 1: iload_1 // rozměr druhé dimenze pole 2: multianewarray #2, 2; // class "[[Z" (dvourozměrné pole prvků typu boolean) 6: astore_2 // uložení výsledku (nového pole) do lokální proměnné 7: iload_0 // rozměr první dimenze pole 8: iload_1 // rozměr druhé dimenze pole 9: multianewarray #3, 2; // class "[[C" (dvourozměrné pole prvků typu char) 13: astore_3 // uložení výsledku (nového pole) do lokální proměnné 14: iload_0 // rozměr první dimenze pole 15: iload_1 // rozměr druhé dimenze pole 16: multianewarray #4, 2; // class "[[B" (dvourozměrné pole prvků typu byte) 20: astore 4 // uložení výsledku (nového pole) do lokální proměnné 22: iload_0 // rozměr první dimenze pole 23: iload_1 // rozměr druhé dimenze pole 24: multianewarray #5, 2; // class "[[S" (dvourozměrné pole prvků typu short) 28: astore 5 // uložení výsledku (nového pole) do lokální proměnné 30: iload_0 // rozměr první dimenze pole 31: iload_1 // rozměr druhé dimenze pole 32: multianewarray #6, 2; // class "[[I" (dvourozměrné pole prvků typu int) 36: astore 6 // uložení výsledku (nového pole) do lokální proměnné 38: iload_0 // rozměr první dimenze pole 39: iload_1 // rozměr druhé dimenze pole 40: multianewarray #7, 2; // class "[[J" (dvourozměrné pole prvků typu long) 44: astore 7 // uložení výsledku (nového pole) do lokální proměnné 46: iload_0 // rozměr první dimenze pole 47: iload_1 // rozměr druhé dimenze pole 48: multianewarray #8, 2; // class "[[F" (dvourozměrné pole prvků typu float) 52: astore 8 // uložení výsledku (nového pole) do lokální proměnné 54: iload_0 // rozměr první dimenze pole 55: iload_1 // rozměr druhé dimenze pole 56: multianewarray #9, 2; // class "[[D" (dvourozměrné pole prvků typu double) 60: astore 9 // uložení výsledku (nového pole) do lokální proměnné 62: return // návrat z metody }
10. Demonstrační příklad Test19.lua: vytvoření tabulek
V demonstračním příkladu nazvaném Test19.lua je ukázáno vytvoření tabulky obsahující několik číselných položek a dále tabulky, jejíž prvky jsou taktéž tabulky, takže výsledkem je vlastně matice o velikosti 3×3 prvky. Povšimněte si taktéž způsobu výpisu obsahu tabulek s využitím funkce pairs() vracející iterátor. V tomto případě by bylo možné použít i funkci ipairs(), je ovšem dobré vědět, že i „normální“ tabulky mohou vracet pro své prvky klíče:
-- -- Vytvoreni tabulky. -- -- -- Vytvoreni jednoduche tabulky. -- function test0() local tabulka = {1, 3, 5, 7, 11, 13, 17} return tabulka end -- -- Vytvoreni vnorene tabulky. -- function test1() local matice = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} return matice end -- -- Test. -- function main() local x = test0() for key,val in pairs(x) do print("table[" .. key .. "] = " .. val) end print() local y = test1() for i,vector in pairs(y) do for j,item in pairs(vector) do print("table[" .. i .. "," .. j .. "] = " .. item) end end end main()
Bajtkód vygenerovaný překladem demonstračního příkladu Test19.lua je poměrně zajímavý, protože zde najdeme vysokoúrovňové instrukce NEWTABLE (vytvoření tabulky), SETLIST (nastavení prvků tabulky) i TFORCALL+TFORLOOP (smyčka typu foreach vysvětlená příště):
function <Test19.lua:10,13> (11 instructions at 0x817bc88) 0 params, 8 slots, 0 upvalues, 1 local, 7 constants, 0 functions 1 [11] NEWTABLE 0 7 0 // konstrukce nové tabulky o velikosti 7 položek 2 [11] LOADK 1 -1 // uložit konstantu 1 do registru 3 [11] LOADK 2 -2 // uložit konstantu 3 do registru 4 [11] LOADK 3 -3 // uložit konstantu 5 do registru 5 [11] LOADK 4 -4 // uložit konstantu 7 do registru 6 [11] LOADK 5 -5 // uložit konstantu 11 do registru 7 [11] LOADK 6 -6 // uložit konstantu 13 do registru 8 [11] LOADK 7 -7 // uložit konstantu 17 do registru 9 [11] SETLIST 0 7 1 // inicializace položek 10 [12] RETURN 0 2 // tabulka je návratovou hodnotou 11 [13] RETURN 0 1 // implicitně vkládáno překladačem function <Test19.lua:20,23> (19 instructions at 0x817c0f0) 0 params, 7 slots, 0 upvalues, 1 local, 9 constants, 0 functions 1 [21] NEWTABLE 0 3 0 // konstrukce nové tabulky o velikosti 3 položek 2 [21] NEWTABLE 1 3 0 // konstrukce nové podtabulky o velikosti 3 položek 3 [21] LOADK 2 -1 // uložit konstantu 1 do registru 4 [21] LOADK 3 -2 // uložit konstantu 2 do registru 5 [21] LOADK 4 -3 // uložit konstantu 3 do registru 6 [21] SETLIST 1 3 1 // inicializace položek podtabulky 7 [21] NEWTABLE 2 3 0 // konstrukce nové podtabulky o velikosti 3 položek 8 [21] LOADK 3 -4 // uložit konstantu 4 do registru 9 [21] LOADK 4 -5 // uložit konstantu 5 do registru 10 [21] LOADK 5 -6 // uložit konstantu 6 do registru 11 [21] SETLIST 2 3 1 // inicializace položek tabulky 12 [21] NEWTABLE 3 3 0 // konstrukce nové podtabulky o velikosti 3 položek 13 [21] LOADK 4 -7 // uložit konstantu 7 do registru 14 [21] LOADK 5 -8 // uložit konstantu 8 do registru 15 [21] LOADK 6 -9 // uložit konstantu 9 do registru 16 [21] SETLIST 3 3 1 // inicializace položek tabulky 17 [21] SETLIST 0 3 1 // inicializace položek (podtabulek) hlavní tabulky 18 [22] RETURN 0 2 // tabulka je návratovou hodnotou 19 [23] RETURN 0 1 // implicitně vkládáno překladačem function <Test19.lua:30,44> (41 instructions at 0x817c630) 0 params, 19 slots, 1 upvalue, 17 locals, 7 constants, 0 functions 1 [31] GETTABUP 0 0 -1 // příprava na volání funkce "test0" 2 [31] CALL 0 1 2 3 [32] GETTABUP 1 0 -2 // příprava na volání funkce "pairs" 4 [32] MOVE 2 0 5 [32] CALL 1 2 4 // zavolání funkce "pairs" 6 [32] JMP 0 7 ; to 14 7 [33] GETTABUP 6 0 -3 // příprava na volání funkce "print" 8 [33] LOADK 7 -4 ; "table[" 9 [33] MOVE 8 4 10 [33] LOADK 9 -5 ; "] = " 11 [33] MOVE 10 5 12 [33] CONCAT 7 7 10 13 [33] CALL 6 2 1 // zavolání funkce "print" 14 [32] TFORCALL 1 2 15 [32] TFORLOOP 3 -9 ; to 7 16 [36] GETTABUP 1 0 -3 // příprava na volání funkce "print" 17 [36] CALL 1 1 1 18 [38] GETTABUP 1 0 -6 // příprava na volání funkce "test1" 19 [38] CALL 1 1 2 20 [39] GETTABUP 2 0 -2 // příprava na volání funkce "pairs" 21 [39] MOVE 3 1 22 [39] CALL 2 2 4 // zavolání funkce "pairs" 23 [39] JMP 0 15 ; to 39 24 [40] GETTABUP 7 0 -2 // příprava na volání funkce "pairs" 25 [40] MOVE 8 6 26 [40] CALL 7 2 4 // zavolání funkce "pairs" 27 [40] JMP 0 9 ; to 37 28 [41] GETTABUP 12 0 -3// příprava na volání funkce "print" 29 [41] LOADK 13 -4 ; "table[" 30 [41] MOVE 14 5 31 [41] LOADK 15 -7 ; "," 32 [41] MOVE 16 10 33 [41] LOADK 17 -5 ; "] = " 34 [41] MOVE 18 11 35 [41] CONCAT 13 13 18 36 [41] CALL 12 2 1 // zavolání funkce "print" 37 [40] TFORCALL 7 2 38 [40] TFORLOOP 9 -11 ; to 28 39 [39] TFORCALL 2 2 40 [39] TFORLOOP 4 -17 ; to 24 41 [44] RETURN 0 1 // implicitně vkládáno překladačem
11. Demonstrační příklad Test20.lua: vytvoření asociativního pole
V demonstračním příkladu nazvaném Test20.lua je vytvořeno asociativní pole s pěticí dvojic klíč:hodnota, jehož obsah je následně vypsán na standardní výstup s využitím programové smyčky typu foreach:
-- -- Vytvoreni asociativniho pole. -- -- -- Vytvoreni asociativniho pole. -- function test0() local pole = {first=1, second=3, third=5, fourth=7, fifth=11} return pole end -- -- Test. -- function main() local x = test0() for key,val in pairs(x) do print("table[" .. key .. "] = " .. val) end end main()
Podívejme se nyní na bajtkód vytvořený překladem demonstračního příkladu Test20.lua. Můžeme zde vidět již známou instrukci NEWTABLE a taktéž novou instrukci SETTABLE sloužící pro přidání prvku do asociativního pole:
function <Test20.lua:10,13> (8 instructions at 0x961ec88) 0 params, 2 slots, 0 upvalues, 1 local, 10 constants, 0 functions 1 [11] NEWTABLE 0 0 5 // konstrukce nové tabulky o velikosti 5 položek 2 [11] SETTABLE 0 -1 -2 // vložení nové dvojice ("first" 1) do tabulky 3 [11] SETTABLE 0 -3 -4 // vložení nové dvojice ("second" 3) do tabulky 4 [11] SETTABLE 0 -5 -6 // vložení nové dvojice ("third" 5) do tabulky 5 [11] SETTABLE 0 -7 -8 // vložení nové dvojice ("fourth" 7) do tabulky 6 [11] SETTABLE 0 -9 -10 // vložení nové dvojice ("fifth" 11) do tabulky 7 [12] RETURN 0 2 // tabulka je návratovou hodnotou 8 [13] RETURN 0 1 // implicitně vkládáno překladačem function <Test20.lua:20,25> (16 instructions at 0x961f178) 0 params, 11 slots, 1 upvalue, 6 locals, 5 constants, 0 functions 1 [21] GETTABUP 0 0 -1 // příprava na volání funkce "test0" 2 [21] CALL 0 1 2 3 [22] GETTABUP 1 0 -2 // příprava na volání funkce "pairs" 4 [22] MOVE 2 0 5 [22] CALL 1 2 4 // zavolání funkce "pairs" 6 [22] JMP 0 7 ; to 14 7 [23] GETTABUP 6 0 -3 // příprava na volání funkce "print" 8 [23] LOADK 7 -4 ; "table[" 9 [23] MOVE 8 4 10 [23] LOADK 9 -5 ; "] = " 11 [23] MOVE 10 5 12 [23] CONCAT 7 7 10 13 [23] CALL 6 2 1 // zavolání funkce "print" 14 [22] TFORCALL 1 2 15 [22] TFORLOOP 3 -9 ; to 7 16 [25] RETURN 0 1 // implicitně vkládáno překladačem
12. Demonstrační příklad Test19.py: vytvoření seznamu
V demonstračním příkladu nazvaném Test19.py je ukázáno vytvoření seznamu obsahujícího několik číselných položek a dále pak seznamu obsahujícího jako své prvky podseznamy (toto je jedna z možností, jak v Pythonu vytvořit obdobu matic):
# # Vytvoreni seznamu. # # # Vytvoreni jednoducheho seznamu. # def test0(): ntice = [1, 2, 3, 4] return ntice # # Vytvoreni seznamu seznamu. # def test1(): pole = [[1, 2], [3, 4]] return pole # # Test. # def main(): print(test0()) print(test1()) # # Ukazka disasembleru. # def disassemble(): from dis import dis print("\ntest0:") dis(test0) print("\ntest1:") dis(test1) main() disassemble()
Následuje bajtkód vzniklý překladem tohoto demonstračního příkladu:
test0: 11 0 LOAD_CONST 1 // načtení konstanty 1 3 LOAD_CONST 2 // načtení konstanty 2 6 LOAD_CONST 3 // načtení konstanty 3 9 LOAD_CONST 4 // načtení konstanty 4 12 BUILD_LIST 4 // vytvoření seznamu o velikosti čtyři položky 15 STORE_FAST 0 // uložit referenci do lokální proměnné 12 18 LOAD_FAST 0 // uložit referenci na seznam na TOS 21 RETURN_VALUE // vrácení seznamu test1: 20 0 LOAD_CONST 1 // načtení konstanty 1 3 LOAD_CONST 2 // načtení konstanty 2 6 BUILD_LIST 2 // vytvoření podseznamu o velikosti dvě položky 9 LOAD_CONST 3 // načtení konstanty 3 12 LOAD_CONST 4 // načtení konstanty 4 15 BUILD_LIST 2 // vytvoření podseznamu o velikosti dvě položky 18 BUILD_LIST 2 // vytvoření seznamu o velikosti dvě položky typu podseznam 21 STORE_FAST 0 // uložit referenci na pole na TOS 21 24 LOAD_FAST 0 // uložit referenci na pole na TOS 27 RETURN_VALUE // vrácení pole
13. Demonstrační příklad Test19.py: vytvoření n-tice
Demonstrační příklad nazvaný Test20.py se v mnoha ohledech podobá předchozímu demonstračnímu příkladu, ovšem s tím (poměrně závažným) rozdílem, že se namísto seznamů vytváří n-tice, a to jak n-tice obsahující číselné konstanty, tak i n-tice obsahující další pod-n-tice :-) jako své prvky:
# # Vytvoreni n-tice. # # # Vytvoreni jednoduche n-tice. # def test0(): seznam = (1, 2, 3, 4) return seznam # # Vytvoreni n-tice n-tic. # def test1(): pole = ((1, 2), (3, 4)) return pole # # Test. # def main(): print(test0()) print(test1()) # # Ukazka disasembleru. # def disassemble(): from dis import dis print("\ntest0:") dis(test0) print("\ntest1:") dis(test1) main() disassemble()
Opět následuje bajtkód vzniklý překladem tohoto demonstračního příkladu:
test0: 11 0 LOAD_CONST 5 // n-tice je konstanta ((1, 2, 3, 4)) 3 STORE_FAST 0 // do lokální proměnné 12 6 LOAD_FAST 0 // načtení lokální proměnné na TOS 9 RETURN_VALUE // vrácení n-tice test1: 19 0 LOAD_CONST 5 // n-tice je konstanta ((1, 2)) 3 LOAD_CONST 6 // n-tice je konstanta ((3, 4)) 6 BUILD_TUPLE 2 // vytvoření n-tice 9 STORE_FAST 0 // do lokální proměnné 20 12 LOAD_FAST 0 // načtení lokální proměnné na TOS 15 RETURN_VALUE // vrácení pole
14. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů
Všechny dnes popsané a využité demonstrační příklady (naprogramované v Javě, Lue i Pythonu) byly uloženy do Mercurial repositáře umístěného na adrese http://icedtea.classpath.org/people/ptisnovs/jvm-tools/. Odkazy na prozatím poslední verze těchto příkladů naleznete v tabulce pod tímto odstavcem:
15. Odkazy na Internetu
- Programming in Lua (first edition)
http://www.lua.org/pil/contents.html - Programming in Lua: Numeric for
http://www.lua.org/pil/4.3.4.html - Programming in Lua: break and return
http://www.lua.org/pil/4.4.html - Programming in Lua: Tables
http://www.lua.org/pil/2.5.html - Programming in Lua: Table Constructors
http://www.lua.org/pil/3.6.html - Programovací jazyk Lua
http://palmknihy.cz/web/kniha/programovaci-jazyk-lua-12651.htm - Lua: Tables Tutorial
http://lua-users.org/wiki/TablesTutorial - Lua: Control Structure Tutorial
http://lua-users.org/wiki/ControlStructureTutorial - Lua Types Tutorial
http://lua-users.org/wiki/LuaTypesTutorial - Goto Statement in Lua
http://lua-users.org/wiki/GotoStatement - Python break, continue and pass Statements
http://www.tutorialspoint.com/python/python_loop_control.htm - For Loop (Wikipedia)
http://en.wikipedia.org/wiki/For_loop - Heinz Rutishauser
http://en.wikipedia.org/wiki/Heinz_Rutishauser - Parrot
http://www.parrot.org/ - Parrot languages
http://www.parrot.org/languages - Parrot Primer
http://docs.parrot.org/parrot/latest/html/docs/intro.pod.html - Parrot Opcodes
http://docs.parrot.org/parrot/latest/html/ops.html - Parrot VM
http://en.wikibooks.org/wiki/Parrot_Virtual_Machine - Parrot Assembly Language
http://www.perl6.org/archive/pdd/pdd06_pasm.html - Parrot Reference: Chapter 11 – Perl 6 and Parrot Essentials
http://oreilly.com/perl/excerpts/perl-6-and-parrot-essentials/parrot-reference.html - Python Bytecode: Fun With Dis
http://akaptur.github.io/blog/2013/08/14/python-bytecode-fun-with-dis/ - Python's Innards: Hello, ceval.c!
http://tech.blog.aknin.name/category/my-projects/pythons-innards/ - Byterun
https://github.com/nedbat/byterun - Python Byte Code Instructions
http://document.ihg.uni-duisburg.de/Documentation/Python/lib/node56.html - Python Byte Code Instructions
https://docs.python.org/3.2/library/dis.html#python-bytecode-instructions - Lua 5.2 sources
http://www.lua.org/source/5.2/ - Lua 5.2 sources – lopcodes.h
http://www.lua.org/source/5.2/lopcodes.h.html - Lua 5.2 sources – lopcodes.c
http://www.lua.org/source/5.2/lopcodes.c.html - dis – Python module
https://docs.python.org/2/library/dis.html - Comparison of Python virtual machines
http://polishlinux.org/apps/cli/comparison-of-python-virtual-machines/ - O-code
http://en.wikipedia.org/wiki/O-code_machine - BCPL
http://en.wikipedia.org/wiki/BCPL - The BCPL Cintcode System and Cintpos User Guide by Martin Richards
http://www.cl.cam.ac.uk/users/mr/bcplman.pdf - Bootstrapping the BCPL Compiler using INTCODE
http://www.gtoal.com/languages/bcpl/amiga/bcpl/booting.txt - p-code machine
http://en.wikipedia.org/wiki/P-code_machine - ucsd-psystem-vm 0.11 (a portable virtual machine for the UCSD p-System)
http://ucsd-psystem-vm.sourceforge.net/ - Introduction to Smalltalk bytecodes
http://marianopeck.wordpress.com/2011/05/21/introduction-to-smalltalk-bytecodes/ - Audio File Formats.
http://sox.sourceforge.net/AudioFormats-11.html - TestSounds.com: pure digital sounds to test your audio
http://www.testsounds.com/ - Test Tones (20hz – 20khz)
http://mdf1.tripod.com/test-tones.html - WAV (Wikipedia)
http://en.wikipedia.org/wiki/WAV - WAVE PCM soundfile format
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ - Audio Interchange File Format
http://en.wikipedia.org/wiki/Aiff - Musical Instrument Digital Interface,
http://en.wikipedia.org/wiki/Musical_Instrument_Digital_Interface - A MIDI Pedalboard Encode,
http://www.pykett.org.uk/a_midi_pedalboard_encoder.htm - MIDI Note Number, Frequency Table,
http://tonalsoft.com/pub/news/pitch-bend.aspx - Note names, MIDI numbers and frequencies,
http://www.phys.unsw.edu.au/jw/notes.html - The MIDI Specification,
http://www.gweep.net/~prefect/eng/reference/protocol/midispec.html - Essentials of the MIDI protocol,
http://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html - General MIDI,
http://en.wikipedia.org/wiki/General_MIDI - Obecné MIDI (General MIDI),
http://www-kiv.zcu.cz/~herout/html_sbo/midi/5.html - Custom Chips: Paula
http://www.amiga-hardware.com/showhardware.cgi?HARDID=1460 - Big Book of Amiga Hardware
http://www.amiga-resistance.info/bboahfaq/ - Amiga Hardware Database
http://amiga.resource.cx/ - ExoticA
http://www.exotica.org.uk/wiki/Main_Page - The absolute basics of Amiga audio
http://www.sufo.estates.co.uk/amiga/amimus.html - Wikipedia: Tracker
http://en.wikipedia.org/wiki/Tracker - Wikipedia: Trackers
http://en.wikipedia.org/wiki/Trackers - Ultimate Soundtracker
http://en.wikipedia.org/wiki/Ultimate_Soundtracker - Protracker
http://en.wikipedia.org/wiki/ProTracker - Impulse Tracker
http://en.wikipedia.org/wiki/Impulse_Tracker - Scream Tracker
http://en.wikipedia.org/wiki/ScreamTracker - MikMod for Java
http://jmikmod.berlios.de/ - List of audio trackers
http://en.wikipedia.org/wiki/List_of_audio_trackers - Wikipedia: Module File
http://en.wikipedia.org/wiki/Module_file - Wikipedia: Chiptune
http://en.wikipedia.org/wiki/Chiptune - SDL_mixer 2.0
http://www.libsdl.org/projects/SDL_mixer/ - SDLJava: package sdljava.ttf
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/package-summary.html#package_description - SDLJava: class sdljava.ttf.SDLTTF
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTTF.html - SDLJava: class sdljava.ttf.SDLTrueTypeFont
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTrueTypeFont.html - SDL_ttf Documentation
http://www.libsdl.org/projects/SDL_ttf/docs/ - SDL_ttf 2.0 (není prozatím součástí SDLJava)
http://www.libsdl.org/projects/SDL_ttf/ - SDL_ttf doc
http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf_frame.html - SDL 1.2 Documentation: SDL_Surface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html - SDL 1.2 Documentation: SDL_PixelFormat
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html - SDL 1.2 Documentation: SDL_LockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html - SDL 1.2 Documentation: SDL_UnlockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html - SDL 1.2 Documentation: SDL_LoadBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html - SDL 1.2 Documentation: SDL_SaveBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html - SDL 1.2 Documentation: SDL_BlitSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html - SDL 1.2 Documentation: SDL_VideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html - SDL 1.2 Documentation: SDL_GetVideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html - glDrawArrays
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArrays.xml - glDrawElements
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElements.xml - glDrawArraysInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArraysInstanced.xml - glDrawElementsInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElementsInstanced.xml - Root.cz: Seriál Grafická knihovna OpenGL
http://www.root.cz/serialy/graficka-knihovna-opengl/ - Root.cz: Seriál Tvorba přenositelných grafických aplikací využívajících knihovnu GLUT
http://www.root.cz/serialy/tvorba-prenositelnych-grafickych-aplikaci-vyuzivajicich-knihovnu-glut/ - Best Practices for Working with Vertex Data
https://developer.apple.com/library/ios/documentation/3ddrawing/conceptual/opengles_programmingguide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html - Class BufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferStrategy.html - Class Graphics
http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Graphics.html - Double Buffering and Page Flipping
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html - BufferStrategy and BufferCapabilities
http://docs.oracle.com/javase/tutorial/extra/fullscreen/bufferstrategy.html - Java:Tutorials:Double Buffering
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering - Double buffer in standard Java AWT
http://www.codeproject.com/Articles/2136/Double-buffer-in-standard-Java-AWT - Java 2D: Hardware Accelerating – Part 1 – Volatile Images
http://www.javalobby.org/forums/thread.jspa?threadID=16840&tstart=0 - Java 2D: Hardware Accelerating – Part 2 – Buffer Strategies
http://www.javalobby.org/java/forums/t16867.html - How does paintComponent work?
http://stackoverflow.com/questions/15544549/how-does-paintcomponent-work - A Swing Architecture Overview
http://www.oracle.com/technetwork/java/architecture-142923.html - Class javax.swing.JComponent
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html - Class java.awt.Component
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html - Class java.awt.Component.BltBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.BltBufferStrategy.html - Class java.awt.Component.FlipBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.FlipBufferStrategy.html - Metoda java.awt.Component.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html#isDoubleBuffered() - Metoda javax.swing.JComponent.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#isDoubleBuffered() - Metoda javax.swing.JComponent.setDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#setDoubleBuffered(boolean) - Javadoc – třída GraphicsDevice
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsDevice.html - Javadoc – třída GraphicsEnvironment
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsEnvironment.html - Javadoc – třída GraphicsConfiguration
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsConfiguration.html - Javadoc – třída DisplayMode
http://docs.oracle.com/javase/7/docs/api/java/awt/DisplayMode.html - Lesson: Full-Screen Exclusive Mode API
http://docs.oracle.com/javase/tutorial/extra/fullscreen/ - Full-Screen Exclusive Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html - Display Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/displaymode.html - Using the Full-Screen Exclusive Mode API in Java
http://www.developer.com/java/other/article.php/3609776/Using-the-Full-Screen-Exclusive-Mode-API-in-Java.htm - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - MultiMedia eXtensions
http://softpixel.com/~cwright/programming/simd/mmx.phpi - SSE (Streaming SIMD Extentions)
http://www.songho.ca/misc/sse/sse.html - Timothy A. Chagnon: SSE and SSE2
http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf - Intel corporation: Extending the Worldr's Most Popular Processor Architecture
http://download.intel.com/technology/architecture/new-instructions-paper.pdf - SIMD architectures:
http://arstechnica.com/old/content/2000/03/simd.ars/ - GC safe-point (or safepoint) and safe-region
http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html - Safepoints in HotSpot JVM
http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html - Java theory and practice: Synchronization optimizations in Mustang
http://www.ibm.com/developerworks/java/library/j-jtp10185/ - How to build hsdis
http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/tools/hsdis/README - Java SE 6 Performance White Paper
http://www.oracle.com/technetwork/java/6-performance-137236.html - Lukas Stadler's Blog
http://classparser.blogspot.cz/2010/03/hsdis-i386dll.html - How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
http://dropzone.nfshost.com/hsdis.htm - PrintAssembly
https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly - The Java Virtual Machine Specification: 3.14. Synchronization
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.14 - The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4 - The Java Virtual Machine Specification: 17.4. Memory Model
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4 - The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7 - Open Source ByteCode Libraries in Java
http://java-source.net/open-source/bytecode-libraries - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - BCEL Home page
http://commons.apache.org/bcel/ - Byte Code Engineering Library (před verzí 5.0)
http://bcel.sourceforge.net/ - Byte Code Engineering Library (verze >= 5.0)
http://commons.apache.org/proper/commons-bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - Javassist
http://www.jboss.org/javassist/ - Byteman
http://www.jboss.org/byteman - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - jclasslib bytecode viewer
http://www.ej-technologies.com/products/jclasslib/overview.html