Obsah
1. Pohled pod kapotu JVM – zpracování výjimek v JVM, Python VM a Lua VM (2)
2. Zpracování výjimek v jazyku Lua
3. Demonstrační příklad Test33.lua: vyhození výjimky v jazyku Lua
4. Překlad demonstračního příkladu Test33.lua do bajtkódu Lua VM
5. Demonstrační příklad Test34.lua: vyhození a následné zachycení výjimky v jazyku Lua
6. Překlad demonstračního příkladu Test34.lua do bajtkódu Lua VM
7. Zpracování výjimek v jazyku Python
8. Demonstrační příklad Test37.py: vyhození výjimky v jazyku Python
9. Překlad demonstračního příkladu Test37.py do bajtkódu Python VM
10. Demonstrační příklad Test38.py: vyhození a následné zachycení výjimky v jazyku Python
11. Překlad demonstračního příkladu Test38.py do bajtkódu Python VM
12. Demonstrační příklad Test39.py: implementace struktury try-catch-finally v jazyku Python
13. Překlad demonstračního příkladu Test39.py do bajtkódu Python VM
14. Repositář se zdrojovými kódy všech pěti dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – zpracování výjimek v JVM, Python VM a Lua VM (2)
V předchozí části seriálu o JVM i o dalších virtuálních strojích jsme si na několika demonstračních příkladech ukázali, jakým způsobem se pracuje s výjimkami v bajtkódu virtuálního stroje Javy (JVM). Připomeňme si, že v JVM slouží pro vytvoření výjimky (přesněji řečeno objektu představujícího výjimku) instrukce new, která výjimku vytvoří a taktéž uloží referenci na tuto výjimku na zásobník operandů (TOS – Top of Stack). Samotné vyhození výjimky je provedeno instrukcí athrow. Tato instrukce očekává, že na vrcholu zásobníku operandů bude uložena reference na výjimku. Metoda, ze které může být vyhozena výjimka, musí ve svých metadatech obsahovat informaci o typu vyhazované výjimky či o typech výjimek (pokud jich je větší počet). Toto pravidlo kontrolované jak překladačem, tak i classloaderem nemusí být dodrženo pro běhové výjimky, tj. pro všechny třídy přímo či nepřímo odvozené od třídy RuntimeException.
Zachycení výjimek je ovšem poněkud složitější. Je řešeno přímo v bajtkódu (explicitní přeskakování kódu náležejícímu bloku catch, dvojitá implementace bloku finally atd.) a taktéž tabulkou přiřazenou k metodě, v níž se má výjimka zachytit. V této tabulce jsou uloženy rozsahy indexů instrukcí, v nichž může k výjimce dojít, index instrukce, na níž se provede skok při vzniku výjimky a taktéž typ výjimky (což je odkaz do constant poolu). Podívejme se na jednoduchý příklad takové tabulky. Poznámky byly samozřejmě dopsány ručně:
Exception table: // tabulka obsahující seznam řádků a případných výjimek from to target type 0 11 22 Class java/lang/Exception // blok try 0 11 42 any // bloky try+finally #1 22 31 42 any // blok catch 42 43 42 any // instrukce zachycení jiné výjimky
2. Zpracování výjimek v jazyku Lua
Minule jsme se taktéž alespoň ve stručnosti zmínili o způsobu práce s výjimkami v programovacím jazyce Lua. Zde se – což je v moderních „mainstreamových“ programovacích jazycích dosti neobvyklé – pro zachycení výjimky nepoužívají programové bloky typu try-catch či try-catch-finally, ale dvojice funkcí nazvaných pcall() a error(). Funkce error() slouží k vyhození výjimky, což znamená, že má podobný význam jako příkaz throw v programovacím jazyku Java či podobný příkaz raise, který najdeme v programovacím jazyku Python. Funkce error() může být ve zdrojovém kódu použita kdekoli; není tedy zapotřebí žádné zvláštní deklarace, která by označovala ty části kódu, kde je tato funkce použita.
Naproti tomu funkce pcall() slouží k zavolání jiné (libovolné) funkce v takzvaném „sandboxu“ (pcall = protected call). Pokud nevznikne ve volané funkci žádná výjimka, vrací pcall() ve svém prvním výsledku hodnotu true, v opačném případě (vznik výjimky) je vrácena hodnota false. Ve skutečnosti však funkce pcall() může vracet větší množství hodnot, přičemž další hodnoty (kromě hodnoty první) jsou výsledkem funkce předané do pcall(). Při vzniku výjimky je vrácena jen dvojice false,výjimka (samotná výjimka je typicky představována řetězcem, není to však nikde předepsáno).
Ukažme si celou strukturu vyvolávání a zachycování výjimek na velmi jednoduchém příkladu:
function noException1() return 1 end function noException2() return 1,2 end function noException3() return 1,2,3 end function throwException1() error(1) end function throwException2() error("Exception!!!") end function main() print("Status", "Return value(s)") print(pcall(noException1)) print(pcall(noException2)) print(pcall(noException3)) print(pcall(throwException1)) print(pcall(throwException2)) end main()
Výsledek vypsaný na standardní výstup:
Status Return value(s) true 1 true 1 2 true 1 2 3 false Test.lua:14: 1 false Test.lua:18: Exception!!!
3. Demonstrační příklad Test33.lua: vyhození výjimky v jazyku Lua
Nyní se již můžeme podívat na způsob překladu dvojice funkcí pcall() a error() do bajtkódu programovacího jazyka Lua. Nejprve si ukážeme velmi jednoduchý demonstrační příklad, v němž je funkce error() volána s libovolným parametrem – hodnota tohoto parametru bude představovat výjimku. Jak jsme si již řekli v předchozí kapitole, může výjimku představovat jakákoli hodnota, typicky řetězec, ale může se jednat i o tabulku, celé či desetinné číslo atd.:
-- -- Demonstracni priklad cislo 33. -- -- Vyhozeni vyjimky s vyuzitim funkce error(). -- -- -- Funkce, ktera vyhodi vyjimku. -- function throwNewException(message) error(message) end -- -- Spusteni testu. -- function main() print("Calling function 'throwNewException()'") throwNewException("Hello world!") print("Returned from function 'throwNewException()'") end main() -- -- Finito. --
Výjimka, která je vyhozena funkcí error(), není nikde zachycena, takže nás pravděpodobně nepřekvapí, že demonstrační příklad Test33.lua vypíše na terminál následující zprávy:
lua: Test33.lua:13: Hello world! stack traceback: [C]: in function 'error' Test33.lua:13: in function 'throwNewException' Test33.lua:23: in function 'main' Test33.lua:29: in main chunk [C]: ? Calling function 'throwNewException()'
Jedná se o klasický výpis stack trace, v němž jsou navíc naznačeny nativní funkce pomocí řetězce [C].
4. Překlad demonstračního příkladu Test33.lua do bajtkódu Lua VM
Při pohledu na bajtkód demonstračního příkladu Test33.lua je patrné, že se v něm ve skutečnosti nenachází žádné speciální instrukce ani metadata, která by souvisela s vyhozením výjimky! Můžeme zde vidět pouze volání funkce error(). To, že se jedná o nativní funkci (naprogramovanou v céčku), z bajtkódu nevyčteme; to je již implementační záležitost virtuálního stroje:
throwNewException(): function <Test33.lua:12,14> (4 instructions, 16 bytes at 0x460f60) 1 param, 3 slots, 0 upvalues, 1 local, 1 constant, 0 functions 1 [13] GETGLOBAL 1 -1 ; získání reference na funkci error() 2 [13] MOVE 2 0 ; parametr předaný funkci error 3 [13] CALL 1 2 1 ; zavolání funkce error (registr R1) s předáním parametru v registru R2 4 [14] RETURN 0 1 ; návrat z funkce throwNewException
Ani volání funkce nazvané throwNewException není v žádném ohledu odlišné od volání jiných funkcí:
main(): function <Test33.lua:21,25> (10 instructions, 40 bytes at 0x461240) 0 params, 2 slots, 0 upvalues, 0 locals, 5 constants, 0 functions 1 [22] GETGLOBAL 0 -1 ; získání reference na funkci print 2 [22] LOADK 1 -2 ; řetězec "Calling function 'throwNewException'" 3 [22] CALL 0 2 1 ; zavolání funkce print() s předáním parametru v registru R1 4 [23] GETGLOBAL 0 -3 ; získání reference na funkci throwNewException 5 [23] LOADK 1 -4 ; řetězec "Hello world!" 6 [23] CALL 0 2 1 ; zavolat funkci throwNewException 7 [24] GETGLOBAL 0 -1 ; získání reference na funkci print 8 [24] LOADK 1 -5 ; řetězec "Returned from function 'throwNewException()'" 9 [24] CALL 0 2 1 ; zavolání funkce print s předáním parametru v registru R1 10 [25] RETURN 0 1 ; návrat z funkce main
5. Demonstrační příklad Test34.lua: vyhození a následné zachycení výjimky v jazyku Lua
Dnešní druhý demonstrační příklad nazvaný Test34.lua je již poněkud složitější než příklad předchozí, a to z toho důvodu, že se zde funkce throwNewException nevolá přímo. Namísto přímého volání se používá „sandbox“ vytvořený funkcí pcall (protected call). Povšimněte si způsobu použití této funkce – namísto throwNewException(„Hello world!“) se použije volání pcall(throwNewException, "Hello world!), tj. volaná funkce je zde předávána jako parametr – funkce jsou totiž v programovacím jazyku Lua plnohodnotnými datovými typy. Funkce pcall() vrací v prvním výsledku stav volání „sandboxované“ funkce:
-- -- Demonstracni priklad cislo 34. -- -- Vyhozeni vyjimky s vyuzitim funkce error() -- s naslednym zachycenim teze vyjimky funkci pcall(). -- -- -- Funkce, ktera vyhodi vyjimku. -- function throwNewException(message) error(message) end -- -- Spusteni testu. -- function main() print("Calling function 'throwNewException()'") local status, message = pcall(throwNewException, "Hello world!") print("Returned from function 'throwNewException()'") print(" Status = ", status) print(" Message = ", message) end main() -- -- Finito. --
Po spuštění tohoto demonstračního příkladu se na standardní výstup vypíšou tyto zprávy oznamující, že při spuštění funkce throwNewException skutečně došlo k vyhození výjimky:
Calling function 'throwNewException()' Returned from function 'throwNewException()' Status = false Message = Test34.lua:14: Hello world!
6. Překlad demonstračního příkladu Test34.lua do bajtkódu Lua VM
Bajtkód funkce throwNewException() se (podle očekávání) nijak neliší od bajtkódu stejnojmenné funkce, kterou jsme již implementovali v předchozím demonstračním příkladu, o čemž se můžeme snadno přesvědčit:
throwNewException(): function <Test34.lua:13,15> (4 instructions, 16 bytes at 0x175af60) 1 param, 3 slots, 0 upvalues, 1 local, 1 constant, 0 functions 1 [14] GETGLOBAL 1 -1 ; získání reference na funkci error() 2 [14] MOVE 2 0 ; parametr předaný funkci error 3 [14] CALL 1 2 1 ; zavolání funkce error (registr R1) s předáním parametru v registru R2 4 [15] RETURN 0 1 ; návrat z funkce throwNewException
Komplikovanější je však bajtkód funkce main, neboť zde je nutné implementovat volání pcall(throwNewException, message), tj. funkce throwNewException zde vystupuje jako parametr funkce pcall. Povšimněte si, jak vysokoúrovňový vlastně bajtkód Lua VM je, zejména v porovnání s JVM:
main(): function <Test34.lua:22,28> (19 instructions, 76 bytes at 0x175b240) 0 params, 5 slots, 0 upvalues, 2 locals, 8 constants, 0 functions 1 [23] GETGLOBAL 0 -1 ; získání reference na funkci print 2 [23] LOADK 1 -2 ; řetězec "Calling function 'throwNewException'" 3 [23] CALL 0 2 1 ; zavolání funkce print s předáním parametru v registru R1 4 [24] GETGLOBAL 0 -3 ; získání reference na funkci pcall 5 [24] GETGLOBAL 1 -4 ; získání reference na funkci throwNewException 6 [24] LOADK 2 -5 ; řetězec "Hello world!" 7 [24] CALL 0 3 3 ; zavolání funkce pcall s dvojicí parametrů (throwNewException, "Hello world!" 8 [25] GETGLOBAL 2 -1 ; získání reference na funkci print 9 [25] LOADK 3 -6 ; řetězec "Returned from function 'throwNewException()'" 10 [25] CALL 2 2 1 ; zavolání funkce print 11 [26] GETGLOBAL 2 -1 ; získání reference na funkci print 12 [26] LOADK 3 -7 ; řetězec " Status = " 13 [26] MOVE 4 0 ; první návratová hodnota funkce pcall 14 [26] CALL 2 3 1 ; zavolání funkce print se dvěma parametry (registry R3 a R4) 15 [27] GETGLOBAL 2 -1 ; získání reference na funkci print 16 [27] LOADK 3 -8 ; řetězec " Message = " 17 [27] MOVE 4 1 ; druhá návratová hodnota funkce pcall 18 [27] CALL 2 3 1 ; zavolání funkce print se dvěma parametry (registry R3 a R4) 19 [28] RETURN 0 1 ; návrat z funkce main
7. Zpracování výjimek v jazyku Python
Způsob práce s výjimkami v programovacím jazyce Python se ze syntaktického i sémantického hlediska do značné míry podobá způsobu zpracování výjimek v programovacím jazyce Java, samozřejmě s ohledem na to, že Python používá dynamické vyhodnocování datových typů a nevyžaduje striktně explicitní zachycení výjimek. Nepatrné rozdíly najdeme i v syntaxi zápisu, protože se namísto klíčového slova catch používá slovo except. Větší rozdíly však najdeme na úrovni bajtkódu, neboť v Pythonu se nepoužívají speciální tabulky s informacemi o tom, v jakém místě kódu mohou nastat výjimky (tyto tabulky najdeme jen v JVM). Namísto toho se používají takzvané bloky instrukcí, přičemž informace o těchto blocích jsou ukládány na zásobníkový rámec. Bloky se vytváří a ruší dynamicky za běhu aplikace, a to s využitím specializovaných instrukcí SETUP_EXCEPT, SETUP_FINALLY, POP_BLOCK a END_FINALLY.
8. Demonstrační příklad Test37.py: vyhození výjimky v jazyku Python
Dnešní první demonstrační příklad ukazující způsob zpracování výjimek v Pythonu nese název Test37.py. V tomto velmi jednoduchém příkladu se ve funkci throwNewException vyhodí nová výjimka typu Exception. Při konstrukci objektu představujícího výjimku se použije zpráva předaná do funkce throwNewException:
# # Demonstracni priklad cislo 37. # # Vyhozeni vyjimky. # # # Funkce, ktera vyhodi vyjimku. # def throwNewException(message): raise Exception(message) # # Spusteni testu. # def main(): print("Calling function 'throwNewException()'") throwNewException("Hello world!") print("Returned from function 'throwNewException()'") # # Ukazka disasembleru. # (prekladu funkci do bajtkodu Python VM). # def disassemble(): from dis import dis print("\nthrowNewException():") dis(throwNewException) print("\nmain():") dis(main) main() #disassemble() # # Finito. #
Po spuštění tohoto demonstračního příkladu vznikne (dle očekávání) výjimka, která není zachycena. Z tohoto důvodu dojde k ukončení běhu aplikace a k vypsání historie volání funkcí:
Calling function 'throwNewException()' Traceback (most recent call last): File "Test37.py", line 42, in main() File "Test37.py", line 22, in main throwNewException("Hello world!") File "Test37.py", line 13, in throwNewException raise Exception(message) Exception: Hello world!
9. Překlad demonstračního příkladu Test37.py do bajtkódu Python VM
Překlad funkce throwNewException do bajtkódu Python VM ukazuje, jakým způsobem je přeložen příkaz raise. Využívá se zde instrukce RAISE_VARARGS, které se předá aktuální počet parametrů od 0 do 3. V našem případě se předává jen jediný parametr – vlastní výjimka:
throwNewException(): 13 0 LOAD_GLOBAL 0 (Exception) ; příprava na vytvoření objektu představujícího výjimku ; získání reference třídy, jejíž instance se bude vytvářet 3 LOAD_FAST 0 (message) ; příprava na vytvoření objektu představujícího výjimku ; načtení parametru funkce 6 CALL_FUNCTION 1 ; volání Exception(message) - vytvoření výjimky 9 RAISE_VARARGS 1 ; vlastní vyhození výjimky 12 LOAD_CONST 0 (None) ; návratová hodnota funkce throwNewException 15 RETURN_VALUE ; výskok z funkce throwNewException
Vzhledem k tomu, že se výjimka z funkce throwNewException nikde nezachycuje, je bajtkód funkce main velmi jednoduchý a vcelku přímočaře odpovídá zdrojovému kódu:
main(): 21 0 LOAD_CONST 1 ; řetězec "Calling function 'throwNewException()'") 3 PRINT_ITEM ; tisk řetězce na standardní výstup 4 PRINT_NEWLINE ; odřádkování 22 5 LOAD_GLOBAL 0 (throwNewException) ; získání reference funkce, která se bude volat 8 LOAD_CONST 2 ; řetězec 'Hello world!' 11 CALL_FUNCTION 1 ; zavolání funkce throwNewException 14 POP_TOP ; úklid návratové hodnoty (nevyužijeme ji) 23 15 LOAD_CONST 3 ; řetězec "Returned from function 'throwNewException()'" 18 PRINT_ITEM ; tisk řetězce na standardní výstup 19 PRINT_NEWLINE ; odřádkování 20 LOAD_CONST 0 (None) ; návratová hodnota funkce main 23 RETURN_VALUE ; výskok z funkce main
10. Demonstrační příklad Test38.py: vyhození a následné zachycení výjimky v jazyku Python
Ve druhém demonstračním příkladu naprogramovaném v Pythonu se již výjimka vyhazovaná z funkce throwNewException zachycuje, a to konkrétně v bloku catch. Zdrojový kód tohoto demonstračního příkladu je opět velmi jednoduchý:
# # Demonstracni priklad cislo 38. # # Vyhozeni vyjimky s jejim naslednym zachycenim. # # # Funkce, ktera vyhodi vyjimku. # def throwNewException(message): raise Exception(message) # # Spusteni testu. # def main(): try: print("Calling function 'throwNewException()'") throwNewException("Hello world!") print("Returned from function 'throwNewException()'") except: print("Catch/except block") # # Ukazka disasembleru. # (prekladu funkci do bajtkodu Python VM). # def disassemble(): from dis import dis print("\nthrowNewException():") dis(throwNewException) print("\nmain():") dis(main) main() #disassemble() # # Finito. #
Po spuštění se na standardní výstup vypíšou pouze dva řádky textu, což znamená, že příkaz print(„Returned from function ‚throwNewException()‘“) byl přeskočen:
Calling function 'throwNewException()' Catch/except block
11. Překlad demonstračního příkladu Test38.py do bajtkódu Python VM
Opět se podívejme na bajtkód demonstračního příkladu Test38.py.
Překlad funkce throwNewException do bajtkódu Python VM je zcela stejný, jako tomu bylo v předchozím demonstračním příkladu:
throwNewException(): 13 0 LOAD_GLOBAL 0 (Exception) ; příprava na vytvoření objektu představujícího výjimku ; získání reference třídy, jejíž instance se bude vytvářet 3 LOAD_FAST 0 (message) ; příprava na vytvoření objektu představujícího výjimku ; načtení parametru funkce 6 CALL_FUNCTION 1 ; volání Exception(message) - vytvoření výjimky 9 RAISE_VARARGS 1 ; vlastní vyhození výjimky 12 LOAD_CONST 0 (None) ; návratová hodnota funkce throwNewException 15 RETURN_VALUE ; výskok z funkce throwNewException
Komplikovanější je však bajtkód funkce main. Zde se můžeme setkat s několika novými instrukcemi, zejména s trojicí instrukcí SETUP_EXCEPT, POP_BLOCK a END_FINALLY. První z těchto instrukcí slouží k vytvoření bloku (uvnitř zásobníkového rámce), v němž může dojít k výjimce. Tento blok se odstraňuje instrukcí POP_BLOCK a poslední zmíněná instrukce END_FINALLY se používá v bloku finally (i když je prázdný). Za zmínku taktéž stojí okomentovaná trojice instrukcí POP_TOP:
main(): 21 0 SETUP_EXCEPT 24 (to 27) ; vytvoření bloku instrukcí, v nichž může dojít k výjimce ; 27 je index první instrukce v bloku except začátek bloku *try* 22 3 LOAD_CONST 1 ; řetězec "Calling function 'throwNewException()'") 6 PRINT_ITEM ; tisk řetězce na standardní výstup 7 PRINT_NEWLINE ; odřádkování 23 8 LOAD_GLOBAL 0 (throwNewException) ; získání reference funkce, která se bude volat 11 LOAD_CONST 2 ; řetězec 'Hello world!' 14 CALL_FUNCTION 1 ; zavolání funkce throwNewException 17 POP_TOP ; úklid návratové hodnoty (nevyužijeme ji) 24 18 LOAD_CONST 3 ; řetězec "Returned from function 'throwNewException()'" 21 PRINT_ITEM ; tisk řetězce na standardní výstup 22 PRINT_NEWLINE ; odřádkování 23 POP_BLOCK ; volání proběhlo v pořádku - zrušíme celý blok ; vytvořený přes SETUP_EXCEPT 24 JUMP_FORWARD 12 (to 39) ; skok na konec funkce (přeskok dalšího bloku) konec bloku *try* začátek bloku *except* 25 27 POP_TOP ; úklid na zásobníku operandů (vlastní výjimka) 28 POP_TOP ; úklid na zásobníku operandů (parametr výjimky) 29 POP_TOP ; úklid na zásobníku operandů (handler) 26 30 LOAD_CONST 4 ; řetězec "Catch/except block" 33 PRINT_ITEM ; tisk řetězce na standardní výstup 34 PRINT_NEWLINE ; odřádkování 35 JUMP_FORWARD 1 (to 39) ; skok na konec funkce (přeskok dalšího prázdného bloku) konec bloku *except* začátek bloku *finally* 38 END_FINALLY ; ukončení bloku finally konec bloku *finally* 39 LOAD_CONST 0 (None) ; návratová hodnota funkce main 42 RETURN_VALUE ; výskok z funkce main
12. Demonstrační příklad Test39.py: implementace struktury try-catch-finally v jazyku Python
V dnešním posledním demonstračním příkladu je již implementována úplná řídicí struktura try-catch-finally, resp. přesněji řečeno try-except-finally, pokud se budeme držet názvosloví používaného v programovacím jazyku Python:
# # Demonstracni priklad cislo 39. # # Implementace struktury try/catch/finally v Pythonu. # # # Funkce, ktera vyhodi vyjimku. # def throwNewException(message): raise Exception(message) # # Spusteni testu. # def main(): try: print("Calling function 'throwNewException()'") throwNewException("Hello world!") print("Returned from function 'throwNewException()'") except: print("Catch/except block") finally: print("Finally block") # # Ukazka disasembleru. # (prekladu funkci do bajtkodu Python VM). # def disassemble(): from dis import dis print("\nthrowNewException():") dis(throwNewException) print("\nmain():") dis(main) main() #disassemble() # # Finito. #
Po spuštění tohoto příkladu se na standardním výstupu objeví následující trojice řádků:
Calling function 'throwNewException()' Catch/except block Finally block
13. Překlad demonstračního příkladu Test39.py do bajtkódu Python VM
Překlad funkce throwNewException do bajtkódu Python VM je opět zcela stejný, jako tomu bylo v minulém i předminulém demonstračním příkladu:
throwNewException(): 13 0 LOAD_GLOBAL 0 (Exception) ; příprava na vytvoření objektu představujícího výjimku ; získání reference třídy, jejíž instance se bude vytvářet 3 LOAD_FAST 0 (message) ; příprava na vytvoření objektu představujícího výjimku ; načtení parametru funkce 6 CALL_FUNCTION 1 ; volání Exception(message) - vytvoření výjimky 9 RAISE_VARARGS 1 ; vlastní vyhození výjimky 12 LOAD_CONST 0 (None) ; návratová hodnota funkce throwNewException 15 RETURN_VALUE ; výskok z funkce throwNewException
Bajtkód funkce main se opět stal složitějším, a to zejména kvůli implementaci řídicí struktury finally. Taktéž zde najdeme novou instrukci SETUP_FINALLY, která dynamicky vytváří na zásobníkovém rámci blok instrukcí odpovídajících programovým řádkům od klíčového slova try až po finally:
main(): 21 0 SETUP_FINALLY 43 (to 46) ; vytvoření bloku instrukcí, v nichž jsou implementovány bloky try-finally 3 SETUP_EXCEPT 24 (to 30) ; vytvoření bloku instrukcí, v nichž může dojít k výjimce začátek bloku *try* 22 9 LOAD_CONST 1 ; řetězec "Calling function 'throwNewException()'") 9 PRINT_ITEM ; tisk řetězce na standardní výstup 10 PRINT_NEWLINE ; odřádkování 23 11 LOAD_GLOBAL 0 (throwNewException) ; získání reference funkce, která se bude volat 14 LOAD_CONST 2 ; řetězec 'Hello world!' 17 CALL_FUNCTION 1 ; zavolání funkce throwNewException 20 POP_TOP ; úklid návratové hodnoty (nevyužijeme ji) 24 21 LOAD_CONST 3 ; řetězec "Returned from function 'throwNewException()'" 24 PRINT_ITEM ; tisk řetězce na standardní výstup 25 PRINT_NEWLINE ; odřádkování 26 POP_BLOCK ; volání proběhlo v pořádku - zrušíme celý blok ; vytvořený přes SETUP_EXCEPT 27 JUMP_FORWARD 12 (to 42) ; skok na konec funkce (přeskok dalšího bloku) konec bloku *try* začátek bloku *except* 25 30 POP_TOP ; úklid na zásobníku operandů (vlastní výjimka) 31 POP_TOP ; úklid na zásobníku operandů (parametr výjimky) 32 POP_TOP ; úklid na zásobníku operandů (handler) 26 33 LOAD_CONST 4 ; řetězec "Catch/except block" 36 PRINT_ITEM ; tisk řetězce na standardní výstup 37 PRINT_NEWLINE ; odřádkování 38 JUMP_FORWARD 1 (to 42) ; skok na konec funkce (přeskok dalšího bloku) konec bloku *except* 41 END_FINALLY ; ukončení prvního bloku finally 42 POP_BLOCK ; náhrada návratové hodnoty funkce 43 LOAD_CONST 0 (None) ; náhrada návratové hodnoty funkce začátek bloku *finally* 28 46 LOAD_CONST 5 ; řetězec "('Finally block')" 49 PRINT_ITEM ; tisk řetězce na standardní výstup 50 PRINT_NEWLINE ; odřádkování 51 END_FINALLY ; ukončení bloku finally konec bloku *finally* 52 LOAD_CONST 0 (None) ; návratová hodnota funkce main 55 RETURN_VALUE ; výskok z funkce main
14. Repositář se zdrojovými kódy všech pěti dnešních demonstračních příkladů
Všech pět dnes popsaných a „disasemblovaných“ demonstračních příkladů bylo uloženo do Mercurial repositáře umístěného na adrese http://icedtea.classpath.org/people/ptisnovs/jvm-tools/ (revize s kódy 8dc74f8e40f1 a 50d36e484ab0). Odkazy na prozatím poslední verze těchto pěti příkladů naleznete v tabulce umístěné pod tímto odstavcem:
15. 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/ - Lambda the Ultimate: Coroutines in Lua,
http://lambda-the-ultimate.org/node/438 - Coroutines Tutorial,
http://lua-users.org/wiki/CoroutinesTutorial - Lua Coroutines Versus Python Generators,
http://lua-users.org/wiki/LuaCoroutinesVersusPythonGenerators - Programming in Lua 9.1 – Coroutine Basics,
http://www.lua.org/pil/9.1.html - Wikipedia CZ: Koprogram,
http://cs.wikipedia.org/wiki/Koprogram - Wikipedia EN: Coroutine,
http://en.wikipedia.org/wiki/Coroutine - 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 - Lua Lanes,
http://kotisivu.dnainternet.net/askok/bin/lanes/ - 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