Obsah
1. Pohled pod kapotu JVM – volání funkcí a použití generátorů i uzávěrů v Python VM
2. Demonstrační příklad Test28.py: volání funkcí v Pythonu
3. Překlad demonstračního příkladu Test28.py do bajtkódu Python VM
4. Demonstrační příklad Test29.py: volání funkcí v Pythonu
5. Překlad demonstračního příkladu Test29.py do bajtkódu Python VM
6. Demonstrační příklad Test30.py: funkce s pojmenovanými parametry
7. Překlad demonstračního příkladu Test30.py do bajtkódu Python VM
8. Demonstrační příklad Test31.py: parametry s implicitní hodnotou
9. Překlad demonstračního příkladu Test31.py do bajtkódu Python VM
10. závěry a generátory v Pythonu
11. Repositář se zdrojovými kódy všech šesti dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – volání funkcí a použití generátorů i uzávěrů v Python VM
V předchozích třech částech seriálu o programovacím jazyku Java i o virtuálním stroji Javy jsme si vysvětlili způsob volání metod, funkcí i konstruktorů v JVM (přesněji řečeno v bajtkódu JVM) a taktéž v bajtkódu Lua VM. Zde již byla popisovaná problematika poněkud zajímavější, a to především z toho důvodu, že programovací jazyk Lua plně podporuje použití takzvaných uzávěrů (closures) (pro jejich konstrukci jsou určeny zvláštní instrukce v bajtkódu). Dnes si popíšeme způsob volání funkcí v bajtkódu virtuálního stroje Pythonu. Kromě volání „běžných“ funkcí si popíšeme i práci s generátory, pro jejichž implementaci je (kupodivu) v Pythonu vyhrazeno zvláštní klíčové slovo yield (v Lue se naproti tomu podobně koncipované koprogramy/coroutines vytváří jen s využitím k tomu určených funkcí, což je poněkud flexibilnější řešení).
2. Demonstrační příklad Test28.py: volání funkcí v Pythonu
Pro osvětlení některých sémantických rozdílů mezi programovacími jazyky Lua a Python byl vytvořen dnešní první demonstrační příklad nazvaný Test28.py. Jsou v něm implementovány funkce se jmény function1(), function2() a function3(), přičemž funkce function1() neočekává žádné argumenty, funkce function2() očekává jeden argument a konečně funkce function3() očekává dva argumenty, které jsou sečteny (přesněji řečeno je na ně aplikován operátor +, který lze přetížit). Všechny tři zmíněné funkce jsou volány z kódu, který je implementován v další trojici funkcí nazvaných callFunction1(), callFunction2() a callFunction3(), přičemž se počet skutečně použitých parametrů mění od nuly (žádné parametry) do dvou.
# # Demonstracni priklad cislo 28. # # Volani funkci v programovacim jazyce Python. # # # Funkce bez parametru. # def function1(): pass # # Funkce s jednim parametrem. # def function2(x): return x # # Funkce se dvema parametry. # def function3(x, y): if x and y: return x+y else: return None # # Volani funkce function1(). # def callFunction1(): function1() function1(None) function1(42) function1(1, 2) function1("xyzzy") # # Volani funkce function2(). # def callFunction2(): function2() function2(None) function2(42) function2(1, 2) function2("xyzzy") # # Volani funkce function3(). # def callFunction3(): function3() function3(None) function3(42) function3(1, 2) function3("xyzzy") # # Spusteni testu. # def main(): callFunction1() callFunction2() callFunction3() # # Ukazka disasembleru. # (prekladu funkci do bajtkodu Python VM). # def disassemble(): from dis import dis print("\nfunction1():") dis(function1) print("\nfunction2():") dis(function2) print("\nfunction3():") dis(function3) print("\ncallFunction1():") dis(callFunction1) print("\ncallFunction2():") dis(callFunction2) print("\ncallFunction3():") dis(callFunction3) main() #disassemble() # # Finito. #
Tento demonstrační příklad po svém spuštění skončí s chybou, protože v programovacím jazyku Python se kontroluje přesný počet (nikoli typ) argumentů, a to ve chvíli volání funkce (tj. v runtime, nikoli v compile time):
Traceback (most recent call last): File "Test28.py", line 94, in <module> main() File "Test28.py", line 76, in main callFunction1() File "Test28.py", line 41, in callFunction1 function1(None) TypeError: function1() takes no arguments (1 given)
Podobně koncipovaný příklad naprogramovaný v Lue lze však spustit bez problémů, jelikož zde jsou přebytečné argumenty ignorovány (popř. uloženy do tabulky) a naopak chybějící argumenty jsou ve chvíli volání funkce inicializovány na nil:
-- -- Demonstracni priklad cislo 25. -- -- Volani funkci v programovacim jazyce Lua. -- -- -- Funkce bez parametru. -- function function1() end -- -- Funkce s jednim parametrem. -- function function2(x) return x end -- -- Funkce se dvema parametry. -- function function3(x, y) if x and y then return x+y else return nil end end -- -- Volani funkce function1(). -- function callFunction1() function1() function1(nil) function1(42) function1(1, 2) function1("xyzzy") end -- -- Volani funkce function2(). -- function callFunction2() function2() function2(nil) function2(42) function2(1, 2) function2("xyzzy") end -- -- Volani funkce function3(). -- function callFunction3() function3() function3(nil) function3(42) function3(1, 2) function3("xyzzy") end -- -- Spusteni testu. -- function main() callFunction1() callFunction2() callFunction3() end main() -- -- Finito. --
3. Překlad demonstračního příkladu Test28.py do bajtkódu Python VM
I když při běhu demonstračního příkladu Test28.py dojde k (běhové) chybě, je překlad všech funkcí do bajtkódu Python VM proveden korektně, o čemž se ostatně můžeme snadno přesvědčit:
function1(): 13 0 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 3 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
function2(): 21 0 LOAD_FAST 0 (x) // uložit první (a jediný) parametr funkce na TOS 3 RETURN_VALUE // vrátit tuto hodnotu
function3(): 29 0 LOAD_FAST 0 (x) // uložit první parametr funkce na TOS 3 JUMP_IF_FALSE 16 (to 22) // skok pokud je první parametr None/false 6 POP_TOP // odstranit prvek z TOS 7 LOAD_FAST 1 (y) // uložit druhý parametr funkce na TOS 10 JUMP_IF_FALSE 9 (to 22) // skok pokud je druhý parametr None/false 13 POP_TOP // odstranit prvek z TOS 30 14 LOAD_FAST 0 (x) // uložit první parametr funkce na TOS 17 LOAD_FAST 1 (y) // uložit druhý parametr funkce na TOS 20 BINARY_ADD // aplikace operátoru + 21 RETURN_VALUE // vrátit tuto hodnotu 22 POP_TOP // odstranit prvek z TOS 32 23 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 26 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS) 27 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 30 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
(zde evidentně neproběhla žádná optimalizace bajtkódu, ostatně podobně jako v případě JVM i Lua VM).
callFunction1(): 40 0 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 3 CALL_FUNCTION 0 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 6 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 41 7 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 10 LOAD_CONST 0 (None) // skutečný parametr funkce uložit na TOS 13 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 16 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 42 17 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 20 LOAD_CONST 1 (42) // skutečný parametr funkce uložit na TOS 23 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 26 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 43 27 LOAD_GLOBAL 2 (function1) // načíst referenci volané funkce 30 LOAD_CONST 2 (1) // skutečný parametr funkce uložit na TOS 33 LOAD_CONST 3 (2) // skutečný parametr funkce uložit na TOS 36 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 39 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 44 40 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 43 LOAD_CONST 4 ('xyzzy') // skutečný parametr funkce uložit na TOS 46 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 49 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 50 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 53 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
callFunction2(): 52 0 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 3 CALL_FUNCTION 0 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 6 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 53 7 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 10 LOAD_CONST 0 (None) // skutečný parametr funkce uložit na TOS 13 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 16 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 54 17 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 20 LOAD_CONST 1 (42) // skutečný parametr funkce uložit na TOS 23 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 26 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 55 27 LOAD_GLOBAL 2 (function2) // načíst referenci volané funkce 30 LOAD_CONST 2 (1) // skutečný parametr funkce uložit na TOS 33 LOAD_CONST 3 (2) // skutečný parametr funkce uložit na TOS 36 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 39 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 56 40 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 43 LOAD_CONST 4 ('xyzzy') // skutečný parametr funkce uložit na TOS 46 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 49 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 50 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 53 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
callFunction3(): 64 0 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 3 CALL_FUNCTION 0 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 6 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 65 7 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 10 LOAD_CONST 0 (None) // skutečný parametr funkce uložit na TOS 13 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 16 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 66 17 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 20 LOAD_CONST 1 (42) // skutečný parametr funkce uložit na TOS 23 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 26 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 67 27 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 30 LOAD_CONST 2 (1) // skutečný parametr funkce uložit na TOS 33 LOAD_CONST 3 (2) // skutečný parametr funkce uložit na TOS 36 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 39 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 68 40 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 43 LOAD_CONST 4 ('xyzzy') // skutečný parametr funkce uložit na TOS 46 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 49 POP_TOP // odstranit prvek (návratovou hodnotu) z TOS 50 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 53 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
Z tohoto výpisu bajtkódu je způsob volání funkcí jasně patrný:
- Reference na volanou funkci je uložena na zásobník operandů
- Skutečné parametry jsou před voláním funkce předány (uloženy) na zásobník operandů
- Funkce je volána pomocí instrukce CALL_FUNCTION
- Návrat z funkce je řešen přes instrukci RETURN_VALUE
- Návratová hodnota je po návratu z volané funkce opět uložena na TOS zásobníku operandů
4. Demonstrační příklad Test29.py: volání funkcí v Pythonu
Dnešní druhý demonstrační příklad, který je nazvaný Test29.py, je již naprogramován korektně, tj. program po svém spuštění poběží bez chyby. V tomto příkladu jsou opět deklarovány tři funkce pojmenované function1(), function2() a function3(), přičemž první funkce neočekává žádné parametry, funkce druhá očekává jeden parametr a funkce třetí dva parametry. Způsob volání těchto tří funkcí je otestován v další trojici funkcí nazvaných callFunction1(), callFunction2() a callFunction3(). Povšimněte si, že se předávají parametry různého typu; konkrétně u funkce function3() je možné použít jakékoli dva parametry, na něž lze aplikovat operátor + (ten je zde mnohem flexibilnější, než operátor + v jazyce Lua nebo Java):
# # Demonstracni priklad cislo 29. # # Volani funkci v programovacim jazyce Python. # # # Funkce bez parametru. # def function1(): pass # # Funkce s jednim parametrem. # def function2(x): return x # # Funkce se dvema parametry. # def function3(x, y): return x+y # # Volani funkce function1(). # def callFunction1(): result = function1() print(result) # # Volani funkce function2(). # def callFunction2(): result1 = function2(None) result2 = function2(42) result3 = function2("xyzzy") result4 = function2([1,2,3]) result5 = function2((1,2,3)) print(result1) print(result2) print(result3) print(result4) print(result5) # # Volani funkce function3(). # def callFunction3(): result1 = function3(1, 2) result2 = function3("Hello ", "world") result3 = function3([1,2,3], [4,5,6]) result4 = function3((1,2,3), (4,5,6)) result5 = function3(["jedna", "dve"], ["Freddy", "jde"]) print(result1) print(result2) print(result3) print(result4) print(result5) # # Spusteni testu. # def main(): callFunction1() callFunction2() callFunction3() # # Ukazka disasembleru. # (prekladu funkci do bajtkodu Python VM). # def disassemble(): from dis import dis print("\nfunction1():") dis(function1) print("\nfunction2():") dis(function2) print("\nfunction3():") dis(function3) print("\ncallFunction1():") dis(callFunction1) print("\ncallFunction2():") dis(callFunction2) print("\ncallFunction3():") dis(callFunction3) main() #disassemble() # # Finito. #
Spuštění tohoto demonstračního příkladu již proběhne bez problémů, což je ostatně patrné i z následujícího výpisu:
None None 42 xyzzy [1, 2, 3] (1, 2, 3) 3 Hello world [1, 2, 3, 4, 5, 6] (1, 2, 3, 4, 5, 6) ['jedna', 'dve', 'Freddy', 'jde']
5. Překlad demonstračního příkladu Test29.py do bajtkódu Python VM
Opět se podívejme na způsob překladu tohoto demonstračního příkladu do bajtkódu Python VM:
function1(): 13 0 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 3 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
function2(): 21 0 LOAD_FAST 0 (x) // uložit první (a jediný) parametr funkce na TOS 3 RETURN_VALUE // vrátit tuto hodnotu
function3(): 29 0 LOAD_FAST 0 (x) // uložit první parametr funkce na TOS 3 LOAD_FAST 1 (y) // uložit druhý parametr funkce na TOS 6 BINARY_ADD // aplikovat operátor + na oba operandy (parametry) 7 RETURN_VALUE // vrátit výsledek operace +
Způsob volání těchto funkcí:
callFunction1(): 37 0 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 3 CALL_FUNCTION 0 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 6 STORE_FAST 0 (result) // uložit výsledek volání funkce do lokální proměnné 38 9 LOAD_FAST 0 (result) // načíst výsledek předchozího volání funkce 12 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 13 PRINT_NEWLINE // odřádkování 14 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 17 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
callFunction2(): 46 0 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 3 LOAD_CONST 0 (None) // skutečný parametr funkce uložit na TOS 6 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 9 STORE_FAST 0 (result1) // uložit výsledek volání funkce do lokální proměnné 47 12 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 15 LOAD_CONST 1 (42) // skutečný parametr funkce uložit na TOS 18 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 21 STORE_FAST 1 (result2) // uložit výsledek volání funkce do lokální proměnné 48 24 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 27 LOAD_CONST 2 ('xyzzy') // skutečný parametr funkce uložit na TOS 30 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 33 STORE_FAST 2 (result3) // uložit výsledek volání funkce do lokální proměnné 49 36 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 39 LOAD_CONST 3 (1) 42 LOAD_CONST 4 (2) 45 LOAD_CONST 5 (3) 48 BUILD_LIST 3 // vytvoření seznamu ze tří prvků 51 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 54 STORE_FAST 3 (result4) // uložit výsledek volání funkce do lokální proměnné 50 57 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 60 LOAD_CONST 6 ((1, 2, 3)) // skutečný parametr funkce uložit na TOS 63 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 66 STORE_FAST 4 (result5) // uložit výsledek volání funkce do lokální proměnné 51 69 LOAD_FAST 0 (result1) // načíst výsledek předchozího volání funkce 72 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 73 PRINT_NEWLINE // odřádkování 52 74 LOAD_FAST 1 (result2) // načíst výsledek předchozího volání funkce 77 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 78 PRINT_NEWLINE // odřádkování 53 79 LOAD_FAST 2 (result3) // načíst výsledek předchozího volání funkce 82 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 83 PRINT_NEWLINE // odřádkování 54 84 LOAD_FAST 3 (result4) // načíst výsledek předchozího volání funkce 87 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 88 PRINT_NEWLINE // odřádkování 55 89 LOAD_FAST 4 (result5) // načíst výsledek předchozího volání funkce 92 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 93 PRINT_NEWLINE // odřádkování 94 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 97 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
(povšimněte si, jak elegantně jsou n-tice reprezentovány konstantami, zatímco seznamy se musí dynamicky tvořit)
callFunction3(): 63 0 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 3 LOAD_CONST 1 (1) // skutečný parametr funkce uložit na TOS 6 LOAD_CONST 2 (2) // skutečný parametr funkce uložit na TOS 9 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 12 STORE_FAST 0 (result1) // uložit výsledek volání funkce do lokální proměnné 64 15 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 18 LOAD_CONST 3 ('Hello ') // skutečný parametr funkce uložit na TOS 21 LOAD_CONST 4 ('world') // skutečný parametr funkce uložit na TOS 24 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 27 STORE_FAST 1 (result2) // uložit výsledek volání funkce do lokální proměnné 65 30 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 33 LOAD_CONST 1 (1) 36 LOAD_CONST 2 (2) 39 LOAD_CONST 5 (3) 42 BUILD_LIST 3 // vytvoření seznamu ze tří prvků 45 LOAD_CONST 6 (4) 48 LOAD_CONST 7 (5) 51 LOAD_CONST 8 (6) 54 BUILD_LIST 3 // vytvoření seznamu ze tří prvků 57 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 60 STORE_FAST 2 (result3) // uložit výsledek volání funkce do lokální proměnné 66 63 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 66 LOAD_CONST 13 ((1, 2, 3)) // skutečný parametr funkce uložit na TOS 69 LOAD_CONST 14 ((4, 5, 6)) // skutečný parametr funkce uložit na TOS 72 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 75 STORE_FAST 3 (result4) // uložit výsledek volání funkce do lokální proměnné 67 78 LOAD_GLOBAL 0 (function3) // načíst referenci volané funkce 81 LOAD_CONST 9 ('jedna') 84 LOAD_CONST 10 ('dve') 87 BUILD_LIST 2 // vytvoření seznamu ze dvou prvků 90 LOAD_CONST 11 ('Freddy') 93 LOAD_CONST 12 ('jde') 96 BUILD_LIST 2 // vytvoření seznamu ze dvou prvků 99 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 102 STORE_FAST 4 (result5) // uložit výsledek volání funkce do lokální proměnné 69 105 LOAD_FAST 0 (result1) // načíst výsledek předchozího volání funkce 108 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 109 PRINT_NEWLINE // odřádkování 70 110 LOAD_FAST 1 (result2) // načíst výsledek předchozího volání funkce 113 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 114 PRINT_NEWLINE // odřádkování 71 115 LOAD_FAST 2 (result3) // načíst výsledek předchozího volání funkce 118 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 119 PRINT_NEWLINE // odřádkování 72 120 LOAD_FAST 3 (result4) // načíst výsledek předchozího volání funkce 123 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 124 PRINT_NEWLINE // odřádkování 73 125 LOAD_FAST 4 (result5) // načíst výsledek předchozího volání funkce 128 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 129 PRINT_NEWLINE // odřádkování 130 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 133 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
6. Demonstrační příklad Test30.py: funkce s pojmenovanými parametry
Dnešní třetí demonstrační příklad, jenž nese jméno Test30.py, bude využit pro zjištění, jakým způsobem se bude do bajtkódu Python VM překládat volání funkcí s využitím pojmenovaných parametrů. Volané funkce jsou v tomto příkladu dvě – funkce function1() očekávající jeden parametr a funkce function2() očekávající parametry dva. Volání těchto funkcí různými způsoby je realizováno v callFunction1() a callFunction2:
# # Demonstracni priklad cislo 30. # # Volani funkci s pojmenovanymi parametry v Pythonu. # # # Funkce s jednim parametrem. # def function1(x): return x # # Funkce se dvema parametry. # def function2(x, y): return x+y # # Volani funkce function1(). # def callFunction1(): result1 = function1(42) result2 = function1(x=42) print(result1) print(result2) # # Volani funkce function2(). # def callFunction2(): result1 = function2("Hello ", "world") result2 = function2(x = "Hello ", y = "world") result3 = function2(y = "Hello ", x = "world") print(result1) print(result2) print(result3) # # Spusteni testu. # def main(): callFunction1() callFunction2() # # Ukazka disasembleru. # (prekladu funkci do bajtkodu Python VM). # def disassemble(): from dis import dis print("\nfunction1():") dis(function1) print("\nfunction2():") dis(function2) print("\ncallFunction1():") dis(callFunction1) print("\ncallFunction2():") dis(callFunction2) main() #disassemble() # # Finito. #
Po spuštění tohoto příkladu se na standardním výstupu objeví následujících pět řádků textu:
42 42 Hello world Hello world worldHello
7. Překlad demonstračního příkladu Test30.py do bajtkódu Python VM
Opět se podívejme na způsob překladu tohoto demonstračního příkladu. Zajímat nás bude především technika deklarace testovacích funkcí i způsob jejich volání:
function1(): 13 0 LOAD_FAST 0 (x) // načíst první parametr 3 RETURN_VALUE // a vrátit ho
function2(): 21 0 LOAD_FAST 0 (x) // načíst první parametr 3 LOAD_FAST 1 (y) // načíst druhý parametr 6 BINARY_ADD // sečíst hodnoty obou parametrů 7 RETURN_VALUE // vrátit výsledek součtu
Ve způsobu deklarací obou funkcí k žádným změnám nedošlo (což je pochopitelní).
callFunction1(): 29 0 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 3 LOAD_CONST 1 (42) // parametr funkce uložit na TOS zásobníku operandů 6 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 9 STORE_FAST 0 (result1) // uložit výsledek volání funkce do lokální proměnné 30 12 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 15 LOAD_CONST 2 ('x') // uložit identifikátor parametru na TOS zásobníku operandů 18 LOAD_CONST 1 (42) // parametr funkce uložit na TOS zásobníku operandů 21 CALL_FUNCTION 256 // volat funkci, nulový počet pozičních parametrů, jeden pojmenovaný parametr 24 STORE_FAST 1 (result2) // uložit výsledek volání funkce do lokální proměnné 31 27 LOAD_FAST 0 (result1) // načíst výsledek předchozího volání funkce 30 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 31 PRINT_NEWLINE // odřádkování 32 32 LOAD_FAST 1 (result2) // načíst výsledek předchozího volání funkce 35 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 36 PRINT_NEWLINE // odřádkování 37 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 40 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
Zde již můžeme vidět jednu velkou změnu – za instrukcí CALL_FUNCTION je uložena hodnota 256. Ve skutečnosti se jedná o dvě hodnoty, každá o šířce osmi bitů, které byly spojeny do jednoho šestnáctibitového slova. Hodnota spodního bajtu udává počet pozičních parametrů (zde 0), hodnota horního bajtu počet pojmenovaných parametrů (zde 1 – každý pojmenovaný parametr se skládá ze svého jména a skutečné hodnoty).
callFunction2(): 40 0 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 3 LOAD_CONST 1 ('Hello ') // první parametr funkce uložit na TOS zásobníku operandů 6 LOAD_CONST 2 ('world') // druhý parametr funkce uložit na TOS zásobníku operandů 9 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 12 STORE_FAST 0 (result1) // uložit výsledek volání funkce do lokální proměnné 41 15 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 18 LOAD_CONST 3 ('x') // uložit identifikátor parametru na TOS zásobníku operandů 21 LOAD_CONST 1 ('Hello ') // parametr funkce uložit na TOS zásobníku operandů 24 LOAD_CONST 4 ('y') // uložit identifikátor parametru na TOS zásobníku operandů 27 LOAD_CONST 2 ('world') // parametr funkce uložit na TOS zásobníku operandů 30 CALL_FUNCTION 512 // volat funkci se dvěma pojmenovanými parametry (512=256*2) 33 STORE_FAST 1 (result2) // uložit výsledek volání funkce do lokální proměnné 42 36 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 39 LOAD_CONST 4 ('y') // uložit identifikátor parametru na TOS zásobníku operandů 42 LOAD_CONST 1 ('Hello ') // parametr funkce uložit na TOS zásobníku operandů 45 LOAD_CONST 3 ('x') // uložit identifikátor parametru na TOS zásobníku operandů 48 LOAD_CONST 2 ('world') // parametr funkce uložit na TOS zásobníku operandů 51 CALL_FUNCTION 512 // volat funkci se dvěma pojmenovanými parametry (512=256*2) 54 STORE_FAST 2 (result3) // uložit výsledek volání funkce do lokální proměnné 44 57 LOAD_FAST 0 (result1) // načíst výsledek předchozího volání funkce 60 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 61 PRINT_NEWLINE // odřádkování 45 62 LOAD_FAST 1 (result2) // načíst výsledek předchozího volání funkce 65 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 66 PRINT_NEWLINE // odřádkování 46 67 LOAD_FAST 2 (result3) // načíst výsledek předchozího volání funkce 70 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 71 PRINT_NEWLINE // odřádkování 72 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 75 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
8. Demonstrační příklad Test31.py: parametry s implicitní hodnotou
Dnešní čtvrtý a současně i poslední demonstrační příklad pojmenovaný Test31.py používá v testovacích funkcích function1() a function2() parametry s implicitní hodnotou, tj. pokud se tyto parametry při volání funkce explicitně nezadají, je namísto nich použita hodnota získaná z hlavičky funkce. Podívejme se na zdrojový kód tohoto demonstračního příkladu:
# # Demonstracni priklad cislo 31. # # Volani funkci s parametry s implicitni hodnotou v Pythonu. # # # Funkce s jednim parametrem. # def function1(x = 1): return x # # Funkce se dvema parametry. # def function2(x = 1, y = 2): return x+y # # Volani funkce function1(). # def callFunction1(): result1 = function1() result2 = function1(42) result3 = function1(x=42) print(result1) print(result2) print(result3) # # Volani funkce function2(). # def callFunction2(): result1 = function2() result2 = function2(0) result2 = function2(0,1) result3 = function2("Hello ", "world") result4 = function2(x = "Hello ", y = "world") result5 = function2(y = "Hello ", x = "world") print(result1) print(result2) print(result3) print(result4) print(result5) # # Spusteni testu. # def main(): callFunction1() callFunction2() # # Ukazka disasembleru. # (prekladu funkci do bajtkodu Python VM). # def disassemble(): from dis import dis print("\nfunction1():") dis(function1) print("\nfunction2():") dis(function2) print("\ncallFunction1():") dis(callFunction1) print("\ncallFunction2():") dis(callFunction2) main() #disassemble() # # Finito. #
Po spuštění tohoto demonstračního příkladu by se měly na standardním výstupu objevit následující zprávy:
1 42 42 3 1 Hello world Hello world worldHello
9. Překlad demonstračního příkladu Test31.py do bajtkódu Python VM
Deklarace obou testovacích funkcí je kupodivu stále stejná, implicitní hodnota parametrů je totiž specifikována při vytváření funkcí instrukcí MAKE_FUNCTION:
function1(): 13 0 LOAD_FAST 0 (x) // načíst první parametr 3 RETURN_VALUE // a vrátit ho
function2(): 21 0 LOAD_FAST 0 (x) // načíst první parametr 3 LOAD_FAST 1 (y) // načíst druhý parametr 6 BINARY_ADD // sečíst hodnoty obou parametrů 7 RETURN_VALUE // vrátit výsledek součtu
Volání se však již odlišuje:
callFunction1(): 29 0 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 3 CALL_FUNCTION 0 // volání funkce s nulovým počtem explicitně zadaných parametrů 6 STORE_FAST 0 (result1) // uložit výsledek volání funkce do lokální proměnné 30 9 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 12 LOAD_CONST 1 (42) // parametr funkce uložit na TOS zásobníku operandů 15 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 18 STORE_FAST 1 (result2) // uložit výsledek volání funkce do lokální proměnné 31 21 LOAD_GLOBAL 0 (function1) // načíst referenci volané funkce 24 LOAD_CONST 2 ('x') // uložit identifikátor parametru na TOS zásobníku operandů 27 LOAD_CONST 1 (42) // parametr funkce uložit na TOS zásobníku operandů 30 CALL_FUNCTION 256 // volat funkci, nulový počet pozičních parametrů, jeden pojmenovaný parametr 33 STORE_FAST 2 (result3) // uložit výsledek volání funkce do lokální proměnné 32 36 LOAD_FAST 0 (result1) // načíst výsledek předchozího volání funkce 39 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 40 PRINT_NEWLINE // odřádkování 33 41 LOAD_FAST 1 (result2) // načíst výsledek předchozího volání funkce 44 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 45 PRINT_NEWLINE // odřádkování 34 46 LOAD_FAST 2 (result3) // načíst výsledek předchozího volání funkce 49 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 50 PRINT_NEWLINE // odřádkování 51 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 54 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
Ještě zajímavější jsou možnosti volání funkce function2():
callFunction2(): 42 0 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 3 CALL_FUNCTION 0 // volání funkce s nulovým počtem explicitně zadaných parametrů 6 STORE_FAST 0 (result1) // uložit výsledek volání funkce do lokální proměnné 43 9 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 12 LOAD_CONST 1 (0) // parametr funkce uložit na TOS zásobníku operandů 15 CALL_FUNCTION 1 // volat funkci (konstanta udává počet skutečně předávaných parametrů) // druhý parametr má implicitní hodnotu 18 STORE_FAST 1 (result2) // uložit výsledek volání funkce do lokální proměnné 44 21 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 24 LOAD_CONST 1 (0) // první parametr funkce uložit na TOS zásobníku operandů 27 LOAD_CONST 2 (1) // druhý parametr funkce uložit na TOS zásobníku operandů 30 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 33 STORE_FAST 1 (result2) // uložit výsledek volání funkce do lokální proměnné 45 36 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 39 LOAD_CONST 3 ('Hello ') // první parametr funkce uložit na TOS zásobníku operandů 42 LOAD_CONST 4 ('world') // druhý parametr funkce uložit na TOS zásobníku operandů 45 CALL_FUNCTION 2 // volat funkci (konstanta udává počet skutečně předávaných parametrů) 48 STORE_FAST 2 (result3) // uložit výsledek volání funkce do lokální proměnné 46 51 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 54 LOAD_CONST 5 ('x') // uložit identifikátor parametru na TOS zásobníku operandů 57 LOAD_CONST 3 ('Hello ') // parametr funkce uložit na TOS zásobníku operandů 60 LOAD_CONST 6 ('y') // uložit identifikátor parametru na TOS zásobníku operandů 63 LOAD_CONST 4 ('world') // parametr funkce uložit na TOS zásobníku operandů 66 CALL_FUNCTION 512 // volat funkci se dvěma pojmenovanými parametry (512=256*2) 69 STORE_FAST 3 (result4) // uložit výsledek volání funkce do lokální proměnné 47 72 LOAD_GLOBAL 0 (function2) // načíst referenci volané funkce 75 LOAD_CONST 6 ('y') // uložit identifikátor parametru na TOS zásobníku operandů 78 LOAD_CONST 3 ('Hello ') // parametr funkce uložit na TOS zásobníku operandů 81 LOAD_CONST 5 ('x') // uložit identifikátor parametru na TOS zásobníku operandů 84 LOAD_CONST 4 ('world') // parametr funkce uložit na TOS zásobníku operandů 87 CALL_FUNCTION 512 // volat funkci se dvěma pojmenovanými parametry (512=256*2) 90 STORE_FAST 4 (result5) // uložit výsledek volání funkce do lokální proměnné 49 93 LOAD_FAST 0 (result1) // načíst výsledek předchozího volání funkce 96 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 97 PRINT_NEWLINE // odřádkování 50 98 LOAD_FAST 1 (result2) // načíst výsledek předchozího volání funkce 101 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 102 PRINT_NEWLINE // odřádkování 51 103 LOAD_FAST 2 (result3) // načíst výsledek předchozího volání funkce 106 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 107 PRINT_NEWLINE // odřádkování 52 108 LOAD_FAST 3 (result4) // načíst výsledek předchozího volání funkce 111 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 112 PRINT_NEWLINE // odřádkování 53 113 LOAD_FAST 4 (result5) // načíst výsledek předchozího volání funkce 116 PRINT_ITEM // tisk výsledku (návratové hodnoty volané funkce) 117 PRINT_NEWLINE // odřádkování 118 LOAD_CONST 0 (None) // uložit konstantu None na zásobník operandů 121 RETURN_VALUE // vrátit tuto konstantu (uloženou na TOS)
10. Uzávěry a generátory v Pythonu
V předchozích čtyřech demonstračních příkladech jsme si ukázali pouze základní způsoby volání funkcí. Možnosti Pythonu jsou v tomto směru totiž mnohem větší než v Javě a dokonce větší než v jazyku Lua, protože kromě parametrů s implicitní hodnotou a pojmenovaných parametrů lze při deklaraci a/nebo volání funkcí použít i další možnosti, například proměnný počet parametrů, tzv. keyword parametry či jejich kombinaci. Navíc i Python podporuje uzávěry (closures), i když ne v takové míře, jako je tomu v Lue, Perlu či JavaScriptu. Aby toho nebylo málo, podporuje programovací jazyk Python i bajtkód jeho virtuálního stroje takzvané generátory. Všechny instrukce bajtkódu Python VM související s voláním funkcí jsou vypsány v další tabulce, přičemž podrobnosti k MAKE_CLOSURE, YIELD_VALUE atd. si řekneme v následující části tohoto seriálu:
# | Instrukce | Stručný popis |
---|---|---|
1 | MAKE_FUNCTION | vytvoření funkce |
2 | MAKE_CLOSURE | vytvoření uzávěru |
3 | CALL_FUNCTION | volání funkce s pozičními a/nebo pojmenovanými parametry |
4 | CALL_FUNCTION_VAR | volání funkce s proměnným počtem parametrů |
5 | CALL_FUNCTION_KW | volání funkce s keyword parametry |
6 | CALL_FUNCTION_VAR_KW | kombinace předchozích dvou možností |
7 | YIELD_VALUE | vrácení (další) hodnoty z generátoru |
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 použité demonstrační příklady 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 čtyř příkladů naleznete v tabulce pod tímto odstavcem:
12. Odkazy na Internetu
- Python Byte Code Instructions
https://docs.python.org/release/2.5.2/lib/bytecodes.html - Python 2.x: funkce range()
https://docs.python.org/2/library/functions.html#range - Python 2.x: typ iterátor
https://docs.python.org/2/library/stdtypes.html#iterator-types - Python break, continue and pass Statements
http://www.tutorialspoint.com/python/python_loop_control.htm - 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 - 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/ - Programming in Lua (first edition)
http://www.lua.org/pil/contents.html - Programming in Lua: 6 – More about Functions
http://www.lua.org/pil/6.html - Programming in Lua: 6.1 – Closures
http://www.lua.org/pil/6.1.html - Programming in Lua: 9.1 – Coroutine Basics
http://www.lua.org/pil/9.1.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 - 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 - For-each Loop in Java
http://www.leepoint.net/notes-java/flow/loops/foreach.html - 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 - O-code
http://en.wikipedia.org/wiki/O-code_machine - 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 - 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