LuaJIT – Just in Time překladač pro programovací jazyk Lua (11 – JIT překlad do nativního kódu procesorů s architekturami x86 a ARM)

8. 1. 2015
Doba čtení: 18 minut

Sdílet

Třetím krokem JIT překladu prováděného LuaJITem je transformace pseudoinstrukcí do nativního kódu mikroprocesoru, na němž je LuaJIT spuštěn. LuaJIT podporuje překlad s využitím instrukčních sad mikroprocesorů Intel i AMD (32 bit, 64 bit), ARM (prozatím 32 bit), MIPS a PowerPC. Touto problematikou se budeme zabývat dnes.

Obsah

1. LuaJIT – Just in Time překladač pro programovací jazyk Lua (11 – JIT překlad do nativního kódu procesorů s architekturami x86 a ARM)

2. Specifika překladu pro různé mikroprocesorové architektury

3. x86 (32 bit)

4. x86_64 (64 bit)

5. ARM (32 bit)

6. Demonstrační příklad: jednoduchá programová smyčka typu while

7. Překlad demonstračního příkladu do nativního kódu

   7.1 Překlad pro architekturu x86 (32 bit)

   7.2 Překlad pro architekturu x86_64 (64 bit)

   7.3 Překlad pro architekturu ARM (32 bit)

8. Literatura

9. Odkazy na Internetu

1. LuaJIT – Just in Time překladač pro programovací jazyk Lua (11 – JIT překlad do nativního kódu procesorů s architekturami x86 a ARM)

V dnešní části seriálu o trasovacím just-in-time překladači LuaJIT se budeme zabývat převážně způsobem transformace pseudokódu do nativního (strojového) kódu zvoleného typu mikroprocesoru. Připomeňme si, že se jedná o třetí překlad (či možná lépe řečeno transformaci) prováděný LuaJITem. První překlad je aplikován na veškerý spouštěný kód: zdrojový text napsaný v Lue je překládán do bajtkódu ([1], [2], [3], [4], [5] a [6]).

Tento bajtkód je následně interpretován a teprve ve chvíli, kdy se zjistí, že nějakou část bajtkódu lze považovat za hot loop či hot call, je spuštěn vlastní just-in-time překlad, který detekované „stopy“ (trace) transformuje do mezikódu a následně pak do nativního kódu kompatibilního s aktuálně používaným mikroprocesorem.

2. Specifika překladu pro různé mikroprocesorové architektury

LuaJIT při překladu do nativního kódu využívá některé optimalizační techniky, ovšem velmi důležitý je i fakt, že se snaží o zjištění, zda se v proměnných (a výrazech, programových smyčkách apod.) při práci s numerickými hodnotami používají celá čísla (integer) či čísla reálná (float/double). V programovacím jazyku Lua, přesněji řečeno v jeho doposud používaných verzích, se totiž předpokládá, že numerické hodnoty jsou typu double, což je z hlediska vysokoúrovňového skriptovacího jazyka pochopitelné (omezí se tím poměrně velký počet běhových chyb typu přetečení apod.).

Na druhou stranu ovšem naprostá většina v současnosti používaných mikroprocesorových architektur je postavena na bázi celočíselné aritmeticko-logické jednotky (ALU), která je sice (většinou!) doplněna matematickým koprocesorem, ovšem pro některé operace, typicky pro implementace programových smyček atd., je výhodnější využívat celočíselnou ALU a taktéž celočíselné pracovní registry. Detekce těch proměnných, v nichž se pracuje jen s celými čísly, je tedy pro LuaJIT důležitá, především na architektuře ARM se soft-float. LuaJIT ovšem musí počítat s tím, že může dojít k přetečení, kterému se musí zabránit a tedy tiše a zejména bez ovlivnění běhu aplikace přejít z celočíselného typu int na double.

3. x86 (32 bit)

Na 32bitové platformě x86 se využívají jak celočíselné registry EAX, EBX, ECX, EDX, ESI, EDI a částečně i EBP, tak i registry přidané v rámci rozšiřující instrukční sady SSE. Nová sada registrů je pojmenovaná XMM0XMM7. Všechny nové registry mají šířku 128 bitů, tj. jsou dvakrát širší, než registry používané v MMX3DNow! a čtyřikrát širší, než běžné pracovní registry na platformě x86 (bavíme se nyní o 32bitovém režimu). Do každého registru je možné uložit čtveřici reálných numerických hodnot reprezentovaných v systému plovoucí řádové tečky podle normy IEEE 754 (single), přičemž tato norma je dodržována přesněji, než v případě 3DNow! (různé zaokrouhlovací režimy či práce s denormalizovanými čísly sice mohou vypadat trošku jako černá magie, ovšem například v knihovnách pro numerické výpočty, které musí vždy za specifikovaných okolností dát stejný výsledek, se jedná o velmi důležitou vlastnost). K osmi novým registrům XMM* byl ještě přidán jeden 32bitový registr nazvaný MXCSR, jenž byl určený pro nastavení (řízení) režimů výpočtu.

Ve skutečnosti je však většina instrukcí SSE pro jazyk Lua nepoužitelná :-), protože tyto instrukce pracují pouze s numerickými hodnotami typu single. Podpora pro hodnoty typu double se objevuje až v rozšiřující instrukční sadě SSE2. V rámci SSE2 totiž byly zavedeny dvouprvkové vektory obsahující hodnoty reprezentované ve formátu plovoucí řádové čárky, ovšem tentokrát se jedná o čísla uložená v 64 bitech (2×64=128) odpovídající dvojité přesnosti (double) z normy IEEE 754. LuaJIT SSE2 dokáže velmi efektivně využít, což ostatně uvidíme i na způsobu překladu demonstračního příkladu. Všechny nové operace implementované v SSE2 jsou vypsány v následující tabulce. Ve třetím sloupci je naznačeno, jaké vektory jsou danou operací zpracovávány, přičemž první číslo znamená počet prvků vektoru, za nímž následuje bitová šířka jednotlivých prvků:

# Instrukce Operace/funkce Struktura vektoru Datový typ Saturace? Poznámka
1 addpd součet 2×64bit double ×  
2 addsd součet 1×64bit double × operace provedena jen s pravým prvkem vektorů
3 subpd rozdíl 2×64bit double ×  
4 subsd rozdíl 1×64bit double × operace provedena jen s pravým prvkem vektorů
5 mulpd součin 2×64bit double ×  
6 mulsd součin 1×64bit double × operace provedena jen s pravým prvkem vektorů
7 divpd podíl 2×64bit double ×  
8 divsd podíl 1×64bit double × operace provedena jen s pravým prvkem vektorů
9 paddb součet 16×8bit integer ne  
10 paddw součet 8×16bit integer ne  
11 paddd součet 4×32bit integer ne  
12 paddq součet 2×64bit integer ne  
13 paddsb součet 16×8bit integer ano  
14 paddsw součet 8×16bit integer ano  
15 paddusb součet 16×8bit unsigned ano  
16 paddusw součet 8×16bit unsigned ano  
17 psubb rozdíl 16×8bit integer ne  
18 psubw rozdíl 8×16bit integer ne  
19 psubd rozdíl 4×32bit integer ne  
20 psubq rozdíl 2×64bit integer ne  
21 psubsb rozdíl 16×8bit integer ano  
22 psubsw rozdíl 8×16bit integer ano  
23 psubusb rozdíl 16×8bit unsigned ano  
24 psubusw rozdíl 8×16bit unsigned ano  
25 maxpd maximum 2×64bit double ×  
26 maxsd maximum 2×64bit double × operace provedena jen s pravým prvkem vektorů
27 minpd minimum 2×64bit double ×  
28 minsd minimum 2×64bit double × operace provedena jen s pravým prvkem vektorů
29 pmaddwd součin/add 8×16bit integer ×  
30 pmulhw součin 8×16bit integer × vrací vektor horních 16 bitů výsledků
31 pmullw součin 8×16bit integer × vrací vektor dolních 16 bitů výsledků
32 pmuludq součin 4×32bit integer × 64 bitový výsledek pro každý součin
33 rcpps převrácená hodnota 4×32bit single × aproximace
34 rcpss převrácená hodnota 4×32bit single × operace provedena jen s pravým prvkem vektorů
35 sqrtpd druhá odmocnina 2×64bit double ×  
36 sqrtsd druhá odmocnina 2×64bit double ×   operace provedena jen s pravým prvkem vektorů

4. x86_64 (64 bit)

Pokud LuaJIT zjistí, že je provozován na mikroprocesoru, který podporuje 64bitovou instrukční sadu x86_64 (x64) a současně běžícího v 64bitovém režimu, dokáže při just-in-time překladu využít všech šestnáct univerzálních pracovních registrů (namísto původních osmi registrů), v nichž lze navíc pracovat s 64bitovými hodnotami a nejenom s hodnotami 32bitovými. Možná důležitější je však fakt, že i počet XMM* registrů používaných v SSE/SSE2 se zdvojnásobil z osmi (XMM0-XMM7) na šestnáct, takže lineární alokátor registrů zde má poněkud snazší práci. V mnoha dalších ohledech se však nativní kód určený pro 32bitový režim a 64bitový režim lišit nebude, alespoň u těch demonstračních příkladů, které si budeme ukazovat v navazujících kapitolách popř. i v následujícím pokračování tohoto seriálu.

5. ARM (32 bit)

V případě procesorů z rodiny ARM může LuaJIT, na základě konkrétní konfigurace a možností daného procesoru, využívat soft-float ABI a soft-float operace s numerickými hodnotami typu double (což je nejpomalejší varianta), dále pak soft-float ABI a operace VFPv2 popř. hard-float ABI a taktéž operace VFPv2. Kdykoli je to možné – například u mnoha typů programových smyček – provádí se operace s celočíselnými registry a tím pádem se tyto výpočty odehrávají v ALU procesorů ARM. Význam některých „celočíselných“ instrukcí použitých v nativním kódu dále popsaného demonstračního příkladu je uveden v následující tabulce:

# Instrukce Význam
1 adds r0:=r1+r2 a nastav příznaky N, V, Z, C
     
2 cmp operand1-operand2 (compare a nastav příznaky N, V, Z, C)
3 cmn operand1+operand2 (compare negative a nastav příznaky N, V, Z, C)
     
4 blne podmíněný skok provedený při nerovnosti (Z=0)
5 blvs podmíněný skok provedený při přetečení (V=1)
6 blge podmíněný skok provedený při N=V
7 blt podmíněný skok provedený při N!=V
     
8 bl skok do subrutiny
     
9 ldrd načtení hodnoty do registru

Vraťme se nyní na chvíli k numerickým hodnotám s plovoucí řádovou čárkou. Technologie VFP byla navržena takovým způsobem, aby ji bylo možné použít v mnoha aplikačních oblastech, například v řídicích jednotkách automobilů, pro zpracování obrazu (konvoluční filtry, rychlá Fourierova transformace, rasterizace a další operace prováděné v tiskových procesorech), při zpracování řeči (kodeky) a taktéž pro provádění různých 3D operací (transformace) – právě v těchto oblastech lze totiž využít práci nikoli pouze se skalárními hodnotami, ale taktéž s vektory o dvou až osmi prvcích. Zajímavé je, že později došlo ke sloučení VFP s architekturou NEON.

Původní architektura VFPv1 je již dnes považována za překonanou a v žádných současných čipech se s níž již nesetkáme. Druhá verze této architektury VFPv2 začala být používána na některých čipech ARMv5E, ARMv5TEJ a taktéž na ARMv6 – instrukce VFP v tomto případě rozšiřovaly původní instrukční sady ARM. Zajímavější je dnes třetí verze architektury VFP značená VFPv3 používaná od ARMv7 (samozřejmě jen u vybraných čipů – zdaleka ne všechny aplikační oblasti totiž nutně vyžadují matematický koprocesor). V tomto případě lze nové „vektorové“ instrukce používat v instrukční sadě ARM, Thumb i ThumbEE.

Z hlediska programovacího jazyka Lua je důležité, že se u technologie VFP používají především formáty single/floatdouble, přičemž existují rozšíření i pro formáty s poloviční přesností (half-float), které lze v některých oblastech s výhodou používat, například pro ukládání barvových složek pixelů (zvýší se tím mj. i dynamický rozsah při filtraci obrazu). Vzhledem k tomu, že technologie VFP je určena i pro aplikaci v systémech, v nichž je mnohdy důležité dosáhnout co největšího výpočetního výkonu popř. co nejkratší doby odezvy (RT aplikace), může matematický koprocesor VFP pracovat buď v režimu full compliance, který je přímo kompatibilní s normou IEEE 754, popř. je možné provést přepnutí do režimu RunFast, v němž se negenerují některé výjimky a taktéž může dojít ke ztrátě přesnosti v nejnižších bitech mantisy (většinou pouze v bitu nejnižším). Vlastnosti obou režimů jsou samozřejmě velmi přesně popsány, takže záleží jen na vývojáři, který režim v daný okamžik použije – v případě jazyka Lua to bude typ double a pravděpodobně i režim full compliance.

Matematické koprocesory VFP obecně obsahují šestnáct pracovních registrů, každý o šířce 64 bitů. Tyto registry lze použít buď pro práci s hodnotami s dvojitou přesností (double) – potom se tyto registry v assembleru označují jmény d0d15 (podobně jsou označeny ve zdrojových kódech LuaJITu, akorát s velkými písmeny). Ovšem taktéž je možné libovolný registr rozdělit na dva registry o šířce 32 bitů, z nichž každý dokáže pojmout číselnou hodnotu s jednoduchou přesností (single/float). Díky tomuto rozdělení se počet registrů pro formát single zvětšil na dvojnásobek – tyto registry jsou v assembleru pojmenovány s0s31. Podle konvence dodržované jak překladači, tak i v programových knihovnách se při volání subrutin používají registry d0d7 pro předávání parametrů subrutině, popř. pro získání návratových hodnot ze subrutiny. Samozřejmě se tyto registry taktéž používají při výpočtech v subrutině. Ostatní registry lze taktéž použít, ovšem jejich hodnota by měla být při návratu ze subrutiny obnovena.

Při vzniku technologie VFP se její tvůrci zaměřili na to, aby instrukční sada VFP umožňovala jak práci se skalárními hodnotami, tak i práci s vektory. Na první pohled by se tedy mohlo zdát, že se jedná o jednu z mnoha aplikací architektury SIMD, ve skutečnosti se ovšem v případě VFP vektory zpracovávají sekvenčně. To například znamená, že součet dvou osmiprvkových vektorů realizovaný instrukcí VADD používá tu samou FP-sčítačku a prvky vektorů jsou tedy sečítány postupně. Stále se jedná o rychlejší operaci, než osm krát opakovaná instrukce ADF (mimo jiné se ušetří cykly strávené při načítání a dekódování instrukce – instruction fetchinstruction decode) – ovšem reálný SIMD systém to není, na rozdíl od na první pohled obdobných technologií: 3DNow!, SSE atd. Změna přišla až při sloučení VFP s technologií NEON, která na procesory ARM přinesla skutečné operace SIMD.

6. Demonstrační příklad: jednoduchá programová smyčka typu while

Pro ukázku překladu z mezikódu do nativního kódu bude použit demonstrační příklad, s nímž jsme se již ve stručnosti seznámili minule. V tomto příkladu je implementována programová smyčka typu while, v níž se pracuje s dvojicí proměnných – počitadla i a taktéž proměnné sum. Po provedení 100 iterací je vypsána aktuální hodnota proměnné sum:

--
-- LuaJIT: demonstrační příklad číslo 43.
--
-- Test JITu.
--
 
 
 
local i = 0
local sum = 0
 
while i < 100 do
    sum = sum + 1
    i = i + 1
end
 
print(sum)
 
 
 
--
-- Finito.
--

Tento typ programové smyčky je díky provedení 100 iterací detekován jako stopa vhodná pro JITování (hot loop). Struktura bajtkódu detekované stopy používá instrukci LOOP, která je doplněna o ISGE:

---- TRACE 1 start test43.lua:12
0007  ADDVN    1   1   0  ; 1
0008  ADDVN    0   0   0  ; 1
0009  JMP      2 => 0003
0003  KSHORT   2 100
0004  ISGE     0   2
0005  JMP      2 => 0010
0006  LOOP     2 => 0010

Transformace bajtkódu do sekvence pseudoinstrukcí:

---- TRACE 1 IR
0001 >  int SLOAD  #2    T
0002 >+ int ADDOV  0001  +1
0003 >  int SLOAD  #1    T
0004 >+ int ADDOV  0003  +1
0005 >  int LT     0004  +100
0006 ------ LOOP ------------
0007 >+ int ADDOV  0002  +1
0008 >+ int ADDOV  0004  +1
0009 >  int LT     0008  +100
0010    int PHI    0002  0007
0011    int PHI    0004  0008
---- TRACE 1 stop -> loop

Povšimněte si především použití datového typu int a taktéž využití pseudoinstrukcí ADDOV. LuaJIT předpokládá, že jak proměnná i, tak i proměnná sum bude obsahovat celá čísla typu int, což je sice pravda, ovšem při zvyšování hodnoty těchto proměnných může dojít k přetečení, kterému je zapotřebí zamezit. V následujících podkapitolách uvidíme, že se tyto pseudoinstrukce v některých případech překládají poměrně složitým způsobem, a to kvůli tomu, aby se detekovalo již zmíněné přetečení výsledku a přechod na použití jiného datového typu.

7. Překlad demonstračního příkladu do nativního kódu

Pojďme se nyní podívat na překlad demonstračního příkladu just-in-time překladačem do nativního kódu procesorů s architekturou x86 (32bit), x86_64 (64bit) a ARM (32bit).

7.1 Překlad pro architekturu x86 (32 bit)

Pro 32bitovou platformu x86 se detekovaný hot loop přeloží následujícím způsobem:

---- TRACE 1 mcode 95
0xb7f68f97  mov      dword [0xb7d9f2bc], 0x1
0xb7f68fa1  movsd    xmm1, [0xb7db1bb0]
0xb7f68fa9  movsd    xmm0, [0xb7db1bb8]
0xb7f68fb1  cmp      dword [edx+0xc], -0x0f
0xb7f68fb5  jnb      0xb7f61008    ->0
0xb7f68fbb  movsd    xmm6, [edx+0x8]
0xb7f68fc0  addsd    xmm6, xmm1
0xb7f68fc4  cmp      dword [edx+0x4], -0x0f
0xb7f68fc8  jnb      0xb7f61008    ->0
0xb7f68fce  movsd    xmm7, [edx]
0xb7f68fd2  addsd    xmm7, xmm1
0xb7f68fd6  ucomisd  xmm0, xmm7
0xb7f68fda  jbe      0xb7f6100c    ->1
->LOOP:
0xb7f68fe0  addsd   xmm6, xmm1          ; registr xmm1 obsahuje jedničku, která se přičte k obsahu xmm6
0xb7f68fe4  movaps  xmm5, xmm7
0xb7f68fe7  addsd   xmm7, xmm1          ; další přičtení jedničky
0xb7f68feb  ucomisd xmm0, xmm7          ; test, zda nemá dojít k ukončení smyčky
0xb7f68fef  ja      0xb7f68fe0 ->LOOP   ; opakování smyčky
0xb7f68ff1  jmp     0xb7f61014    ->3
---- TRACE 1 stop -> loop

Můžeme zde vidět několik podmíněných skoků (jnb – jump if not below, jbe – jump if below or equal) a ja – jump if above s podobným významem jako v předchozím nativním kódu.

Z instrukcí, které nebyly vypsány ve třetí kapitole stojí za zmínku movaps (přenos celého 128bitového slova mezi dvěma XMM registry) a ucomisd (porovnání obsahu spodní poloviny dvou registrů a nastavení příznaků v EFLAGS podobným způsobem, jako u instrukce cmp – zde se však porovnávají dvě hodnoty typu double). Vidíme, že všechny výpočty probíhají v registrech XMM a využívá se zde instrukční sada SSE2, což se pozná podle toho, že instrukce končí na písmeno d – double.

7.2 Překlad pro architekturu x86_64 (64 bit)

Pro platformu x86_64 dostaneme v detailech nepatrně odlišný „stroják“:

---- TRACE 1 mcode 104
0x0bceff8e  mov     dword [0x409604a0], 0x1
0x0bceff99  movsd   xmm1, [0x404b0d38]
0x0bceffa2  movsd   xmm0, [0x404b0d40]
0x0bceffab  cmp     dword [rdx+0xc], 0xfffeffff
0x0bceffb2  jnb     0x0bce0010        ->0
0x0bceffb8  movsd   xmm6, [rdx+0x8]
0x0bceffbd  addsd   xmm6, xmm1
0x0bceffc1  cmp     dword [rdx+0x4], 0xfffeffff
0x0bceffc8  jnb     0x0bce0010        ->0
0x0bceffce  movsd   xmm7, [rdx]
0x0bceffd2  addsd   xmm7, xmm1
0x0bceffd6  ucomisd xmm0, xmm7
0x0bceffda  jbe     0x0bce0014        ->1
->LOOP:
0x0bceffe0  addsd   xmm6, xmm1          ; registr xmm1 obsahuje jedničku, která se přičte k obsahu xmm6
0x0bceffe4  movaps  xmm5, xmm7
0x0bceffe7  addsd   xmm7, xmm1          ; další přičtení jedničky
0x0bceffeb  ucomisd xmm0, xmm7          ; test, zda nemá dojít k ukončení smyčky
0x0bceffef  ja      0x0bceffe0 ->LOOP   ; opakování smyčky
0x0bcefff1  jmp     0x0bce001c        ->3
---- TRACE 1 stop -> loop

V tomto jednoduchém demonstračním příkladu se od sebe oba vygenerované kódy na úrovni zdrojových kódů prakticky neliší, až na použití odlišných registrů: EDX vs. RDX. Programová smyčka typu while dokonce byla přeložena totožným způsobem:

x86 (32bit)                    x86_64 (64bit)
-----------------------------------------------------------
addsd   xmm6, xmm1             addsd   xmm6, xmm1
movaps  xmm5, xmm7             movaps  xmm5, xmm7
addsd   xmm7, xmm1             addsd   xmm7, xmm1
ucomisd xmm0, xmm7             ucomisd xmm0, xmm7
ja      0xb7f68fe0 ->LOOP      ja      0x0bceffe0 ->LOOP

Ve skutečnosti se dá toto chování očekávat, protože část LuaJITu, která se stará o překlad na 32bitovou a 64bitovou architekturu, je prakticky shodná.

ict ve školství 24

7.3 Překlad pro architekturu ARM (32 bit)

Překlad do nativního strojového kódu pro 32bitové mikroprocesory ARM vypadá již na první pohled velmi čitelně (což jen ukazuje, jak může být RISCová instrukční sada elegantní):

---- TRACE 1 start test43.lua:12
---- TRACE 1 mcode 84
0x00397fac  ldrd  r4, [r9, #8]
0x00397fb0  cmn   r5, #14
0x00397fb4  blne  0x00390018      ->0
0x00397fb8  adds  r4, r4, #1
0x00397fbc  blvs  0x00390018      ->0
0x00397fc0  ldrd  r6, [r9]
0x00397fc4  cmn   r7, #14
0x00397fc8  blne  0x00390018      ->0
0x00397fcc  adds  r6, r6, #1
0x00397fd0  blvs  0x00390018      ->0
0x00397fd4  cmp   r6, #100
0x00397fd8  blge  0x0039001c      ->1
->LOOP:
0x00397fdc  mov   r11, r6                ; přenos hodnot proměnných do pracovních registrů
0x00397fe0  mov   r10, r4
0x00397fe4  adds  r4, r10, #1            ; přičtení jedničky s uložením výsledku do nového registru a nastavením příznaků
0x00397fe8  blvs  0x00390020      ->2    ; test na přetečení
0x00397fec  adds  r6, r11, #1            ; přičtení jedničky s uložením výsledku do nového registru a nastavením příznaků
0x00397ff0  blvs  0x00390020      ->2    ; test na přetečení
0x00397ff4  cmp   r6, #100               ; test na ukončení smyčky
0x00397ff8  blt   0x00397fdc      ->LOOP ; skok na začátek smyčky - další iterace
0x00397ffc  bl    0x00390024      ->3
---- TRACE 1 stop -> loop

Povšimněte si především množství podmíněných skoků (blne, blvs), kterými jsou realizovány asserce zmíněné v předchozím textu. Dále stojí za zmínku použití instrukcí pracujících pouze s celočíselnými registry – v tomto případě LuaJIT zvolil použití operací s celými čísly typu integer o šířce 32 bitů. To si vyžádalo úpravu programové smyčky takovým způsobem, aby se kontrolovalo přetečení (instrukce adds nastaví všechny potřebné příznaky testované ihned poté podmíněným skokem blvs). Pokud by měl LuaJIT jistotu, že k přetečení nedojde, mohly by se instrukce adds nahradit za add a skoky blvs zcela odstranit (snad se dočkáme v další verzi).

8. Literatura

  1. Bolz, Cuni, Fijalkowski, Rigo:
    „Tracing the Meta-Level: PyPy's Tracing JIT Compiler“
  2. Vasanth Bala, Evelyn Duesterwald, Sanjeev Banerjia:
    „Dynamo: A Transparent Dynamic Optimization System“
  3. Bolz, Cuni, Fijalkowski, Leuschel, Pedroni, Rigo: „Allocation removal by partial evaluation in a tracing JIT“
  4. Bolz:
    „Automatic JIT Compiler Generation with Runtime Partial Evaluation“
  5. Bolz, Kuhn, Lienhard, Matsakis, Nierstrasz, Renggli, Rigo and T. Verwaest:
    „Back to the Future in One Week – Implementing a Smalltalk VM in PyPy“
    pages 123–139. 2008.
  6. Bolz and Rigo:
    „How to not write a virtual machine“
    In Proceedings of the 3rd Workshop on Dynamic Languages and Applications (DYLA), 2007
  7. Bruni, Verwaest:
    „PyGirl: generating Whole-System VMs from High-Level prototypes using PyPy“
    In Tools, accepted for publication, 2009.
  8. Sullivan, Bruening, Baron, Garnett and Amarasinghe:
    „Dynamic native optimization of interpreters“
    In Proceedings of the 2003 Workshop on Interpreters,
    Virtual Machines and Emulators pages 50–57, San Diego, California, 2003. ACM.

9. Odkazy na Internetu

  1. Static single assignment form (SSA)
    http://en.wikipedia.org/wi­ki/Static_single_assignmen­t_form
  2. LuaJIT 2.0 SSA IR
    http://wiki.luajit.org/SSA-IR-2.0
  3. Dynamic Assembler
    http://luajit.org/dynasm.html
  4. The Unofficial DynASM Documentation: Introduction
    http://corsix.github.io/dynasm-doc/index.html
  5. Have tracing JIT compilers won?
    http://lambda-the-ultimate.org/node/3851
  6. Tracing just-in-time compilation
    http://en.wikipedia.org/wi­ki/Tracing_just-in-time_compilation
  7. How does LuaJIT's trace compiler work?
    http://www.freelists.org/pos­t/luajit/How-does-LuaJITs-trace-compiler-work,1
  8. How does LuaJIT's trace compiler work?
    http://stackoverflow.com/qu­estions/20266523/how-does-luajits-trace-compiler-work
  9. TraceMonkey
    https://wiki.mozilla.org/Ja­vaScript:TraceMonkey
  10. TraceMonkey
    http://brendaneich.com/2008/08/tra­cemonkey-javascript-lightspeed/
  11. Improving JavaScript performance with JägerMonkey
    http://hacks.mozilla.org/2010/03/im­proving-javascript-performance-with-jagermonkey/
  12. Wikipedia: Mezijazyk
    http://cs.wikipedia.org/wi­ki/Mezijazyk
  13. The LuaJIT Project
    http://luajit.org/index.html
  14. LuaJIT FAQ
    http://luajit.org/faq.html
  15. LuaJIT Performance Comparison
    http://luajit.org/performance.html
  16. LuaJIT 2.0 intellectual property disclosure and research opportunities
    http://article.gmane.org/gma­ne.comp.lang.lua.general/58908
  17. LuaJIT Wiki
    http://wiki.luajit.org/Home
  18. LuaJIT 2.0 Bytecode Instructions
    http://wiki.luajit.org/Bytecode-2.0
  19. Programming in Lua 9.1 – Coroutine Basics,
    http://www.lua.org/pil/9.1.html
  20. Programming in Lua (first edition)
    http://www.lua.org/pil/contents.html
  21. Programming in Lua: 6 – More about Functions
    http://www.lua.org/pil/6.html
  22. Lua Lanes
    http://kotisivu.dnainternet­.net/askok/bin/lanes/
  23. Programming in Lua: 6.1 – Closures
    http://www.lua.org/pil/6.1.html
  24. Programming in Lua: 9.1 – Coroutine Basics
    http://www.lua.org/pil/9.1.html
  25. Programming in Lua: Numeric for
    http://www.lua.org/pil/4.3.4.html
  26. Programming in Lua: break and return
    http://www.lua.org/pil/4.4.html
  27. Programming in Lua: Tables
    http://www.lua.org/pil/2.5.html
  28. Programming in Lua: Table Constructors
    http://www.lua.org/pil/3.6.html
  29. Programovací jazyk Lua
    http://palmknihy.cz/web/kni­ha/programovaci-jazyk-lua-12651.htm
  30. Lua: Tables Tutorial
    http://lua-users.org/wiki/TablesTutorial
  31. Lua: Control Structure Tutorial
    http://lua-users.org/wiki/ControlStruc­tureTutorial
  32. Lua Types Tutorial
    http://lua-users.org/wiki/LuaTypesTutorial
  33. Goto Statement in Lua
    http://lua-users.org/wiki/GotoStatement
  34. Lua 5.2 sources
    http://www.lua.org/source/5.2/
  35. Lua 5.2 sources – lopcodes.h
    http://www.lua.org/source/5­.2/lopcodes.h.html
  36. Lua 5.2 sources – lopcodes.c
    http://www.lua.org/source/5­.2/lopcodes.c.html
  37. Lambda the Ultimate: Coroutines in Lua,
    http://lambda-the-ultimate.org/node/438
  38. Coroutines Tutorial,
    http://lua-users.org/wiki/CoroutinesTutorial
  39. Lua Coroutines Versus Python Generators,
    http://lua-users.org/wiki/LuaCorouti­nesVersusPythonGenerators
  40. SSE (Streaming SIMD Extentions)
    http://www.songho.ca/misc/sse/sse­.html
  41. Timothy A. Chagnon: SSE and SSE2
    http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf
  42. Intel corporation: Extending the World's Most Popular Processor Architecture
    http://download.intel.com/techno­logy/architecture/new-instructions-paper.pdf
  43. SIMD architectures:
    http://arstechnica.com/ol­d/content/2000/03/simd.ar­s/
  44. Sixth Generation Processors
    http://www.pcguide.com/ref/cpu/fam/g6­.htm
  45. Great Microprocessors of the Past and Present
    http://www.cpushack.com/CPU/cpu1.html
  46. The VFP architecture
    http://infocenter.arm.com/hel­p/index.jsp?topic=/com.ar­m.doc.dui0056d/Bcfibfha.html
  47. ARM Floating Point Accelerator (ARM FPA)
    http://vswww.kaist.ac.kr/ver4­.0/index.php/research/past-research/arm-fpa.html
  48. The ARM Processor Architecture
    http://www.arm.com/produc­ts/processors/technologies/in­struction-set-architectures.php

Autor článku

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