Obsah
1. LuaJIT – Just in Time překladač pro programovací jazyk Lua (3)
2. Demonstrační příklad číslo 13: relační operátory pro proměnné obsahujících numerické hodnoty
3. Demonstrační příklad číslo 14: relační operátory pro porovnání proměnné s číselnou konstantou
4. Demonstrační příklad číslo 15: porovnání hodnoty proměnné s booleovskou konstantou true či false
5. Demonstrační příklad číslo 16: porovnání hodnoty proměnné s konstantou nil
6. Demonstrační příklad číslo 17: porovnání hodnoty proměnné s řetězcem
8. Repositář se zdrojovými kódy všech šesti dnešních demonstračních příkladů
1. LuaJIT – Just in Time překladač pro programovací jazyk Lua (3)
Ve druhé části článku o Just in Time překladači nazvaném LuaJIT jsme si s využitím demonstračních příkladů ukázali, jak se používají základní instrukce IR implementované pro porovnání dvou hodnot. Připomeňme si, že se jedná o čtveřici instrukcí nazvaných ISLT, ISGE, ISLE a ISGT. Tyto instrukce porovnají hodnoty uložené ve dvou slotech (lokálních proměnných) a na základě výsledků porovnání se buď provede nebo naopak neprovede skok, jehož instrukce JMP musí být umístěna ihned za zmíněnými čtyřmi instrukcemi pro porovnání. Je zajímavé, že IR obsahuje instrukce pro všechny typy relací, tj. <, ≤, ≥, > (o relacích typu = a ≠ se budeme podrobněji bavit v navazujících kapitolách), i když by teoreticky bylo možné nahradit například instrukci ISLT instrukcí ISLE s prohozenými operandy. Ve skutečnosti je však nutné, aby se v IR korektně pracovalo i s hodnotou NaN (Not a Number), takže především pro práci s numerickými hodnotami se používají všechny instrukce implementující test na relace.
V následující tabulce jsou vypsány čtyři instrukce testující relace <, ≤, ≥ a > pro hodnoty uložené ve slotech (lokálních proměnných). Tyto instrukce jsou použity pro všechny typy hodnot, tj. jak pro numerické hodnoty, tak i pro řetězce atd.:
# | Instrukce | Operandy | Popis |
---|---|---|---|
1 | ISLT | slot, slot | následuje skok provedený při splnění podmínky A < D |
2 | ISGE | slot, slot | následuje skok provedený při splnění podmínky A ≥ D |
3 | ISLE | slot, slot | následuje skok provedený při splnění podmínky A ≤ D |
4 | ISGT | slot, slot | následuje skok provedený při splnění podmínky A > D |
2. Demonstrační příklad číslo 13: relační operátory pro proměnné obsahujících numerické hodnoty
V úvodní kapitole jsme se seznámili se čtyřmi základními instrukcemi použitými pro porovnání dvou hodnot uložených ve slotech. Pokud je nutné zjistit, zda jsou si dvě hodnoty rovny či naopak nerovny, je nutné v IR rozlišit, jakého typu porovnávané hodnoty jsou a zda jsou uloženy v proměnných či zda jsou naopak reprezentovány konstantou. Pokud se jedná o dvě proměnné, je situace velmi jednoduchá, protože lze pro porovnání obsahu těchto proměnných použít instrukce ISEQV a ISNEV vypsané ve druhé tabulce:
# | Instrukce | Operandy | Popis |
---|---|---|---|
1 | ISEQV | slot, slot | následuje skok provedený při splnění podmínky A = D |
2 | ISNEV | slot, slot | následuje skok provedený při splnění podmínky A ≠ D |
Použití instrukcí ISLT, ISLE, ISGT, ISGE a taktéž ISEQV a ISNEV bude ukázáno v dnešním prvním demonstračním příkladu:
-- -- LuaJIT: demonstracni priklad cislo 13 -- -- Porovnavani promennych obsahujicich numericke hodnoty. -- -- inicializace promennych numerickymi konstantami local a = 1 local b = 2 -- inicializace promennych s vyuzitim relacnich vyrazu local x1 = a == b local x2 = a ~= b local x3 = a < b local x4 = a <= b local x5 = a > b local x6 = a > b -- tisk hodnot vsech promennych print(a) print(b) print() print(x1) print(x2) print(x3) print(x4) print(x5) print(x6) -- finito
Podívejme se nyní na překlad tohoto příkladu do IR. Z vygenerovaného IR je patrné, že se výrazy s relačními operátory přeložily do sekvence instrukcí s podmíněnými a nepodmíněnými skoky (a to zajímavější bude zjištění, co s těmito skoky provede vlastní JIT :-):
; Překlad demonstračního příkladu test13.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test13.lua:0-40 0001 KSHORT 0 1 ; do slotu číslo 0 uložit hodnotu 1 0002 KSHORT 1 2 ; do slotu číslo 1 uložit hodnotu 2 0003 ISEQV 0 1 ; porovnání dvou proměnných na rovnost 0004 JMP 2 => 0007 ; skok provedený při splnění podmínky 0005 KPRI 2 1 ; speciální hodnota false 0006 JMP 3 => 0008 ; nepodmíněný skok 0007 => KPRI 2 2 ; speciální hodnota true 0008 => ISNEV 0 1 ; porovnání dvou proměnných na nerovnost 0009 JMP 3 => 0012 ; skok provedený při splnění podmínky 0010 KPRI 3 1 ; speciální hodnota false 0011 JMP 4 => 0013 ; nepodmíněný skok 0012 => KPRI 3 2 ; speciální hodnota true 0013 => ISLT 0 1 ; porovnání dvou proměnných na relaci "menší než" 0014 JMP 4 => 0017 ; skok provedený při splnění podmínky 0015 KPRI 4 1 ; speciální hodnota false 0016 JMP 5 => 0018 ; nepodmíněný skok 0017 => KPRI 4 2 ; speciální hodnota true 0018 => ISLE 0 1 ; porovnání dvou proměnných na relaci "menší nebo rovno" 0019 JMP 5 => 0022 ; skok provedený při splnění podmínky 0020 KPRI 5 1 ; speciální hodnota false 0021 JMP 6 => 0023 ; nepodmíněný skok 0022 => KPRI 5 2 ; speciální hodnota true 0023 => ISLT 1 0 ; porovnání dvou proměnných na relaci "menší než" 0024 JMP 6 => 0027 ; skok provedený při splnění podmínky 0025 KPRI 6 1 ; speciální hodnota false 0026 JMP 7 => 0028 ; nepodmíněný skok 0027 => KPRI 6 2 ; speciální hodnota true 0028 => ISLE 1 0 ; porovnání dvou proměnných na relaci "menší nebo rovno" 0029 JMP 7 => 0032 ; skok provedený při splnění podmínky 0030 KPRI 7 1 ; speciální hodnota false 0031 JMP 8 => 0033 ; nepodmíněný skok 0032 => KPRI 7 2 ; speciální hodnota true 0033 => GGET 8 0 ; získání reference na funkci se jménem "print" 0034 MOV 9 0 ; parametr použitý při volání funkce print() 0035 CALL 8 1 2 ; volání funkce print() 0036 GGET 8 0 ; získání reference na funkci se jménem "print" 0037 MOV 9 1 ; parametr použitý při volání funkce print() 0038 CALL 8 1 2 ; volání funkce print() 0039 GGET 8 0 ; získání reference na funkci se jménem "print" 0040 CALL 8 1 1 ; volání funkce print() - odřádkování 0041 GGET 8 0 ; získání reference na funkci se jménem "print" 0042 MOV 9 2 ; parametr použitý při volání funkce print() 0043 CALL 8 1 2 ; volání funkce print() 0044 GGET 8 0 ; získání reference na funkci se jménem "print" 0045 MOV 9 3 ; parametr použitý při volání funkce print() 0046 CALL 8 1 2 ; volání funkce print() 0047 GGET 8 0 ; získání reference na funkci se jménem "print" 0048 MOV 9 4 ; parametr použitý při volání funkce print() 0049 CALL 8 1 2 ; volání funkce print() 0050 GGET 8 0 ; získání reference na funkci se jménem "print" 0051 MOV 9 5 ; parametr použitý při volání funkce print() 0052 CALL 8 1 2 ; volání funkce print() 0053 GGET 8 0 ; získání reference na funkci se jménem "print" 0054 MOV 9 6 ; parametr použitý při volání funkce print() 0055 CALL 8 1 2 ; volání funkce print() 0056 GGET 8 0 ; získání reference na funkci se jménem "print" 0057 MOV 9 7 ; parametr použitý při volání funkce print() 0058 CALL 8 1 2 ; volání funkce print() 0059 RET0 0 1 ; návrat z programu ; konec
3. Demonstrační příklad číslo 14: relační operátory pro porovnání proměnné s číselnou konstantou
V mnoha aplikacích se využívá porovnání hodnoty proměnné s numerickou (číselnou) konstantou. V tomto případě nám IR LuaJITu nabízí dvě další instrukce nazvané ISEQN a ISNEN, kde N na konci jména instrukce znamená number, podobně jako V na konci dvou instrukcí zmíněných v předchozí kapitole znamená variable. Tyto dvě nové instrukce jsou vypsány ve třetí tabulce:
# | Instrukce | Operandy | Popis |
---|---|---|---|
1 | ISEQN | slot, konstanta | následuje skok provedený při splnění podmínky A = konstanta |
2 | ISNEN | slot, konstanta | následuje skok provedený při splnění podmínky A ≠ konstanta |
Opět se podívejme na způsob využití obou dvou instrukcí (a současně i instrukcí ISLE, ISLT, ISGE a ISGT) v jednoduchém demonstračním příkladu:
-- -- LuaJIT: demonstracni priklad cislo 14 -- -- Porovnavani promennych obsahujicich numericke hodnoty s konstantami. -- -- inicializace promenne konstantou local a = 1 -- inicializace promennych s vyuzitim relacnich vyrazu local x1 = a == 10 local x2 = a ~= 10 local x3 = a < 10 local x4 = a <= 10 local x5 = a > 10 local x6 = a >= 10 -- tisk hodnot vsech promennych print(a) print() print(x1) print(x2) print(x3) print(x4) print(x5) print(x6) -- finito
Následuje výpis IR tohoto demonstračního příkladu:
; Překlad demonstračního příkladu test14.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test14.lua:0-38 0001 KSHORT 0 1 ; do slotu číslo 0 uložit hodnotu 1 0002 ISEQN 0 0 ; porovnání obsahu slotu/proměnné 0 s konstantou 10 0003 JMP 1 => 0006 ; skok provedený při splnění podmínky 0004 KPRI 1 1 ; speciální hodnota false 0005 JMP 2 => 0007 ; nepodmíněný skok 0006 => KPRI 1 2 ; speciální hodnota true 0007 => ISNEN 0 0 ; porovnání obsahu slotu/proměnné 0 s konstantou 10 0008 JMP 2 => 0011 ; skok provedený při splnění podmínky 0009 KPRI 2 1 ; speciální hodnota false 0010 JMP 3 => 0012 ; nepodmíněný skok 0011 => KPRI 2 2 ; speciální hodnota true 0012 => KSHORT 3 10 ; konstanta 10 použitá pro porovnávání 0013 ISLT 0 3 ; porovnání obsahu slotu/proměnné 0 s hodnotou 10 uloženou do dalšího slotu 0014 JMP 3 => 0017 ; skok provedený při splnění podmínky 0015 KPRI 3 1 ; speciální hodnota false 0016 JMP 4 => 0018 ; nepodmíněný skok 0017 => KPRI 3 2 ; speciální hodnota true 0018 => KSHORT 4 10 ; konstanta 10 použitá pro porovnávání 0019 ISLE 0 4 ; porovnání obsahu slotu/proměnné 0 s hodnotou 10 uloženou do dalšího slotu 0020 JMP 4 => 0023 ; skok provedený při splnění podmínky 0021 KPRI 4 1 ; speciální hodnota false 0022 JMP 5 => 0024 ; nepodmíněný skok 0023 => KPRI 4 2 ; speciální hodnota true 0024 => KSHORT 5 10 ; konstanta 10 použitá pro porovnávání 0025 ISLT 5 0 ; porovnání obsahu slotu/proměnné 0 s hodnotou 10 uloženou do dalšího slotu 0026 JMP 5 => 0029 ; skok provedený při splnění podmínky 0027 KPRI 5 1 ; speciální hodnota false 0028 JMP 6 => 0030 ; nepodmíněný skok 0029 => KPRI 5 2 ; speciální hodnota true 0030 => KSHORT 6 10 ; konstanta 10 použitá pro porovnávání 0031 ISLE 6 0 ; porovnání obsahu slotu/proměnné 0 s hodnotou 10 uloženou do dalšího slotu 0032 JMP 6 => 0035 ; skok provedený při splnění podmínky 0033 KPRI 6 1 ; speciální hodnota false 0034 JMP 7 => 0036 ; nepodmíněný skok 0035 => KPRI 6 2 ; speciální hodnota true 0036 => GGET 7 0 ; získání reference na funkci se jménem "print" 0037 MOV 8 0 ; parametr použitý při volání funkce print() 0038 CALL 7 1 2 ; volání funkce print() 0039 GGET 7 0 ; získání reference na funkci se jménem "print" 0040 CALL 7 1 1 ; volání funkce print() 0041 GGET 7 0 ; získání reference na funkci se jménem "print" 0042 MOV 8 1 ; parametr použitý při volání funkce print() 0043 CALL 7 1 2 ; volání funkce print() 0044 GGET 7 0 ; získání reference na funkci se jménem "print" 0045 MOV 8 2 ; parametr použitý při volání funkce print() 0046 CALL 7 1 2 ; volání funkce print() 0047 GGET 7 0 ; získání reference na funkci se jménem "print" 0048 MOV 8 3 ; parametr použitý při volání funkce print() 0049 CALL 7 1 2 ; volání funkce print() 0050 GGET 7 0 ; získání reference na funkci se jménem "print" 0051 MOV 8 4 ; parametr použitý při volání funkce print() 0052 CALL 7 1 2 ; volání funkce print() 0053 GGET 7 0 ; získání reference na funkci se jménem "print" 0054 MOV 8 5 ; parametr použitý při volání funkce print() 0055 CALL 7 1 2 ; volání funkce print() 0056 GGET 7 0 ; získání reference na funkci se jménem "print" 0057 MOV 8 6 ; parametr použitý při volání funkce print() 0058 CALL 7 1 2 ; volání funkce print() 0059 RET0 0 1 ; návrat z programu ; konec
4. Demonstrační příklad číslo 15: porovnání hodnoty proměnné s booleovskou konstantou true či false
IR LuaJITu obsahuje dvě další instrukce nazvané ISEQP a ISNEP. Tyto instrukce slouží pro porovnání obsahu slotu/proměnné s jednou ze tří speciálních konstant jazyka Lua: true, false či nil. Tyto hodnoty jsou v instrukčním slově IR reprezentovány čísly 0, 1 a 2, což jsme již ostatně viděli v předchozích výpisech IR, konkrétně u instrukce KPRI. Použití instrukcí ISEQP a ISNEP je velmi snadné:
# | Instrukce | Operandy | Popis |
---|---|---|---|
1 | ISEQP | slot, pri | následuje skok provedený při splnění podmínky A = pri_type |
2 | ISNEP | slot, pri | následuje skok provedený při splnění podmínky A ≠ pri_type |
Nejdříve se podívejme na způsob porovnání obsahu proměnné s hodnotou true či false (ve skutečnosti takto přímé porovnání není většinou zapotřebí provádět, minimálně ne v jazyku Lua):
-- -- LuaJIT: demonstracni priklad cislo 15 -- -- Porovnavani promennych obsahujicich booleovske hodnoty s booleovskymi konstantami. -- -- inicializace promenne booleovskou konstantou local a = true -- inicializace promennych s vyuzitim porovnani s booleovskou konstantou local x1 = a == true local x2 = a ~= true local x3 = a == false local x4 = a ~= false -- tisk hodnot vsech promennych print(a) print() print(x1) print(x2) print(x3) print(x4) -- finito
V přeloženém IR skutečně můžeme vidět použití instrukcí ISEQP a ISNEP:
; Překlad demonstračního příkladu test15.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test15.lua:0-34 0001 KPRI 0 2 ; do slotu číslo 0 uložit hodnotu true 0002 ISEQP 0 2 ; porovnání obsahu proměnné s hodnotou true 0003 JMP 1 => 0006 ; skok provedený při splnění podmínky 0004 KPRI 1 1 ; speciální hodnota false 0005 JMP 2 => 0007 ; nepodmíněný skok 0006 => KPRI 1 2 ; speciální hodnota true 0007 => ISNEP 0 2 ; porovnání obsahu proměnné s hodnotou true 0008 JMP 2 => 0011 ; skok provedený při splnění podmínky 0009 KPRI 2 1 ; speciální hodnota false 0010 JMP 3 => 0012 ; nepodmíněný skok 0011 => KPRI 2 2 ; speciální hodnota true 0012 => ISEQP 0 1 ; porovnání obsahu proměnné s hodnotou false 0013 JMP 3 => 0016 ; skok provedený při splnění podmínky 0014 KPRI 3 1 ; speciální hodnota false 0015 JMP 4 => 0017 ; nepodmíněný skok 0016 => KPRI 3 2 ; speciální hodnota true 0017 => ISNEP 0 1 ; porovnání obsahu proměnné s hodnotou false 0018 JMP 4 => 0021 ; skok provedený při splnění podmínky 0019 KPRI 4 1 ; speciální hodnota false 0020 JMP 5 => 0022 ; nepodmíněný skok 0021 => KPRI 4 2 ; speciální hodnota true 0022 => GGET 5 0 ; získání reference na funkci se jménem "print" 0023 MOV 6 0 ; parametr použitý při volání funkce print() 0024 CALL 5 1 2 ; volání funkce print() 0025 GGET 5 0 ; získání reference na funkci se jménem "print" 0026 CALL 5 1 1 ; volání funkce print() 0027 GGET 5 0 ; získání reference na funkci se jménem "print" 0028 MOV 6 1 ; parametr použitý při volání funkce print() 0029 CALL 5 1 2 ; volání funkce print() 0030 GGET 5 0 ; získání reference na funkci se jménem "print" 0031 MOV 6 2 ; parametr použitý při volání funkce print() 0032 CALL 5 1 2 ; volání funkce print() 0033 GGET 5 0 ; získání reference na funkci se jménem "print" 0034 MOV 6 3 ; parametr použitý při volání funkce print() 0035 CALL 5 1 2 ; volání funkce print() 0036 GGET 5 0 ; získání reference na funkci se jménem "print" 0037 MOV 6 4 ; parametr použitý při volání funkce print() 0038 CALL 5 1 2 ; volání funkce print() 0039 RET0 0 1 ; návrat z programu ; konec
5. Demonstrační příklad číslo 16: porovnání hodnoty proměnné s konstantou nil
Stejné dvě instrukce ISEQP a ISNEP:
# | Instrukce | Operandy | Popis |
---|---|---|---|
1 | ISEQP | slot, pri | následuje skok provedený při splnění podmínky A = pri_type |
2 | ISNEP | slot, pri | následuje skok provedený při splnění podmínky A ≠ pri_type |
mohou být použity pro porovnání libovolné proměnné s hodnotou nil:
-- -- LuaJIT: demonstracni priklad cislo 16 -- -- Porovnavani promennych obsahujicich libovolnou hodnoty s konstantou nil. -- -- inicializace promennych konstantami ruznych typu local a = true local b = false local c = nil local d = 42 local e = {1,2} -- inicializace promennych s vyuzitim porovnani s konstantou nil. local x1 = a == nil local x2 = a ~= nil local x3 = b == nil local x4 = b ~= nil local x5 = c == nil local x6 = c ~= nil local x7 = d == nil local x8 = d ~= nil local x9 = e == nil local x10 = e ~= nil -- tisk hodnot vsech promennych print(a) print() print(x1) print(x2) print(x3) print(x4) print(x5) print(x6) print(x7) print(x8) print(x9) print(x10) -- finito
Opět se podívejme na IR vygenerovaný LuaJITem:
; Překlad demonstračního příkladu test16.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test16.lua:0-50 0001 KPRI 0 2 ; local a = true 0002 KPRI 1 1 ; local b = false 0003 KPRI 2 0 ; local c = nil 0004 KSHORT 3 42 ; local d = 42 0005 TDUP 4 0 ; local e = {1,2} 0006 ISEQP 0 0 ; porovnání obsahu proměnné s hodnotou nil 0007 JMP 5 => 0010 ; skok provedený při splnění podmínky 0008 KPRI 5 1 ; speciální hodnota false 0009 JMP 6 => 0011 ; nepodmíněný skok 0010 => KPRI 5 2 ; speciální hodnota true 0011 => ISNEP 0 0 ; porovnání obsahu proměnné s hodnotou nil (opačná podmínka) 0012 JMP 6 => 0015 ; skok provedený při splnění podmínky 0013 KPRI 6 1 ; speciální hodnota false 0014 JMP 7 => 0016 ; nepodmíněný skok 0015 => KPRI 6 2 ; speciální hodnota true 0016 => ISEQP 1 0 ; porovnání obsahu proměnné s hodnotou nil 0017 JMP 7 => 0020 ; skok provedený při splnění podmínky 0018 KPRI 7 1 ; speciální hodnota false 0019 JMP 8 => 0021 ; nepodmíněný skok 0020 => KPRI 7 2 ; speciální hodnota true 0021 => ISNEP 1 0 ; porovnání obsahu proměnné s hodnotou nil (opačná podmínka) 0022 JMP 8 => 0025 ; skok provedený při splnění podmínky 0023 KPRI 8 1 ; speciální hodnota false 0024 JMP 9 => 0026 ; nepodmíněný skok 0025 => KPRI 8 2 ; speciální hodnota true 0026 => ISEQP 2 0 ; porovnání obsahu proměnné s hodnotou nil 0027 JMP 9 => 0030 ; skok provedený při splnění podmínky 0028 KPRI 9 1 ; speciální hodnota false 0029 JMP 10 => 0031 ; nepodmíněný skok 0030 => KPRI 9 2 ; speciální hodnota true 0031 => ISNEP 2 0 ; porovnání obsahu proměnné s hodnotou nil (opačná podmínka) 0032 JMP 10 => 0035 ; skok provedený při splnění podmínky 0033 KPRI 10 1 ; speciální hodnota false 0034 JMP 11 => 0036 ; nepodmíněný skok 0035 => KPRI 10 2 ; speciální hodnota true 0036 => ISEQP 3 0 ; porovnání obsahu proměnné s hodnotou nil 0037 JMP 11 => 0040 ; skok provedený při splnění podmínky 0038 KPRI 11 1 ; speciální hodnota false 0039 JMP 12 => 0041 ; nepodmíněný skok 0040 => KPRI 11 2 ; speciální hodnota true 0041 => ISNEP 3 0 ; porovnání obsahu proměnné s hodnotou nil (opačná podmínka) 0042 JMP 12 => 0045 ; skok provedený při splnění podmínky 0043 KPRI 12 1 ; speciální hodnota false 0044 JMP 13 => 0046 ; nepodmíněný skok 0045 => KPRI 12 2 ; speciální hodnota true 0046 => ISEQP 4 0 ; porovnání obsahu proměnné s hodnotou nil 0047 JMP 13 => 0050 ; skok provedený při splnění podmínky 0048 KPRI 13 1 ; speciální hodnota false 0049 JMP 14 => 0051 ; nepodmíněný skok 0050 => KPRI 13 2 ; speciální hodnota true 0051 => ISNEP 4 0 ; porovnání obsahu proměnné s hodnotou nil (opačná podmínka) 0052 JMP 14 => 0055 ; skok provedený při splnění podmínky 0053 KPRI 14 1 ; speciální hodnota false 0054 JMP 15 => 0056 ; nepodmíněný skok 0055 => KPRI 14 2 ; speciální hodnota true 0056 => GGET 15 1 ; získání reference na funkci se jménem "print" 0057 MOV 16 0 ; parametr použitý při volání funkce print() 0058 CALL 15 1 2 ; volání funkce print() 0059 GGET 15 1 ; získání reference na funkci se jménem "print" 0060 CALL 15 1 1 ; volání funkce print() 0061 GGET 15 1 ; získání reference na funkci se jménem "print" 0062 MOV 16 5 ; parametr použitý při volání funkce print() 0063 CALL 15 1 2 ; volání funkce print() 0064 GGET 15 1 ; získání reference na funkci se jménem "print" 0065 MOV 16 6 ; parametr použitý při volání funkce print() 0066 CALL 15 1 2 ; volání funkce print() 0067 GGET 15 1 ; získání reference na funkci se jménem "print" 0068 MOV 16 7 ; parametr použitý při volání funkce print() 0069 CALL 15 1 2 ; volání funkce print() 0070 GGET 15 1 ; získání reference na funkci se jménem "print" 0071 MOV 16 8 ; parametr použitý při volání funkce print() 0072 CALL 15 1 2 ; volání funkce print() 0073 GGET 15 1 ; získání reference na funkci se jménem "print" 0074 MOV 16 9 ; parametr použitý při volání funkce print() 0075 CALL 15 1 2 ; volání funkce print() 0076 GGET 15 1 ; získání reference na funkci se jménem "print" 0077 MOV 16 10 ; parametr použitý při volání funkce print() 0078 CALL 15 1 2 ; volání funkce print() 0079 GGET 15 1 ; získání reference na funkci se jménem "print" 0080 MOV 16 11 ; parametr použitý při volání funkce print() 0081 CALL 15 1 2 ; volání funkce print() 0082 GGET 15 1 ; získání reference na funkci se jménem "print" 0083 MOV 16 12 ; parametr použitý při volání funkce print() 0084 CALL 15 1 2 ; volání funkce print() 0085 GGET 15 1 ; získání reference na funkci se jménem "print" 0086 MOV 16 13 ; parametr použitý při volání funkce print() 0087 CALL 15 1 2 ; volání funkce print() 0088 GGET 15 1 ; získání reference na funkci se jménem "print" 0089 MOV 16 14 ; parametr použitý při volání funkce print() 0090 CALL 15 1 2 ; volání funkce print() 0091 RET0 0 1 ; návrat z programu ; konec
6. Demonstrační příklad číslo 17: porovnání hodnoty proměnné s řetězcem
Další dvě instrukce pojmenované ISEQS a ISNES slouží pro porovnání hodnoty proměnné s řetězcem, přesněji řečeno s řetězcovou konstantou (literálem). Vznik jména těchto instrukcí je zřejmý: is+equal/not equal + string. V instrukčním slově je uložen operační kód instrukce, číslo slotu/indexu lokální proměnné a taktéž index řetězcové konstanty:
# | Instrukce | Operandy | Popis |
---|---|---|---|
1 | ISEQS | slot, string | následuje skok provedený při splnění podmínky A = string |
2 | ISNES | slot, string | následuje skok provedený při splnění podmínky A ≠ string |
Opět se podívejme na jednoduchý příklad, v němž se porovnávají obsahy proměnných různých typů s řetězcovou konstantou:
-- -- LuaJIT: demonstracni priklad cislo 17 -- -- Porovnavani promennych s retezcem. -- -- inicializace promennych konstantami ruznych typu local a = true local b = false local c = nil local d = 42 local e = "hello" -- inicializace promennych s vyuzitim porovnani s konstantou nil. local x1 = a == "hello" local x2 = a ~= "hello" local x3 = b == "hello" local x4 = b ~= "hello" local x5 = c == "hello" local x6 = c ~= "hello" local x7 = d == "hello" local x8 = d ~= "hello" local x9 = e == "hello" local x10 = e ~= "hello" -- tisk hodnot vsech promennych print(a) print() print(x1) print(x2) print(x3) print(x4) print(x5) print(x6) print(x7) print(x8) print(x9) print(x10) -- finito
V přeloženém IR vidíme použití instrukcí ISEQS a ISNES:
; Překlad demonstračního příkladu test17.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test17.lua:0-50 0001 KPRI 0 2 ; deklarace a inicializace lokální proměnné a=true 0002 KPRI 1 1 ; deklarace a inicializace lokální proměnné b=false 0003 KPRI 2 0 ; deklarace a inicializace lokální proměnné c=nil 0004 KSHORT 3 42 ; deklarace a inicializace lokální proměnné d=42 0005 KSTR 4 0 ; deklarace a inicializace lokální proměnné e="hello" 0006 ISEQS 0 0 ; porovnání obsahu proměnné s řetězcem "hello" 0007 JMP 5 => 0010 ; skok provedený při splnění podmínky 0008 KPRI 5 1 ; speciální hodnota false 0009 JMP 6 => 0011 ; nepodmíněný skok 0010 => KPRI 5 2 ; speciální hodnota true 0011 => ISNES 0 0 ; porovnání obsahu proměnné s řetězcem "hello" (opačná podmínka) 0012 JMP 6 => 0015 ; skok provedený při splnění podmínky 0013 KPRI 6 1 ; speciální hodnota false 0014 JMP 7 => 0016 ; nepodmíněný skok 0015 => KPRI 6 2 ; speciální hodnota true 0016 => ISEQS 1 0 ; porovnání obsahu proměnné s řetězcem "hello" 0017 JMP 7 => 0020 ; skok provedený při splnění podmínky 0018 KPRI 7 1 ; speciální hodnota false 0019 JMP 8 => 0021 ; nepodmíněný skok 0020 => KPRI 7 2 ; speciální hodnota true 0021 => ISNES 1 0 ; porovnání obsahu proměnné s řetězcem "hello" (opačná podmínka) 0022 JMP 8 => 0025 ; skok provedený při splnění podmínky 0023 KPRI 8 1 ; speciální hodnota false 0024 JMP 9 => 0026 ; nepodmíněný skok 0025 => KPRI 8 2 ; speciální hodnota true 0026 => ISEQS 2 0 ; porovnání obsahu proměnné s řetězcem "hello" 0027 JMP 9 => 0030 ; skok provedený při splnění podmínky 0028 KPRI 9 1 ; speciální hodnota false 0029 JMP 10 => 0031 ; nepodmíněný skok 0030 => KPRI 9 2 ; speciální hodnota true 0031 => ISNES 2 0 ; porovnání obsahu proměnné s řetězcem "hello" (opačná podmínka) 0032 JMP 10 => 0035 ; skok provedený při splnění podmínky 0033 KPRI 10 1 ; speciální hodnota false 0034 JMP 11 => 0036 ; nepodmíněný skok 0035 => KPRI 10 2 ; speciální hodnota true 0036 => ISEQS 3 0 ; porovnání obsahu proměnné s řetězcem "hello" 0037 JMP 11 => 0040 ; skok provedený při splnění podmínky 0038 KPRI 11 1 ; speciální hodnota false 0039 JMP 12 => 0041 ; nepodmíněný skok 0040 => KPRI 11 2 ; speciální hodnota true 0041 => ISNES 3 0 ; porovnání obsahu proměnné s řetězcem "hello" (opačná podmínka) 0042 JMP 12 => 0045 ; skok provedený při splnění podmínky 0043 KPRI 12 1 ; speciální hodnota false 0044 JMP 13 => 0046 ; nepodmíněný skok 0045 => KPRI 12 2 ; speciální hodnota true 0046 => ISEQS 4 0 ; porovnání obsahu proměnné s řetězcem "hello" 0047 JMP 13 => 0050 ; skok provedený při splnění podmínky 0048 KPRI 13 1 ; speciální hodnota false 0049 JMP 14 => 0051 ; nepodmíněný skok 0050 => KPRI 13 2 ; speciální hodnota true 0051 => ISNES 4 0 ; porovnání obsahu proměnné s řetězcem "hello" (opačná podmínka) 0052 JMP 14 => 0055 ; skok provedený při splnění podmínky 0053 KPRI 14 1 ; speciální hodnota false 0054 JMP 15 => 0056 ; nepodmíněný skok 0055 => KPRI 14 2 ; speciální hodnota true 0056 => GGET 15 1 ; získání reference na funkci se jménem "print" 0057 MOV 16 0 ; parametr použitý při volání funkce print() 0058 CALL 15 1 2 ; volání funkce print() 0059 GGET 15 1 ; získání reference na funkci se jménem "print" 0060 CALL 15 1 1 ; volání funkce print() 0061 GGET 15 1 ; získání reference na funkci se jménem "print" 0062 MOV 16 5 ; parametr použitý při volání funkce print() 0063 CALL 15 1 2 ; volání funkce print() 0064 GGET 15 1 ; získání reference na funkci se jménem "print" 0065 MOV 16 6 ; parametr použitý při volání funkce print() 0066 CALL 15 1 2 ; volání funkce print() 0067 GGET 15 1 ; získání reference na funkci se jménem "print" 0068 MOV 16 7 ; parametr použitý při volání funkce print() 0069 CALL 15 1 2 ; volání funkce print() 0070 GGET 15 1 ; získání reference na funkci se jménem "print" 0071 MOV 16 8 ; parametr použitý při volání funkce print() 0072 CALL 15 1 2 ; volání funkce print() 0073 GGET 15 1 ; získání reference na funkci se jménem "print" 0074 MOV 16 9 ; parametr použitý při volání funkce print() 0075 CALL 15 1 2 ; volání funkce print() 0076 GGET 15 1 ; získání reference na funkci se jménem "print" 0077 MOV 16 10 ; parametr použitý při volání funkce print() 0078 CALL 15 1 2 ; volání funkce print() 0079 GGET 15 1 ; získání reference na funkci se jménem "print" 0080 MOV 16 11 ; parametr použitý při volání funkce print() 0081 CALL 15 1 2 ; volání funkce print() 0082 GGET 15 1 ; získání reference na funkci se jménem "print" 0083 MOV 16 12 ; parametr použitý při volání funkce print() 0084 CALL 15 1 2 ; volání funkce print() 0085 GGET 15 1 ; získání reference na funkci se jménem "print" 0086 MOV 16 13 ; parametr použitý při volání funkce print() 0087 CALL 15 1 2 ; volání funkce print() 0088 GGET 15 1 ; získání reference na funkci se jménem "print" 0089 MOV 16 14 ; parametr použitý při volání funkce print() 0090 CALL 15 1 2 ; volání funkce print() 0091 RET0 0 1 ; návrat z programu ; konec
7. Demonstrační příklad číslo 18: způsob překladu jednoduchých podmínek typu if x then a if not x then
Posledními dnes popsanými instrukcemi IR jsou instrukce pojmenované IST a ISF. Jedná se o velmi jednoduše použitelné instrukce, které testují, zda je hodnota lokální proměnné nastavena na hodnotu true či false:
# | Instrukce | Operandy | Popis |
---|---|---|---|
1 | IST | slot | následuje skok provedený při splnění podmínky A = true |
2 | ISF | slot | následuje skok provedený při splnění podmínky A = false |
Tyto instrukce se typicky používají pro implementaci jednoduchých podmínek typu if x then a if not x then:
-- -- LuaJIT: demonstracni priklad cislo 18 -- -- Zpracovani jednoduchych podminek typu if x then... -- -- inicializace promennych konstantami ruznych typu local a = true local b = false local c = nil local d = 42 -- jednoduche podminky typu if x then if a then print("a") end if not a then print("!a") end if b then print("b") end if not b then print("!b") end if c then print("c") end if not c then print("!c") end if d then print("d") end if not e then print("!e") end -- finito
V přeloženém IR vidíme velmi přímočaré použití instrukcí IST a IST:
; Překlad demonstračního příkladu test18.lua ; do IR využívaného virtuálním strojem a JIT ; překladačem LuaJIT. -- BYTECODE -- test18.lua:0-54 0001 KPRI 0 2 ; deklarace a inicializace lokální proměnné a=true 0002 KPRI 1 1 ; deklarace a inicializace lokální proměnné b=false 0003 KPRI 2 0 ; deklarace a inicializace lokální proměnné c=nil 0004 KSHORT 3 42 ; deklarace a inicializace lokální proměnné d=42 0005 ISF 0 ; test hodnoty lokální proměnné na hodnotu false 0006 JMP 4 => 0010 ; skok provedený při splnění podmínky 0007 GGET 4 0 ; získání reference na funkci se jménem "print" 0008 KSTR 5 1 ; načtení řetězce "a", který se bude tisknout 0009 CALL 4 1 2 ; volání funkce print() 0010 => IST 0 ; test hodnoty lokální proměnné na hodnotu true 0011 JMP 4 => 0015 ; skok provedený při splnění podmínky 0012 GGET 4 0 ; získání reference na funkci se jménem "print" 0013 KSTR 5 2 ; načtení řetězce "!a", který se bude tisknout 0014 CALL 4 1 2 ; volání funkce print() 0015 => ISF 1 ; test hodnoty lokální proměnné na hodnotu false 0016 JMP 4 => 0020 ; skok provedený při splnění podmínky 0017 GGET 4 0 ; získání reference na funkci se jménem "print" 0018 KSTR 5 3 ; načtení řetězce "b", který se bude tisknout 0019 CALL 4 1 2 ; volání funkce print() 0020 => IST 1 ; test hodnoty lokální proměnné na hodnotu true 0021 JMP 4 => 0025 ; skok provedený při splnění podmínky 0022 GGET 4 0 ; získání reference na funkci se jménem "print" 0023 KSTR 5 4 ; načtení řetězce "!b", který se bude tisknout 0024 CALL 4 1 2 ; volání funkce print() 0025 => ISF 2 ; test hodnoty lokální proměnné na hodnotu false 0026 JMP 4 => 0030 ; skok provedený při splnění podmínky 0027 GGET 4 0 ; získání reference na funkci se jménem "print" 0028 KSTR 5 5 ; načtení řetězce "c", který se bude tisknout 0029 CALL 4 1 2 ; volání funkce print() 0030 => IST 2 ; test hodnoty lokální proměnné na hodnotu true 0031 JMP 4 => 0035 ; skok provedený při splnění podmínky 0032 GGET 4 0 ; získání reference na funkci se jménem "print" 0033 KSTR 5 6 ; načtení řetězce "!c", který se bude tisknout 0034 CALL 4 1 2 ; volání funkce print() 0035 => ISF 3 ; test hodnoty lokální proměnné na hodnotu false 0036 JMP 4 => 0040 ; skok provedený při splnění podmínky 0037 GGET 4 0 ; získání reference na funkci se jménem "print" 0038 KSTR 5 7 ; načtení řetězce "d", který se bude tisknout 0039 CALL 4 1 2 ; volání funkce print() 0040 => GGET 4 8 ; načtení řetězce "e", který se bude tisknout 0041 IST 4 ; test hodnoty lokální proměnné na hodnotu true 0042 JMP 4 => 0046 ; skok provedený při splnění podmínky 0043 GGET 4 0 ; získání reference na funkci se jménem "print" 0044 KSTR 5 9 ; načtení řetězce "!e", který se bude tisknout 0045 CALL 4 1 2 ; volání funkce print() 0046 => RET0 0 1 ; návrat z programu ; konec
8. Repositář se zdrojovými kódy všech šesti dnešních demonstračních příkladů
Všech šest dnes popsaných a taktéž „disasemblovaných“ demonstračních příkladů bylo uloženo do Git repositáře umístěného na adrese https://github.com/tisnik/luajit-examples. Odkazy na prozatím poslední verze těchto příkladů naleznete v tabulce umístěné pod tímto odstavcem:
9. Odkazy na Internetu
- Wikipedia: Mezijazyk
http://cs.wikipedia.org/wiki/Mezijazyk - The LuaJIT Project
http://luajit.org/index.html - LuaJIT FAQ
http://luajit.org/faq.html - LuaJIT Performance Comparison
http://luajit.org/performance.html - LuaJIT 2.0 intellectual property disclosure and research opportunities
http://article.gmane.org/gmane.comp.lang.lua.general/58908 - LuaJIT Wiki
http://wiki.luajit.org/Home - LuaJIT 2.0 Bytecode Instructions
http://wiki.luajit.org/Bytecode-2.0 - Programming in Lua 9.1 – Coroutine Basics,
http://www.lua.org/pil/9.1.html - 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 - 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