Hlavní navigace

Pohled pod kapotu JVM – volání funkcí a použití generátorů i uzávěrů v Python VM

26. 8. 2014
Doba čtení: 28 minut

Sdílet

I v dnešní části seriálu o JVM (i o dalších typech virtuálních strojů) se budeme zabývat problematikou volání funkcí a metod. Již víme, jak je řešeno volání statických i nestatických metod a konstruktorů v JVM, známe i volání funkcí, metod a uzávěrů v Lua VM, takže zbývá vysvětlit řešení této problematiky v Python VM.

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ů

12. Odkazy na Internetu

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()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()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ý:

  1. Reference na volanou funkci je uložena na zásobník operandů
  2. Skutečné parametry jsou před voláním funkce předány (uloženy) na zásobník operandů
  3. Funkce je volána pomocí instrukce CALL_FUNCTION
  4. Návrat z funkce je řešen přes instrukci RETURN_VALUE
  5. 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()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()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()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()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():

CS24_early

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.or­g/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

  1. Python Byte Code Instructions
    https://docs.python.org/re­lease/2.5.2/lib/bytecodes­.html
  2. Python 2.x: funkce range()
    https://docs.python.org/2/li­brary/functions.html#range
  3. Python 2.x: typ iterátor
    https://docs.python.org/2/li­brary/stdtypes.html#itera­tor-types
  4. Python break, continue and pass Statements
    http://www.tutorialspoint­.com/python/python_loop_con­trol.htm
  5. Python Bytecode: Fun With Dis
    http://akaptur.github.io/blog/2013/08/14/pyt­hon-bytecode-fun-with-dis/
  6. Python's Innards: Hello, ceval.c!
    http://tech.blog.aknin.na­me/category/my-projects/pythons-innards/
  7. Byterun
    https://github.com/nedbat/byterun
  8. Python Byte Code Instructions
    http://document.ihg.uni-duisburg.de/Documentation/Pyt­hon/lib/node56.html
  9. Python Byte Code Instructions
    https://docs.python.org/3­.2/library/dis.html#python-bytecode-instructions
  10. dis – Python module
    https://docs.python.org/2/li­brary/dis.html
  11. Comparison of Python virtual machines
    http://polishlinux.org/ap­ps/cli/comparison-of-python-virtual-machines/
  12. Programming in Lua (first edition)
    http://www.lua.org/pil/contents.html
  13. Programming in Lua: 6 – More about Functions
    http://www.lua.org/pil/6.html
  14. Programming in Lua: 6.1 – Closures
    http://www.lua.org/pil/6.1.html
  15. Programming in Lua: 9.1 – Coroutine Basics
    http://www.lua.org/pil/9.1.html
  16. Programming in Lua: Numeric for
    http://www.lua.org/pil/4.3.4.html
  17. Programming in Lua: break and return
    http://www.lua.org/pil/4.4.html
  18. Programming in Lua: Tables
    http://www.lua.org/pil/2.5.html
  19. Programming in Lua: Table Constructors
    http://www.lua.org/pil/3.6.html
  20. Programovací jazyk Lua
    http://palmknihy.cz/web/kni­ha/programovaci-jazyk-lua-12651.htm
  21. Lua: Tables Tutorial
    http://lua-users.org/wiki/TablesTutorial
  22. Lua: Control Structure Tutorial
    http://lua-users.org/wiki/ControlStruc­tureTutorial
  23. Lua Types Tutorial
    http://lua-users.org/wiki/LuaTypesTutorial
  24. Goto Statement in Lua
    http://lua-users.org/wiki/GotoStatement
  25. Lua 5.2 sources
    http://www.lua.org/source/5.2/
  26. Lua 5.2 sources – lopcodes.h
    http://www.lua.org/source/5­.2/lopcodes.h.html
  27. Lua 5.2 sources – lopcodes.c
    http://www.lua.org/source/5­.2/lopcodes.c.html
  28. For-each Loop in Java
    http://www.leepoint.net/notes-java/flow/loops/foreach.html
  29. For Loop (Wikipedia)
    http://en.wikipedia.org/wiki/For_loop
  30. Heinz Rutishauser
    http://en.wikipedia.org/wi­ki/Heinz_Rutishauser
  31. Parrot
    http://www.parrot.org/
  32. Parrot languages
    http://www.parrot.org/languages
  33. Parrot Primer
    http://docs.parrot.org/pa­rrot/latest/html/docs/intro­.pod.html
  34. Parrot Opcodes
    http://docs.parrot.org/pa­rrot/latest/html/ops.html
  35. Parrot VM
    http://en.wikibooks.org/wi­ki/Parrot_Virtual_Machine
  36. Parrot Assembly Language
    http://www.perl6.org/archi­ve/pdd/pdd06_pasm.html
  37. Parrot Reference: Chapter 11 – Perl 6 and Parrot Essentials
    http://oreilly.com/perl/excerpts/perl-6-and-parrot-essentials/parrot-reference.html
  38. O-code
    http://en.wikipedia.org/wiki/O-code_machine
  39. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  40. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  41. GC safe-point (or safepoint) and safe-region
    http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html
  42. Safepoints in HotSpot JVM
    http://blog.ragozin.info/2012/10/sa­fepoints-in-hotspot-jvm.html
  43. Java theory and practice: Synchronization optimizations in Mustang
    http://www.ibm.com/develo­perworks/java/library/j-jtp10185/
  44. How to build hsdis
    http://hg.openjdk.java.net/jdk7/hot­spot/hotspot/file/tip/src/sha­re/tools/hsdis/README
  45. Java SE 6 Performance White Paper
    http://www.oracle.com/technet­work/java/6-performance-137236.html
  46. Lukas Stadler's Blog
    http://classparser.blogspot­.cz/2010/03/hsdis-i386dll.html
  47. How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
    http://dropzone.nfshost.com/hsdis.htm
  48. PrintAssembly
    https://wikis.oracle.com/dis­play/HotSpotInternals/Prin­tAssembly
  49. The Java Virtual Machine Specification: 3.14. Synchronization
    http://docs.oracle.com/ja­vase/specs/jvms/se7/html/jvms-3.html#jvms-3.14
  50. The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4
  51. The Java Virtual Machine Specification: 17.4. Memory Model
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.4
  52. The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.7
  53. Open Source ByteCode Libraries in Java
    http://java-source.net/open-source/bytecode-libraries
  54. ASM Home page
    http://asm.ow2.org/
  55. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2.org/users.html
  56. ObjectWeb ASM (Wikipedia)
    http://en.wikipedia.org/wi­ki/ObjectWeb_ASM
  57. Java Bytecode BCEL vs ASM
    http://james.onegoodcooki­e.com/2005/10/26/java-bytecode-bcel-vs-asm/
  58. BCEL Home page
    http://commons.apache.org/bcel/
  59. Byte Code Engineering Library (před verzí 5.0)
    http://bcel.sourceforge.net/
  60. Byte Code Engineering Library (verze >= 5.0)
    http://commons.apache.org/pro­per/commons-bcel/
  61. BCEL Manual
    http://commons.apache.org/bcel/ma­nual.html
  62. Byte Code Engineering Library (Wikipedia)
    http://en.wikipedia.org/wiki/BCEL
  63. BCEL Tutorial
    http://www.smfsupport.com/sup­port/java/bcel-tutorial!/
  64. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
  65. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2.org/eclipse/index.html
  66. Javassist
    http://www.jboss.org/javassist/
  67. Byteman
    http://www.jboss.org/byteman
  68. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ibm.com/develo­perworks/java/library/j-dyn0414/
  69. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  70. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  71. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  72. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  73. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  74. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  75. aspectj (Eclipse)
    http://www.eclipse.org/aspectj/
  76. Aspect-oriented programming (Wikipedia)
    http://en.wikipedia.org/wi­ki/Aspect_oriented_program­ming
  77. AspectJ (Wikipedia)
    http://en.wikipedia.org/wiki/AspectJ
  78. EMMA: a free Java code coverage tool
    http://emma.sourceforge.net/
  79. Cobertura
    http://cobertura.sourceforge.net/
  80. jclasslib bytecode viewer
    http://www.ej-technologies.com/products/jclas­slib/overview.html

Byl pro vás článek přínosný?

Autor článku

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