Hlavní navigace

LuaJIT – Just in Time překladač pro programovací jazyk Lua (3)

28. 10. 2014
Doba čtení: 23 minut

Sdílet

Ve třetím článku o Just in Time překladači LuaJIT si popíšeme všechny instrukce mezijazyka (IR) implementující podmínky a relační operátory. Jedná se o rozšíření tématu, kterému jsme se věnovali minule, dnes se však budeme zabývat mj. i porovnáním obsahu proměnných s řetězci či se speciálními hodnotami true, false a nil.

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

7. Demonstrační příklad číslo 18: způsob překladu jednoduchých podmínek typu if x thenif not x then

8. Repositář se zdrojovými kódy všech šesti dnešních demonstračních příkladů

9. Odkazy na Internetu

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, ISLEISGT. 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 ISEQVISNEV 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éž ISEQVISNEV 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é ISEQNISNEN, 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, ISGEISGT) 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é ISEQPISNEP. 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í ISEQPISNEP 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í ISEQPISNEP:

; 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 ISEQPISNEP:

# 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é ISEQSISNES 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í ISEQSISNES:

; 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 thenif not x then

Posledními dnes popsanými instrukcemi IR jsou instrukce pojmenované ISTISF. 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 thenif not x then:

CS24_early

--
-- 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í ISTIST:

; 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

  1. Wikipedia: Mezijazyk
    http://cs.wikipedia.org/wi­ki/Mezijazyk
  2. The LuaJIT Project
    http://luajit.org/index.html
  3. LuaJIT FAQ
    http://luajit.org/faq.html
  4. LuaJIT Performance Comparison
    http://luajit.org/performance.html
  5. LuaJIT 2.0 intellectual property disclosure and research opportunities
    http://article.gmane.org/gma­ne.comp.lang.lua.general/58908
  6. LuaJIT Wiki
    http://wiki.luajit.org/Home
  7. LuaJIT 2.0 Bytecode Instructions
    http://wiki.luajit.org/Bytecode-2.0
  8. Programming in Lua 9.1 – Coroutine Basics,
    http://www.lua.org/pil/9.1.html
  9. Programming in Lua (first edition)
    http://www.lua.org/pil/contents.html
  10. Programming in Lua: 6 – More about Functions
    http://www.lua.org/pil/6.html
  11. Lua Lanes
    http://kotisivu.dnainternet­.net/askok/bin/lanes/
  12. Programming in Lua: 6.1 – Closures
    http://www.lua.org/pil/6.1.html
  13. Programming in Lua: 9.1 – Coroutine Basics
    http://www.lua.org/pil/9.1.html
  14. Programming in Lua: Numeric for
    http://www.lua.org/pil/4.3.4.html
  15. Programming in Lua: break and return
    http://www.lua.org/pil/4.4.html
  16. Programming in Lua: Tables
    http://www.lua.org/pil/2.5.html
  17. Programming in Lua: Table Constructors
    http://www.lua.org/pil/3.6.html
  18. Programovací jazyk Lua
    http://palmknihy.cz/web/kni­ha/programovaci-jazyk-lua-12651.htm
  19. Lua: Tables Tutorial
    http://lua-users.org/wiki/TablesTutorial
  20. Lua: Control Structure Tutorial
    http://lua-users.org/wiki/ControlStruc­tureTutorial
  21. Lua Types Tutorial
    http://lua-users.org/wiki/LuaTypesTutorial
  22. Goto Statement in Lua
    http://lua-users.org/wiki/GotoStatement
  23. Lua 5.2 sources
    http://www.lua.org/source/5.2/
  24. Lua 5.2 sources – lopcodes.h
    http://www.lua.org/source/5­.2/lopcodes.h.html
  25. Lua 5.2 sources – lopcodes.c
    http://www.lua.org/source/5­.2/lopcodes.c.html
  26. Lambda the Ultimate: Coroutines in Lua,
    http://lambda-the-ultimate.org/node/438
  27. Coroutines Tutorial,
    http://lua-users.org/wiki/CoroutinesTutorial
  28. Lua Coroutines Versus Python Generators,
    http://lua-users.org/wiki/LuaCorouti­nesVersusPythonGenerators

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.