Obsah
1.2 Tabulka se strojovými instrukcemi použitými při překladu do strojového kódu mikroprocesorů ARM
2. První demonstrační příklad test54.lua – výpočet (konvergující) geometrické řady
2.3 Překlad stopy do sekvence meziinstrukcí
3. Překlad prvního demonstračního příkladu do strojového kódu procesorů x86_64
4. Překlad prvního demonstračního příkladu do strojového kódu procesorů ARM
5. Druhý demonstrační příklad test55.lua – složitější výpočty prováděné ve smyčce while
5.3 Překlad stopy do sekvence meziinstrukcí
6. Překlad druhého demonstračního příkladu do strojového kódu procesorů x86_64
7. Překlad druhého demonstračního příkladu do strojového kódu procesoru ARM
8. Odkazy na zdrojové texty demonstračních příkladů i na JITované sekvence instrukcí
1. LuaJIT – Just in Time překladač pro programovací jazyk Lua (12 – překlad operací s reálnými čísly)
V demonstračním příkladu, jehož just-in-time překlad jsme si popsali v předchozí části tohoto seriálu, byla implementována programová smyčka typu while, v níž se provádělo prosté zvyšování počitadla smyčky o jedničku a současně i zvyšování další lokální proměnné (resp. přesněji řečeno proměnné lokální v aktuálně používaném modulu). Vzhledem k tomu, že počáteční hodnota obou proměnných byla nastavena na nulu a v každé iteraci došlo ke zvýšení jejich hodnoty o jedničku (celé číslo), mohl LuaJIT v tomto případě použít pouze celočíselné operace, což je ostatně patrné i při pohledu na vygenerovanou sekvenci meziinstrukcí:
---- 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 prefixu int uvedeného před všemi instrukcemi. Tento prefix znamená, že LuaJIT může (ale nemusí!) při vygenerování nativního kódu použít celočíselné operace. Ostatně již minule jsme mohli vidět, že zatímco na 32bitové platformě ARM se skutečně využívala pouze celočíselná aritmeticko-logická jednotka i celočíselné pracovní registry, na platformě x86_64 vybavené mj. i instrukčními sadami SSE a SSE2 se již pracovalo s registry XMM. Dnes si ukážeme formu just-in-time překladu u krátkých demonstračních programů, kde se již používají operace s reálnými čísly i na platformě ARM.
1.1 Tabulka se strojovými instrukcemi použitými při překladu do strojového kódu mikroprocesorů x86_64
V následující tabulce jsou pro úplnost vypsány všechny strojové instrukce mikroprocesorů s architekturou x86_64, s nimiž se setkáme v navazujících kapitolách. Zajímavé je, že LuaJIT si u překladu mnoha programů vystačí skutečně jen s relativně malou sadou instrukcí, takže zbylých několik set (!) instrukcí ze základní sady i z několika rozšiřujících sad (8087, 80387, MMX, SSEx…) zůstává většinou nevyužito:
# | Instrukce | Typ | Popis |
---|---|---|---|
1 | add | aritmetická operace | součet dvou skalárních hodnot |
2 | addsd | aritmetická operace | součet prvků vektorů bez saturace, operace provedena jen s pravým prvkem vektorů |
3 | mulsd | aritmetická operace | součin prvků vektorů, operace provedena jen s pravým prvkem vektorů |
4 | divsd | aritmetická operace | podíl prvků vektorů, operace provedena jen s pravým prvkem vektorů |
5 | cmp | porovnání | porovnání dvou skalárních hodnot, nastavení příznaků v EFLAGS |
6 | ucomisd | porovnání | porovnání dvou hodnot typu dobule, nastavení příznaků v EFLAGS |
7 | jmp | skok | nepodmíněný skok |
8 | ja | skok | podmíněný skok vykonaný při splnění: CF = 0 and ZF = 0 |
9 | jbe | skok | podmíněný skok vykonaný při splnění: CF = 1 or ZF = 1 (negace předchozího) |
10 | jg | skok | podmíněný skok vykonaný při splnění: ZF = 0 and SF = OF |
11 | jle | skok | podmíněný skok vykonaný při splnění: ZF = 1 or SF != OF (negace předchozího) |
12 | jnb | skok | podmíněný skok vykonaný při splnění: CF = 0 |
13 | mov | přenos dat | přenos skalárních hodnot |
14 | movsd | přenos dat | přenos vektorů |
15 | movaps | přenos dat | přenos (vektoru) hodnot typu single |
16 | cvtsd2si | konverze | konverze hodnot z typu double na int |
Tabulka je rozdělena do několika sekcí. V první sekci lze najít aritmetické instrukce prováděné s celými čísly i s vektory definovanými v SSE/SSE2. Instrukce končící postfixem „sd“ pracují s hodnotami typu double. Ve druhé sekci lze nalézt nepodmíněný skok i několik podmíněných skoků, v sekci následující pak instrukce pro přenos dat mezi pamětí, celočíselnými registry a registry XMM. Poslední instrukce slouží ke konverzi dat.
1.2 Tabulka se strojovými instrukcemi použitými při překladu do strojového kódu mikroprocesorů ARM
Podobnou tabulku si uveďme i pro instrukce využívané LuaJITem při překladu do strojového kódu 32bitových mikroprocesorů s architekturou ARM, přesněji řečeno těch mikroprocesorů, které mají ve svém jádře implementovaný VFPv2 (Vector Floating Point):
# | Instrukce | Typ | Popis |
---|---|---|---|
1 | add | aritmetická operace | r0:=r1+r2, ovšem bez nastavení příznaků |
2 | adds | aritmetická operace | r0:=r1+r2 a nastav příznaky N, V, Z, C |
3 | vadd.f64 | aritmetická operace | součet prvků vektorů uložených ve VFP registrech |
4 | vmul.f64 | aritmetická operace | součin prvků vektorů uložených ve VFP registrech |
5 | vdiv.f64 | aritmetická operace | podíl prvků vektorů uložených ve VFP registrech |
6 | cmp | porovnání | operand1-operand2 (compare a nastav příznaky N, V, Z, C) |
7 | cmn | porovnání | operand1+operand2 (compare negative a nastav příznaky N, V, Z, C) |
8 | orr | logická/bitová operace | r0:=r1+r2 |
9 | bl | skok | skok do subrutiny |
10 | ble | skok | podmíněný skok provedený při N!=V |
11 | blge | skok | podmíněný skok provedený při N=V |
12 | blgt | skok | podmíněný skok provedený při Z=0 and N=V |
13 | blhs | skok | podmíněný skok provedený při C=1 |
14 | blne | skok | podmíněný skok provedený při nerovnosti (Z=0) |
15 | blt | skok | podmíněný skok provedený při N!=V |
16 | blvs | skok | podmíněný skok provedený při přetečení (V=1) |
17 | ldr | přenos dat | načtení slova do registru |
18 | ldrd | přenos dat | načtení hodnoty do registru |
19 | mov | přenos dat | načtení druhého operandu do registru |
20 | vldr | přenos dat | načtení (jedné) hodnoty do vybraného VFP registru |
Opět můžeme vidět, že tabulka je rozdělena do několika sekcí. Nejprve jsou uvedeny dvě celočíselné aritmetické instrukce, dále pak tři instrukce prováděné s hodnotami uloženými ve VFP registrech. Další dvojici instrukcí již známe z minula – jedná se o porovnání dvou operandů (registrů) a nastavení příslušných příznaků N (negative), V (overflow), Z (zero) a C (carry) využívaných mj. i v podmíněných skocích vypsaných v páté sekci. V instrukcích sloužících pro přenos dat můžeme mj. vidět i instrukci vldr pro přenos do VFP registru.
Zajímavý je postfix u instrukcí vadd, vmul a vdiv. Ten určuje typ dat a současně i sadu registrů, s kterými daná instrukce pracuje:
Postfix | Typ dat (IEEE 754) | Registry (operandy) |
---|---|---|
f32 | single precision | Sd, Sn, Sm |
f64 | double precision | Dd, Dn, Dm |
2. První demonstrační příklad test54.lua – výpočet (konvergující) geometrické řady
V dnešním prvním demonstračním příkladu nazvaném test54.lua se provádí výpočet geometrické řady konvergující ke dvojce. Implementace je velmi jednoduchá, protože je použita počítaná programová smyčka typu for, v níž se v tisíci iteracích sčítají jednotlivé prvky řady, přičemž každý prvek má hodnotu 2-n. Vzhledem k tomu, že se ve výpočtu používá dělení 1/x, je zřejmé, že LuaJIT nemůže použít optimalizaci spočívající v přetypování proměnných na typ integer, ale veškeré výpočty musí být prováděny s hodnotami typu double (a to navíc ideálně takovým způsobem, aby geometrická řada na všech platformách skutečně konvergovala ke dvojce :-).
2.1 Zdrojový kód
Podívejme se nejdříve na zdrojový kód tohoto příkladu:
-- -- LuaJIT: demonstracni priklad cislo 54. -- -- Test JITu - prekladu do nativniho kodu. -- local i local geom = 0 local x = 1 for i = 1,1000 do geom = geom + 1/x x = x * 2 end print(geom) -- -- Finito. --
2.2 Detekovaná stopa hot-loop
Trasovací just-it-time překladač LuaJIT po několika desítkách iterací (konkrétně po padesáté šesté iteraci, jak jsme se již ostatně dozvěděli v předchozích částech tohoto seriálu) nalezne následující hot-loop reprezentovanou snadno pochopitelným bajtkódem:
---- TRACE 1 start test53.lua:13 0008 DIVNV 7 2 0 ; 1 0009 ADDVV 1 1 7 0010 MULVN 2 2 1 ; 2 0011 FORL 3 => 0008
První tři instrukce (s tříadresovým kódem) tvoří tělo počítané programové smyčky. U každé instrukce jsou uvedeny tři registry: jeden registr cílový a dva registry zdrojové. Výsledek operace DIVNV je přičten k registru číslo 1 ve druhé operaci ADDVN a následně je obsah registru číslo 2 zdvojnásoben (i když by zde teoreticky bylo možné použít pouhé přičtení).
2.3 Překlad stopy do sekvence meziinstrukcí
Bajtkód je následně přetransformován do následující sekvence meziinstrukcí, kde je ke každé operaci doplněn datový typ. Prefix num značí použití čísel reprezentovaných v systému plovoucí řádové čárky (tečky):
---- TRACE 1 IR 0001 int SLOAD #4 CI 0002 > num SLOAD #3 T 0003 num DIV +1 0002 0004 > num SLOAD #2 T 0005 + num ADD 0004 0003 0006 + num ADD 0002 0002 0007 + int ADD 0001 +1 0008 > int LE 0007 +1000 0009 ------ LOOP ------------ 0010 num DIV +1 0006 0011 + num ADD 0010 0005 0012 + num ADD 0006 0006 0013 + int ADD 0007 +1 0014 > int LE 0013 +1000 0015 int PHI 0007 0013 0016 num PHI 0006 0012 0017 num PHI 0005 0011
3. Překlad prvního demonstračního příkladu do strojového kódu procesorů x86_64
Nyní se podívejme, jakým způsobem provedl LuaJIT překlad výše uvedené programové smyčky do (nativního) strojového kódu mikroprocesorů s architekturou x86_64 vybavenými navíc doplňkovou instrukční sadou SSE a SSE2:
---- TRACE 1 mcode 118 0bceff89 mov dword [0x41f9e4a0], 0x1 0bceff94 movsd xmm0, [0x400d9090] 0bceff9d cvtsd2si ebp, [rdx+0x18] 0bceffa2 cmp dword [rdx+0x14], 0xfffeffff 0bceffa9 jnb 0x0bce0010 ->0 0bceffaf movsd xmm6, [rdx+0x10] 0bceffb4 movaps xmm7, xmm0 0bceffb7 divsd xmm7, xmm6 0bceffbb cmp dword [rdx+0xc], 0xfffeffff 0bceffc2 jnb 0x0bce0010 ->0 0bceffc8 addsd xmm7, [rdx+0x8] 0bceffcd addsd xmm6, xmm6 0bceffd1 add ebp, +0x01 0bceffd4 cmp ebp, 0x3e8 0bceffda jg 0x0bce0014 ->1 ->LOOP: 0bceffe0 movaps xmm5, xmm0 0bceffe3 divsd xmm5, xmm6 0bceffe7 addsd xmm7, xmm5 0bceffeb addsd xmm6, xmm6 0bceffef add ebp, +0x01 0bcefff2 cmp ebp, 0x3e8 0bcefff8 jle 0x0bceffe0 ->LOOP 0bcefffa jmp 0x0bce001c ->3 ---- TRACE 1 stop -> loop
Samotná programová smyčka je přeložena zajímavým způsobem – můžeme zde vidět, že prakticky všechny konstanty použité při výpočtu jsou uloženy v registrech XMMx (což je samozřejmě dobře) a taktéž použití celočíselného registru EBP ve funkci počitadla (konstanta 0×3e8 odpovídá dekadické hodnotě 1000 a tím pádem i maximálnímu počtu iterací). Zatímco vlastní výpočet je do jisté míry optimalizován – viz náhrada násobení za pouhý součet provedený v instrukci addsd xmm6, xmm6, tak řízení programové smyčky je přeloženo značně šablonovitým způsobem (zpětné počítání by bylo rychlejší, což ale platí pro sekvenci DEC+JNZ a nikoli pro LOOP).
4. Překlad prvního demonstračního příkladu do strojového kódu procesorů ARM
Zajímavé bude porovnat předchozí kód s kódem vytvořeným pro procesory s architekturou ARM:
---- TRACE 1 mcode 104 00397f98 mov r0, #-1342177280 00397f9c orr r0, r0, #114294784 00397fa0 orr r0, r0, #97280 00397fa4 vldr d0, [r0, #424] 00397fa8 ldr r11, [r9, #24] 00397fac ldr lr, [r9, #20] 00397fb0 vldr d1, [r9, #16] 00397fb4 cmn lr, #15 00397fb8 blhs 0x00390018 ->0 00397fbc vdiv.f64 d3, d0, d1 00397fc0 ldr lr, [r9, #12] 00397fc4 vldr d2, [r9, #8] 00397fc8 cmn lr, #15 00397fcc blhs 0x00390018 ->0 00397fd0 vadd.f64 d15, d2, d3 00397fd4 vadd.f64 d14, d1, d1 00397fd8 add r11, r11, #1 00397fdc cmp r11, #1000 00397fe0 blgt 0x0039001c ->1 ->LOOP: 00397fe4 vdiv.f64 d13, d0, d14 00397fe8 vadd.f64 d15, d13, d15 00397fec vadd.f64 d14, d14, d14 00397ff0 add r11, r11, #1 00397ff4 cmp r11, #1000 00397ff8 ble 0x00397fe4 ->LOOP 00397ffc bl 0x00390024 ->3 ---- TRACE 1 stop -> loop
Vlastní programová smyčka je implementována s využitím šesti instrukcí, tj. je zde o jednu instrukci méně než u konkurenčního x86_64, a to zejména díky pěkně navržené tříadresové instrukční sadě. Opět zde můžeme vidět optimalizaci v instrukci vadd.f64 d14, d14, d14, která nahrazuje pomalé násobení rychlejším součtem. Jako počitadlo smyčky je použit registr r11, jehož hodnota je postupně zvyšována o jedničku a testována proti konstantně 1000, což je opět dosti šablonovitý překlad, protože aritmetické instrukce s postfixem „s“ dokážou nastavovat příznakové bity automaticky (takže by zde bylo možné použít operaci pro odečítání).
5. Druhý demonstrační příklad test55.lua – složitější výpočty prováděné ve smyčce while
Ve druhém demonstračním příkladu nazvaném test55.lua je použita programová smyčka typu while, což mj. znamená, že základní struktura bude odpovídat demonstračnímu příkladu uvedenému minule. V těle smyčky se zvyšuje hodnota počitadla i a navíc se ještě provádí další dva výpočty – hodnota lokální proměnné x se ztrojnásobí a hodnota proměnné y násobí konstantou pět. LuaJIT zde nebude moci použít celočíselné operace, především kvůli tomu, že se bude pracovat (po 56 iteraci) s příliš velkými čísly.
5.1 Zdrojový kód
Opět si nejprve uveďme zdrojový kód tohoto příkladu:
-- -- LuaJIT: demonstracni priklad cislo 55. -- -- Test JITu - prekladu do nativniho kodu. -- local i = 0 local x = 1 local y = 1 while i < 100 do i = i + 1 x = x * 3 y = y * 5 end print(i) print(x) print(y) -- -- Finito. --
5.2 Detekovaná stopa hot-loop
Programová smyčka – hot-loop – detekovaná LuaJITem je zde poněkud delší a kupodivu i sekvence instrukcí v nalezené trase je „rozsekaná“:
---- TRACE 1 start test53.lua:13 0008 ADDVN 0 0 0 ; 1 0009 MULVN 1 1 1 ; 3 0010 MULVN 2 2 2 ; 5 0011 JMP 3 => 0004 0004 KSHORT 3 100 0005 ISGE 0 3 0006 JMP 3 => 0012 0007 LOOP 3 => 0012
5.3 Překlad stopy do sekvence meziinstrukcí
Pro úplnost se podívejme na mezikód, tj. na sekvenci meziinstrukcí vygenerovaných z výše vypsaného bajtkódu:
---- TRACE 1 IR 0001 > num SLOAD #1 T 0002 + num ADD 0001 +1 0003 > num SLOAD #2 T 0004 + num MUL 0003 +3 0005 > num SLOAD #3 T 0006 + num MUL 0005 +5 0007 > num LT 0002 +100 0008 ------ LOOP ------------ 0009 + num ADD 0002 +1 0010 + num MUL 0004 +3 0011 + num MUL 0006 +5 0012 > num LT 0009 +100 0013 num PHI 0002 0009 0014 num PHI 0004 0010 0015 num PHI 0006 0011
6. Překlad druhého demonstračního příkladu do strojového kódu procesorů x86_64
Překlad do nativního kódu mikroprocesorů x86_64 vypadá následovně:
---- TRACE 1 mcode 145 0bceff66 mov dword [0x406bc4a0], 0x1 0bceff71 movsd xmm3, [0x406c8bf0] 0bceff7a movsd xmm2, [0x406c8bf8] 0bceff83 movsd xmm1, [0x406c8c00] 0bceff8c movsd xmm0, [0x406c8c08] 0bceff95 cmp dword [rdx+0x4], 0xfffeffff 0bceff9c jnb 0x0bce0010 ->0 0bceffa2 movsd xmm5, [rdx] 0bceffa6 addsd xmm5, xmm3 0bceffaa cmp dword [rdx+0xc], 0xfffeffff 0bceffb1 jnb 0x0bce0010 ->0 0bceffb7 movsd xmm6, [rdx+0x8] 0bceffbc mulsd xmm6, xmm2 0bceffc0 cmp dword [rdx+0x14], 0xfffeffff 0bceffc7 jnb 0x0bce0010 ->0 0bceffcd movsd xmm7, [rdx+0x10] 0bceffd2 mulsd xmm7, xmm1 0bceffd6 ucomisd xmm0, xmm5 0bceffda jbe 0x0bce0014 ->1 ->LOOP: 0bceffe0 addsd xmm5, xmm3 0bceffe4 mulsd xmm6, xmm2 0bceffe8 mulsd xmm7, xmm1 0bceffec ucomisd xmm0, xmm5 0bcefff0 ja 0x0bceffe0 ->LOOP 0bcefff2 jmp 0x0bce001c ->3 ---- TRACE 1 stop -> loop
V těle smyčky nalezneme podle očekávání dvojici operací mulsd následovanou instrukcí ucomisd, která provede porovnání počitadla s konstantou uloženou v registru xmm0. To je docela zajímavé, protože v předchozím příkladu se podařilo počítanou smyčku for přeložit s využitím celočíselných operací – zde se skrývá jedna z předností této programové smyčky pro ty programátory, kteří se snaží o tvorbu co nejefektivnějšího kódu.
7. Překlad druhého demonstračního příkladu do strojového kódu procesoru ARM
Překlad do nativního kódu mikroprocesorů s architekturou ARM vypadá následovně:
---- TRACE 1 mcode 120 00397f88 mov r0, #-1275068416 00397f8c orr r0, r0, #47710208 00397f90 orr r0, r0, #23552 00397f94 vldr d1, [r0, #424] 00397f98 vldr d0, [r0, #432] 00397f9c ldrd r4, [r9] 00397fa0 cmn r5, #14 00397fa4 blne 0x00390018 ->0 00397fa8 adds r4, r4, #1 00397fac blvs 0x00390018 ->0 00397fb0 ldr lr, [r9, #12] 00397fb4 vldr d3, [r9, #8] 00397fb8 cmn lr, #15 00397fbc blhs 0x00390018 ->0 00397fc0 vmul.f64 d14, d3, d1 00397fc4 ldr lr, [r9, #20] 00397fc8 vldr d2, [r9, #16] 00397fcc cmn lr, #15 00397fd0 blhs 0x00390018 ->0 00397fd4 vmul.f64 d15, d2, d0 00397fd8 cmp r4, #100 00397fdc blge 0x0039001c ->1 ->LOOP: 00397fe0 mov r11, r4 00397fe4 adds r4, r11, #1 00397fe8 blvs 0x00390020 ->2 00397fec vmul.f64 d14, d14, d1 00397ff0 vmul.f64 d15, d15, d0 00397ff4 cmp r4, #100 00397ff8 blt 0x00397fe0 ->LOOP 00397ffc bl 0x00390024 ->3 ---- TRACE 1 stop -> loop
Zde je kupodivu programová smyčka implementována v sedmi instrukcích, což je ve skutečnosti zbytečné – stačí se podívat na to, jakým způsobem se manipuluje s registry r4 a r11. Výpočet je realizován dvojicí instrukcí vmul.f64, řízení programové smyčky zajišťuje čtveřice adds+blvs+cmp+blt (blvs by se nemuselo provádět, jedná se o kontrolu přetečení).
Překlad do nativního kódu provedený například s využitím gcc by v tomto případě vypadal odlišně, a to i v případě, že by se při překladu nepoužily optimalizační metody typu rozbalení smyček apod.
8. Odkazy na zdrojové texty demonstračních příkladů i na JITované sekvence instrukcí
Oba dnes použité demonstrační příklady byly, jak je tomu ostatně v tomto seriálu již dlouhodobějším zvykem, uloženy do Git (přesněji řečeno do GitHub) repositáře umístěného na adrese https://github.com/tisnik/luajit-examples.
Následuje tabulka obsahující odkazy na poslední verze obou dnešních příkladů i na výstup vygenerovaný LuaJITem:
# | Zdrojový kód | Umístění |
---|---|---|
1 | test54.lua | https://github.com/tisnik/luajit-examples/blob/master/src/test54.lua |
2 | test55.lua | https://github.com/tisnik/luajit-examples/blob/master/src/test55.lua |
3 | test54.ir | https://github.com/tisnik/luajit-examples/blob/master/ir/test54.ir |
4 | test55.ir | https://github.com/tisnik/luajit-examples/blob/master/ir/test55.ir |
5 | test54_arm.asm | https://github.com/tisnik/luajit-examples/blob/master/asm/test54_arm.asm |
6 | test54_x86.asm | https://github.com/tisnik/luajit-examples/blob/master/asm/test54_x86.asm |
7 | test55_arm.asm | https://github.com/tisnik/luajit-examples/blob/master/asm/test55_arm.asm |
8 | test55_x86.asm | https://github.com/tisnik/luajit-examples/blob/master/asm/test55_x86.asm |
9. Literatura
- Bolz, Cuni, Fijalkowski, Rigo:
„Tracing the Meta-Level: PyPy's Tracing JIT Compiler“ - Vasanth Bala, Evelyn Duesterwald, Sanjeev Banerjia:
„Dynamo: A Transparent Dynamic Optimization System“ - Bolz, Cuni, Fijalkowski, Leuschel, Pedroni, Rigo: „Allocation removal by partial evaluation in a tracing JIT“
- Bolz:
„Automatic JIT Compiler Generation with Runtime Partial Evaluation“ - 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. - Bolz and Rigo:
„How to not write a virtual machine“
In Proceedings of the 3rd Workshop on Dynamic Languages and Applications (DYLA), 2007 - Bruni, Verwaest:
„PyGirl: generating Whole-System VMs from High-Level prototypes using PyPy“
In Tools, accepted for publication, 2009. - 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.
10. Odkazy na Internetu
- Static single assignment form (SSA)
http://en.wikipedia.org/wiki/Static_single_assignment_form - LuaJIT 2.0 SSA IRhttp://wiki.luajit.org/SSA-IR-2.0
- Dynamic Assembler
http://luajit.org/dynasm.html - The Unofficial DynASM Documentation: Introduction
http://corsix.github.io/dynasm-doc/index.html - Have tracing JIT compilers won?
http://lambda-the-ultimate.org/node/3851 - Tracing just-in-time compilation
http://en.wikipedia.org/wiki/Tracing_just-in-time_compilation - How does LuaJIT's trace compiler work?
http://www.freelists.org/post/luajit/How-does-LuaJITs-trace-compiler-work,1 - How does LuaJIT's trace compiler work?
http://stackoverflow.com/questions/20266523/how-does-luajits-trace-compiler-work - TraceMonkey
https://wiki.mozilla.org/JavaScript:TraceMonkey - TraceMonkey
http://brendaneich.com/2008/08/tracemonkey-javascript-lightspeed/ - Improving JavaScript performance with JägerMonkey
http://hacks.mozilla.org/2010/03/improving-javascript-performance-with-jagermonkey/ - 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 - SSE (Streaming SIMD Extentions)
http://www.songho.ca/misc/sse/sse.html - Timothy A. Chagnon: SSE and SSE2
http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf - Intel corporation: Extending the World's Most Popular Processor Architecture
http://download.intel.com/technology/architecture/new-instructions-paper.pdf - SIMD architectures:
http://arstechnica.com/old/content/2000/03/simd.ars/ - Sixth Generation Processors
http://www.pcguide.com/ref/cpu/fam/g6.htm - Great Microprocessors of the Past and Present
http://www.cpushack.com/CPU/cpu1.html - The VFP architecture
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Bcfibfha.html - ARM Floating Point Accelerator (ARM FPA)
http://vswww.kaist.ac.kr/ver4.0/index.php/research/past-research/arm-fpa.html - The ARM Processor Architecture
http://www.arm.com/products/processors/technologies/instruction-set-architectures.php