Reiz es nolÄmu jautri pierÄdÄ«t procesa atgriezeniskumu un uzziniet, kÄ Ä£enerÄt JavaScript (precÄ«zÄk, Asm.js) no maŔīnas koda. Eksperimentam tika izvÄlÄts QEMU, un kÄdu laiku vÄlÄk tika uzrakstÄ«ts raksts par Habr. KomentÄros man tika ieteikts pÄrtaisÄ«t projektu WebAssembly un pat izstÄties pats gandriz beidzies Man kaut kÄ negribÄjÄs projektu... Darbs notika, bet ļoti lÄni, un tagad, nesen tajÄ rakstÄ parÄdÄ«jÄs komentÄrs par tÄmu "KÄ tas viss beidzÄs?" Atbildot uz manu detalizÄto atbildi, es dzirdÄju: "Tas izklausÄs pÄc raksta." Nu ja varÄsi, bÅ«s raksts. VarbÅ«t kÄdam noderÄs. No tÄ lasÄ«tÄjs uzzinÄs dažus faktus par QEMU koda Ä£enerÄÅ”anas aizmugursistÄmu dizainu, kÄ arÄ« par to, kÄ uzrakstÄ«t tÄ«mekļa lietojumprogrammai Just-in-Time kompilatoru.
uzdevumi
TÄ kÄ jau biju iemÄcÄ«jies QEMU ākaut kÄā portÄt uz JavaScript, tad Å”oreiz tika nolemts to darÄ«t gudri un neatkÄrtot vecÄs kļūdas.
Kļūda numur viens: atzarojums no punkta atbrīvoŔanas
Mana pirmÄ kļūda bija atdalÄ«t savu versiju no iepriekÅ”ÄjÄs versijas 2.4.1. Tad man likÄs laba ideja: ja pastÄv punkta izlaidums, tad tas droÅ”i vien ir stabilÄks par vienkÄrÅ”u 2.4 un vÄl jo vairÄk par zaru. master. Un, tÄ kÄ es plÄnoju pievienot diezgan daudz savu kļūdu, man vispÄr nebija vajadzÄ«gas neviena cita. TÄ tas laikam arÄ« sanÄca. Bet Å”eit ir lieta: QEMU nestÄv uz vietas, un kÄdÄ brÄ«dÄ« viÅi pat paziÅoja par Ä£enerÄtÄ koda optimizÄciju par 10 procentiem. "JÄ, tagad es iesaldÄÅ”os," es nodomÄju un sabojÄjos. Å eit mums ir jÄizdara atkÄpe: QEMU.js viena pavediena rakstura dÄļ un tÄpÄc, ka sÄkotnÄjais QEMU nenozÄ«mÄ vairÄku pavedienu neesamÄ«bu (tas ir, iespÄju vienlaikus darbinÄt vairÄkus nesaistÄ«tus koda ceļus, un ne tikai āizmantot visus kodolusā), tam ir bÅ«tiska nozÄ«me, galvenÄs pavedienu funkcijas man bija ājÄizslÄdzā, lai varÄtu izsaukt no Ärpuses. Tas apvienoÅ”anÄs laikÄ radÄ«ja dažas dabiskas problÄmas. TomÄr tas, ka dažas izmaiÅas no filiÄles master, ar kuriem es mÄÄ£inÄju sapludinÄt savu kodu, arÄ« tika izvÄlÄti punkta izlaidumÄ (un lÄ«dz ar to manÄ filiÄlÄ), arÄ«, iespÄjams, nebÅ«tu papildu ÄrtÄ«bas.
VispÄr es nolÄmu, ka tomÄr ir jÄga izmest prototipu, izjaukt to daļÄm un izveidot jaunu versiju no nulles, pamatojoties uz kaut ko svaigÄku un tagad no plkst. master.
OtrÄ kļūda: TLP metodoloÄ£ija
BÅ«tÄ«bÄ tÄ nav kļūda, kopumÄ tÄ ir tikai projekta izveides iezÄ«me pilnÄ«gas pÄrpratuma apstÄkļos gan par ākur un kÄ pÄrvietoties?ā, gan kopumÄ par āvai mÄs tur tiksim?ā Å ajos apstÄkļos neveikla programmÄÅ”ana bija pamatots variants, bet, protams, es negribÄju to bez vajadzÄ«bas atkÄrtot. Å oreiz gribÄju to darÄ«t gudri: atomu apÅemÅ”anÄs, apzinÄtas koda maiÅas (un nevis ānejauÅ”as rakstzÄ«mju virknÄÅ”ana lÄ«dz kompilÄcijai (ar brÄ«dinÄjumiem)ā, kÄ par kÄdu reiz teica Linuss Torvalds, saskaÅÄ ar Wikiquote) utt.
JoprojÄm neesmu pilnÄ«bÄ atbrÄ«vojies no Ŕī, bet tagad esmu nolÄmis vispÄr neiet mazÄkÄs pretestÄ«bas ceļu un darÄ«t to ākÄ pieauguÅ”aisā, proti, rakstÄ«t savu TCG backend no nulles, lai ne vÄlÄk jÄsaka: "JÄ, tas, protams, notiek lÄni, bet es nevaru visu kontrolÄt - tÄ ir rakstÄ«ts TCI..." TurklÄt sÄkotnÄji tas Ŕķita acÄ«mredzams risinÄjums, jo Es Ä£enerÄju binÄro kodu. KÄ viÅi saka: āGenta pulcÄjÄsŃ, bet ne tas viensā: kods, protams, ir binÄrs, taÄu vadÄ«bu uz to nevar vienkÄrÅ”i pÄrnest ā tas ir nepÄrprotami jÄiespiež pÄrlÅ«kprogrammÄ kompilÄÅ”anai, kÄ rezultÄtÄ tiek izveidots konkrÄts objekts no JS pasaules, kuram tomÄr ir nepiecieÅ”ams kaut kur izglÄbties. TomÄr parastajÄs RISC arhitektÅ«rÄs, cik es saprotu, tipiska situÄcija ir nepiecieÅ”amÄ«ba skaidri atiestatÄ«t instrukciju keÅ”atmiÅu reÄ£enerÄtajam kodam - ja tas nav tas, kas mums nepiecieÅ”ams, tad jebkurÄ gadÄ«jumÄ tas ir tuvu. TurklÄt no mana pÄdÄjÄ mÄÄ£inÄjuma es uzzinÄju, ka vadÄ«ba, Ŕķiet, netiek pÄrnesta uz tulkoÅ”anas bloka vidu, tÄpÄc mums nav Ä«sti nepiecieÅ”ams baitkods, kas interpretÄts no jebkÄdas nobÄ«des, un mÄs varam to vienkÄrÅ”i Ä£enerÄt no TB funkcijas. .
ViÅi nÄca un spÄrda
Lai gan es sÄku pÄrrakstÄ«t kodu jau jÅ«lijÄ, nemanot uznÄca maÄ£isks sitiens: parasti vÄstules no GitHub pienÄk kÄ paziÅojumi par atbildÄm uz problÄmÄm un izvilkÅ”anas pieprasÄ«jumiem, taÄu Å”eit pÄkÅ”Åi pieminÄt pavedienÄ Binaryen kÄ qemu aizmugure kontekstÄ: "ViÅÅ” kaut ko tÄdu izdarÄ«ja, varbÅ«t viÅÅ” kaut ko pateiks." MÄs runÄjÄm par Emscripten saistÄ«tÄs bibliotÄkas izmantoÅ”anu Binaryen lai izveidotu WASM JIT. Nu, es teicu, ka jums tur ir Apache 2.0 licence, un QEMU kopumÄ tiek izplatÄ«ts saskaÅÄ ar GPLv2, un tie nav Ä«paÅ”i saderÄ«gi. PÄkÅ”Åi izrÄdÄ«jÄs, ka licence var bÅ«t kaut kÄ salabot (Es nezinu: varbÅ«t mainÄ«t to, varbÅ«t dubulto licencÄÅ”anu, varbÅ«t kaut ko citu...). Tas, protams, mani iepriecinÄja, jo lÄ«dz tam laikam jau biju kÄrtÄ«gi apskatÄ«jusies binÄrais formÄts WebAssembly, un man bija kaut kÄ skumji un nesaprotami. Bija arÄ« bibliotÄka, kas aprija pamata blokus ar pÄrejas grafiku, izveidoja baitkodu un vajadzÄ«bas gadÄ«jumÄ pat palaist to paÅ”Ä tulkÄ.
Tad bija vairÄk vÄstule QEMU adresÄtu sarakstÄ, bet tas vairÄk attiecas uz jautÄjumu: "Kam tas vispÄr ir vajadzÄ«gs?" Un tÄ ir pÄkÅ”Åi, izrÄdÄ«jÄs, ka tas bija nepiecieÅ”ams. Ja tas darbojas vairÄk vai mazÄk Ätri, varat saskrÄpÄt vismaz Å”Ädas izmantoÅ”anas iespÄjas:
uzsÄkt kaut ko izglÄ«tojoÅ”u bez instalÄcijas
virtualizÄcija operÄtÄjsistÄmÄ iOS, kur saskaÅÄ ar baumÄm vienÄ«gÄ lietojumprogramma, kurai ir tiesÄ«bas Ä£enerÄt kodu lidojumÄ, ir JS dzinÄjs (vai tÄ ir taisnÄ«ba?)
mini-OS demonstrÄcija - viena diskete, iebÅ«vÄta, visa veida programmaparatÅ«ra utt.
PÄrlÅ«ka izpildlaika funkcijas
KÄ jau teicu, QEMU ir saistÄ«ts ar daudzpavedienu, bet pÄrlÅ«kprogrammai tÄ nav. Nu, tas ir, nÄ... SÄkumÄ tas vispÄr neeksistÄja, tad parÄdÄ«jÄs WebWorkers - cik es saprotu, tas ir vairÄku pavedienu veidoÅ”ana, pamatojoties uz ziÅojumu nodoÅ”anu bez koplietotiem mainÄ«gajiem. Protams, tas rada bÅ«tiskas problÄmas, pÄrnesot esoÅ”o kodu, pamatojoties uz koplietojamÄs atmiÅas modeli. Tad pÄc sabiedrÄ«bas spiediena tas tika Ä«stenots ar nosaukumu SharedArrayBuffers. Tas tika pamazÄm ieviests, viÅi svinÄja tÄ palaiÅ”anu dažÄdÄs pÄrlÅ«kprogrammÄs, tad viÅi svinÄja Jauno gadu, un tad Meltdown... PÄc tam viÅi nonÄca pie secinÄjuma, ka laika mÄrÄ«Å”ana ir rupja vai rupja, bet ar kopÄ«gÄs atmiÅas palÄ«dzÄ«bu un pavediens palielinot skaitÄ«tÄju, tas viss ir vienÄds tas izdosies diezgan precÄ«zi. TÄpÄc mÄs atspÄjojÄm daudzpavedienu savienojumu ar koplietojamo atmiÅu. Å Ä·iet, ka viÅi vÄlÄk to atkal ieslÄdza, taÄu, kÄ kļuva skaidrs pirmajÄ eksperimentÄ, ir dzÄ«ve bez tÄ, un, ja tÄ, tad mÄÄ£inÄsim to izdarÄ«t, nepaļaujoties uz daudzpavedienu izmantoÅ”anu.
Otra iezÄ«me ir zema lÄ«meÅa manipulÄciju neiespÄjamÄ«ba ar steku: jÅ«s nevarat vienkÄrÅ”i paÅemt, saglabÄt paÅ”reizÄjo kontekstu un pÄrslÄgties uz jaunu ar jaunu steku. Zvanu steku pÄrvalda JS virtuÄlÄ maŔīna. Å Ä·iet, kÄda ir problÄma, jo mÄs tomÄr nolÄmÄm bijuÅ”Äs plÅ«smas pÄrvaldÄ«t pilnÄ«bÄ manuÄli? Fakts ir tÄds, ka QEMU bloka I/O tiek ieviests, izmantojot korutÄ«nas, un Å”eit noderÄtu zema lÄ«meÅa steka manipulÄcijas. Par laimi Emscipten jau satur asinhrono darbÄ«bu mehÄnismu, pat divus: AsinhronizÄt Šø Emprester. Pirmais darbojas ar ievÄrojamu Ä£enerÄtÄ JavaScript koda uzpÅ«Å”anos un vairs netiek atbalstÄ«ts. Otrais ir paÅ”reizÄjais "pareizais veids", un tas darbojas, izmantojot baitkoda Ä£enerÄÅ”anu vietÄjam tulkam. Tas, protams, darbojas lÄni, taÄu tas nepalielina kodu. Tiesa, Ŕī mehÄnisma korutÄ«nu atbalsts bija jÄsniedz neatkarÄ«gi (bija jau Asyncify rakstÄ«tas korutÄ«nas, un Emterpreter bija ieviesta aptuveni tÄda pati API, tikai vajadzÄja tÄs savienot).
Å obrÄ«d vÄl nav izdevies sadalÄ«t kodu vienÄ kompilÄtÄ WASM un interpretÄt, izmantojot Emterpreter, tÄpÄc blokierÄ«ces pagaidÄm nestrÄdÄ (skat. nÄkamajÄ sÄrijÄ, kÄ saka...). Tas ir, galu galÄ jums vajadzÄtu iegÅ«t kaut ko lÄ«dzÄ«gu Å”ai smieklÄ«gajai slÄÅainajai lietai:
interpretÄtais bloks I/O. Nu, vai tieÅ”Äm gaidÄ«jÄt emulÄtu NVMe ar vietÄjo veiktspÄju? š
statiski kompilÄts galvenais QEMU kods (tulkotÄjs, citas emulÄtas ierÄ«ces utt.)
dinamiski kompilÄts viesu kods WASM
QEMU avotu iezīmes
KÄ jÅ«s droÅ”i vien jau uzminÄjÄt, viesu arhitektÅ«ru emulÄÅ”anas kods un resursdatora instrukciju Ä£enerÄÅ”anas kods ir atdalÄ«ti QEMU. PatiesÄ«bÄ tas ir pat nedaudz sarežģītÄk:
ir viesu arhitektūras
tur ir paÄtrinÄtÄji, proti, KVM aparatÅ«ras virtualizÄcijai operÄtÄjsistÄmÄ Linux (viesa un resursdatora sistÄmÄm, kas ir saderÄ«gas savÄ starpÄ), TCG JIT koda Ä£enerÄÅ”anai jebkur. SÄkot ar QEMU 2.9, parÄdÄ«jÄs atbalsts HAXM aparatÅ«ras virtualizÄcijas standartam operÄtÄjsistÄmÄ Windows (detaļas)
ja tiek izmantota TCG, nevis aparatÅ«ras virtualizÄcija, tad tai ir atseviŔķs koda Ä£enerÄÅ”anas atbalsts katrai saimniekdatora arhitektÅ«rai, kÄ arÄ« universÄlajam tulkam
... un ap to visu - emulÄtas perifÄrijas ierÄ«ces, lietotÄja interfeiss, migrÄcija, ierakstu atkÄrtoÅ”ana utt.
Starp citu, vai zinÄjÄt: QEMU var emulÄt ne tikai visu datoru, bet arÄ« procesoru atseviŔķam lietotÄja procesam resursdatora kodolÄ, ko izmanto, piemÄram, AFL fuzzer binÄrajai instrumentÄcijai. VarbÅ«t kÄds vÄlÄtos portÄt Å”o QEMU darbÄ«bas režīmu uz JS? š
TÄpat kÄ lielÄkÄ daļa ilgstoÅ”Äs bezmaksas programmatÅ«ras, QEMU tiek veidota, izmantojot zvanu configure Šø make. PieÅemsim, ka nolemjat kaut ko pievienot: TCG aizmugursistÄmu, pavedienu ievieÅ”anu vai kaut ko citu. Nesteidzieties priecÄties/Å”ausminÄties (vajadzÄ«go pasvÄ«trot) par iespÄju sazinÄties ar Autoconf ā patiesÄ«bÄ, configure QEMU's acÄ«mredzot ir paÅ”rakstÄ«ts un nav Ä£enerÄts no nekÄ.
WebAssembly
TÄtad, kas ir Ŕī lieta, ko sauc par WebAssembly (aka WASM)? Å is ir Asm.js aizstÄjÄjs, kas vairs neuzdodas par derÄ«gu JavaScript kodu. Gluži pretÄji, tas ir tÄ«ri binÄrs un optimizÄts, un pat vienkÄrÅ”i vesela skaitļa ierakstÄ«Å”ana tajÄ nav ļoti vienkÄrÅ”a: kompaktuma labad tas tiek saglabÄts formÄtÄ LEB128.
IespÄjams, esat dzirdÄjuÅ”i par Asm.js atkÄrtotas cilpas algoritmu ā Ŕī ir āaugsta lÄ«meÅaā plÅ«smas vadÄ«bas instrukciju (tas ir, ja-tad-else, cilpu utt.) atjaunoÅ”ana, kam ir paredzÄti JS dzinÄji, no plkst. zema lÄ«meÅa LLVM IR, tuvÄk procesora izpildÄ«tajam maŔīnas kodam. Protams, QEMU starpposma attÄlojums ir tuvÄks otrajam. VarÄtu Ŕķist, ka te ir, baitkods, moku beigas... Un tad ir bloki, ja-tad-citÄdi un cilpas!..
Un tas ir vÄl viens iemesls, kÄpÄc Binaryen ir noderÄ«gs: tas dabiski var pieÅemt augsta lÄ«meÅa blokus, kas ir tuvu tam, kas tiktu saglabÄts WASM. Bet tas var arÄ« izveidot kodu no pamata bloku un pÄreju diagrammas starp tiem. Nu, es jau teicu, ka tas slÄpj WebAssembly krÄtuves formÄtu aiz ÄrtÄs C/C++ API.
TCG (tiny Code Generator)
TCG sÄkotnÄji bija aizmugure C kompilatoram. Tad acÄ«mredzot tas neizturÄja konkurenci ar GCC, taÄu galu galÄ atrada savu vietu QEMU kÄ resursdatora platformas koda Ä£enerÄÅ”anas mehÄnisms. Ir arÄ« TCG aizmugure, kas Ä£enerÄ kÄdu abstraktu baitkodu, kuru nekavÄjoties izpilda tulks, bet es nolÄmu Å”oreiz izvairÄ«ties no tÄ izmantoÅ”anas. TaÄu tas, ka QEMU jau ir iespÄjams caur funkciju iespÄjot pÄreju uz Ä£enerÄto TB tcg_qemu_tb_exec, man tas izrÄdÄ«jÄs ļoti noderÄ«gi.
Lai QEMU pievienotu jaunu TCG aizmugursistÄmu, ir jÄizveido apakÅ”direktorijs tcg/<ŠøŠ¼Ń Š°ŃŃ ŠøŃŠµŠŗŃŃŃŃ> (Å”ajÄ gadÄ«jumÄ, tcg/binaryen), un tajÄ ir divi faili: tcg-target.h Šø tcg-target.inc.c Šø izrakstÄ«t tas viss ir par configure. Tur var ievietot citus failus, taÄu, kÄ jau nojauÅ”at pÄc Å”o divu nosaukumiem, tie abi tiks kaut kur iekļauti: viens kÄ parasts galvenes fails (tas ir iekļauts tcg/tcg.h, un tas jau atrodas citos direktoriju failos tcg, accel un ne tikai), otrs - tikai kÄ koda fragments iekÅ”Ä tcg/tcg.c, taÄu tai ir piekļuve savÄm statiskajÄm funkcijÄm.
NolÄmis, ka es tÄrÄÅ”u pÄrÄk daudz laika, lai detalizÄti izpÄtÄ«tu, kÄ tas darbojas, es vienkÄrÅ”i nokopÄju Å”o divu failu āskeletusā no citas aizmugursistÄmas ievieÅ”anas, godÄ«gi norÄdot to licences galvenÄ.
fails tcg-target.h satur galvenokÄrt iestatÄ«jumus formÄ #define-s:
cik reÄ£istru un kÄds platums ir mÄrÄ·a arhitektÅ«rÄ (mums ir tik daudz, cik mÄs gribam, cik mÄs vÄlamies - jautÄjums ir vairÄk par to, ko pÄrlÅ«kprogramma Ä£enerÄs efektÄ«vÄkÄ kodÄ "pilnÄ«gi mÄrÄ·a" arhitektÅ«rÄ ...)
resursdatora instrukciju saskaÅoÅ”ana: uz x86 un pat TCI instrukcijas vispÄr netiek lÄ«dzinÄtas, bet es koda buferÄ« likÅ”u nemaz nevis instrukcijas, bet norÄdes uz Binaryen bibliotÄkas struktÅ«rÄm, tÄpÄc teikÅ”u: 4 baiti
kÄdus izvÄles norÄdÄ«jumus var Ä£enerÄt aizmugure - mÄs iekļaujam visu, ko atrodam Binaryen, ļaujam paÄtrinÄtÄjam paÅ”am sadalÄ«t pÄrÄjos vienkÄrÅ”Äkos
KÄds ir aptuvenais aizmugursistÄmas pieprasÄ«tÄs TLB keÅ”atmiÅas lielums. Fakts ir tÄds, ka QEMU viss ir nopietni: lai gan ir palÄ«gfunkcijas, kas veic ielÄdi/uzglabÄÅ”anu, Åemot vÄrÄ viesu MMU (kur mÄs tagad bÅ«tu bez tÄ?), tÄs saglabÄ savu tulkoÅ”anas keÅ”atmiÅu struktÅ«ras veidÄ, kuru apstrÄdi ir Ärti iegult tieÅ”i apraides blokos. JautÄjums ir, kÄdu nobÄ«di Å”ajÄ struktÅ«rÄ visefektÄ«vÄk apstrÄdÄ neliela un Ätra komandu secÄ«ba?
Å”eit varat pielÄgot viena vai divu rezervÄto reÄ£istru mÄrÄ·i, iespÄjot TB izsaukÅ”anu, izmantojot funkciju, un pÄc izvÄles aprakstÄ«t dažus mazus inline-funkcijas kÄ flush_icache_range (bet tas nav mÅ«su gadÄ«jums)
fails tcg-target.inc.c, protams, parasti ir daudz lielÄka izmÄra un satur vairÄkas obligÄtas funkcijas:
inicializÄcija, tostarp ierobežojumi attiecÄ«bÄ uz to, kuras instrukcijas var darboties ar kuriem operandiem. Es klaji nokopÄju no cita aizmugure
funkcija, kas aizÅem vienu iekÅ”Äjo baitkoda instrukciju
Å eit varat ievietot arÄ« palÄ«gfunkcijas, kÄ arÄ« varat izmantot statiskÄs funkcijas no tcg/tcg.c
Sev izvÄlÄjos Å”Ädu stratÄÄ£iju: nÄkamÄ tulkoÅ”anas bloka pirmajos vÄrdos pierakstÄ«ju Äetras norÄdes: sÄkuma atzÄ«me (noteikta vÄrtÄ«ba tuvumÄ 0xFFFFFFFF, kas noteica paÅ”reizÄjo TB stÄvokli), kontekstu, Ä£enerÄto moduli un maÄ£isko numuru atkļūdoÅ”anai. SÄkumÄ tika ievietota atzÄ«me 0xFFFFFFFF - nKur n - neliels pozitÄ«vs skaitlis, un katru reizi, kad tas tika izpildÄ«ts caur tulku, tas palielinÄjÄs par 1. Kad tas sasniedza 0xFFFFFFFE, notika kompilÄcija, modulis tika saglabÄts funkciju tabulÄ, importÄts mazÄ āpalaidÄjÄā, kurÄ nonÄca izpilde no tcg_qemu_tb_exec, un modulis tika izÅemts no QEMU atmiÅas.
PÄrfrÄzÄjot klasiku, āKruÄ·, cik daudz Å”ajÄ skanÄjumÄ savijas progera sirdij...ā. TomÄr atmiÅa kaut kur noplÅ«da. TurklÄt tÄ bija QEMU pÄrvaldÄ«tÄ atmiÅa! Man bija kods, kas, rakstot nÄkamo instrukciju (nu, tas ir, rÄdÄ«tÄju), izdzÄsa to, kura saite bija Å”ajÄ vietÄ agrÄk, bet tas nepalÄ«dzÄja. Faktiski vienkÄrÅ”ÄkajÄ gadÄ«jumÄ QEMU startÄÅ”anas laikÄ pieŔķir atmiÅu un ieraksta tur Ä£enerÄto kodu. Kad buferis beidzas, kods tiek izmests un tÄ vietÄ sÄk rakstÄ«t nÄkamo.
PÄc koda izpÄtes es sapratu, ka triks ar maÄ£isko numuru ļÄva man nepiedzÄ«vot kaudzÄ«tes iznÄ«cinÄÅ”anu, pirmajÄ piegÄjienÄ atbrÄ«vojot kaut ko nepareizu neinicializÄtÄ buferÄ«. Bet kurÅ” pÄrraksta buferi, lai vÄlÄk apietu manu funkciju? KÄ iesaka Emscripten izstrÄdÄtÄji, kad man radÄs problÄma, es pÄrnesu iegÅ«to kodu atpakaļ uz vietÄjo lietojumprogrammu, iestatÄ«ju tajÄ Mozilla Record-Replay... KopumÄ beigÄs es sapratu vienkÄrÅ”u lietu: katram blokam, a struct TranslationBlock ar tÄ aprakstu. Uzminiet, kur... TieÅ”i tÄ, tieÅ”i pirms bloka tieÅ”i buferÄ«. To saprotot, es nolÄmu beigt lietot kruÄ·us (vismaz dažus) un vienkÄrÅ”i izmetu burvju skaitli un pÄrsÅ«tÄ«ju atlikuÅ”os vÄrdus uz struct TranslationBlock, izveidojot atseviŔķi saistÄ«tu sarakstu, kuru var Ätri pÄrvietot, kad tulkoÅ”anas keÅ”atmiÅa ir atiestatÄ«ta, un atbrÄ«vot atmiÅu.
Daži kruÄ·i paliek: piemÄram, iezÄ«mÄtas norÄdes koda buferÄ« - daži no tiem ir vienkÄrÅ”i BinaryenExpressionRef, tas ir, viÅi skatÄs uz izteiksmÄm, kuras lineÄri jÄieliek Ä£enerÄtajÄ pamatblokÄ, daļa ir nosacÄ«jums pÄrejai starp BB, daļa ir kur iet. Nu jau ir sagatavoti bloki Relooper, kas jÄsavieno atbilstoÅ”i nosacÄ«jumiem. Lai tos atŔķirtu, tiek izmantots pieÅÄmums, ka tie visi ir izlÄ«dzinÄti par vismaz Äetriem baitiem, tÄpÄc etiÄ·etei varat droÅ”i izmantot vismazÄkos divus bitus, tikai jÄatceras to noÅemt, ja nepiecieÅ”ams. Starp citu, Å”Ädas etiÄ·etes jau tiek izmantotas QEMU, lai norÄdÄ«tu iemeslu izieÅ”anai no TCG cilpas.
Izmantojot Binaryen
WebAssembly moduļos ir funkcijas, no kurÄm katra satur pamattekstu, kas ir izteiksme. Izteiksmes ir unÄras un binÄras darbÄ«bas, bloki, kas sastÄv no citu izteiksmju sarakstiem, vadÄ«bas plÅ«smas utt. KÄ jau teicu, vadÄ«bas plÅ«sma Å”eit tiek organizÄta precÄ«zi kÄ augsta lÄ«meÅa filiÄles, cilpas, funkciju izsaukumi utt. Funkciju argumenti netiek nodoti stekÄ, bet tieÅ”i, tÄpat kÄ JS. Ir arÄ« globÄlie mainÄ«gie, bet es tos neesmu izmantojis, tÄpÄc par tiem nestÄstÄ«Å”u.
FunkcijÄm ir arÄ« lokÄlie mainÄ«gie, kas numurÄti no nulles, tipa int32 / int64 / float / double. Å ajÄ gadÄ«jumÄ pirmie n vietÄjie mainÄ«gie ir funkcijai nodotie argumenti. LÅ«dzu, Åemiet vÄrÄ, ka, lai gan vadÄ«bas plÅ«smas ziÅÄ viss Å”eit nav pilnÄ«gi zems, veseliem skaitļiem joprojÄm nav atribÅ«ta āparakstÄ«ts/neparakstÄ«tsā: skaitļa darbÄ«ba ir atkarÄ«ga no darbÄ«bas koda.
VispÄrÄ«gi runÄjot, Binaryen nodroÅ”ina vienkÄrÅ”s C-API: jÅ«s izveidojat moduli, viÅÄ izveidot izteiksmes - unÄras, binÄras, blokus no citÄm izteiksmÄm, kontroles plÅ«smu utt. PÄc tam jÅ«s izveidojat funkciju ar izteiksmi kÄ tÄs pamattekstu. Ja jums, tÄpat kÄ man, ir zema lÄ«meÅa pÄrejas grafiks, relooper komponents jums palÄ«dzÄs. Cik es saprotu, blokÄ ir iespÄjams izmantot augsta lÄ«meÅa izpildes plÅ«smas vadÄ«bu, ja vien tas nepÄrsniedz bloka robežas - tas ir, ir iespÄjams padarÄ«t iekÅ”Äjo Ätro ceļu / lÄnu ceļŔ, kas sazarojas iebÅ«vÄtajÄ TLB keÅ”atmiÅas apstrÄdes kodÄ, bet netraucÄ āÄrÄjaiā vadÄ«bas plÅ«smai. AtbrÄ«vojot relooper, tiek atbrÄ«voti tÄ bloki; atbrÄ«vojot moduli, pazÅ«d tam pieŔķirtÄs izteiksmes, funkcijas utt. arÄna.
TomÄr, ja vÄlaties interpretÄt kodu lidojumÄ bez nevajadzÄ«gas tulka instances izveides un dzÄÅ”anas, var bÅ«t lietderÄ«gi Å”o loÄ£iku ievietot C++ failÄ un no turienes tieÅ”i pÄrvaldÄ«t visu bibliotÄkas C++ API, apejot gatavu izgatavoti iesaiÅojumi.
Lai kaut kÄ savienotu QEMU un JS pasaules un tajÄ paÅ”Ä laikÄ Ätri piekļūtu sastÄdÄ«tajÄm funkcijÄm, tika izveidots masÄ«vs (funkciju tabula importÄÅ”anai palaiÅ”anas programmÄ), un tajÄ tika ievietotas Ä£enerÄtÄs funkcijas. Lai Ätri aprÄÄ·inÄtu indeksu, sÄkotnÄji tika izmantots nulles vÄrda tulkoÅ”anas bloka indekss, bet pÄc tam indekss, kas aprÄÄ·inÄts, izmantojot Å”o formulu, sÄka vienkÄrÅ”i iekļauties laukÄ struct TranslationBlock.
Starp citu, demo(Å”obrÄ«d ar neskaidru licenci) labi darbojas tikai Firefox. Chrome izstrÄdÄtÄji bija kaut kÄ nav gatavs uz to, ka kÄds vÄlÄtos izveidot vairÄk nekÄ tÅ«kstoÅ” WebAssembly moduļu gadÄ«jumu, tÄpÄc viÅi vienkÄrÅ”i katram atvÄlÄja gigabaitu virtuÄlÄs adreÅ”u telpas...
Tas pagaidÄm ir viss. VarbÅ«t bÅ«s vÄl kÄds raksts, ja kÄdu interesÄ. Proti, paliek vismaz tikai lai bloku ierÄ«ces darbotos. VarÄtu bÅ«t arÄ« lietderÄ«gi WebAssembly moduļu kompilÄciju padarÄ«t asinhronu, kÄ tas ir ierasts JS pasaulÄ, jo joprojÄm ir tulks, kas to visu var paveikt, lÄ«dz vietÄjais modulis ir gatavs.
Beidzot mÄ«kla: esat sastÄdÄ«jis binÄro failu 32 bitu arhitektÅ«rÄ, bet kods, izmantojot atmiÅas darbÄ«bas, paceļas no Binaryen, kaut kur stekÄ vai kaut kur citur 2 bitu adreÅ”u telpas augÅ”Äjos 32 GB. ProblÄma ir tÄda, ka no Binaryen viedokļa tas piekļūst pÄrÄk lielai iegÅ«tajai adresei. KÄ to apiet?
Administratora veidÄ
Es nebeidzu to pÄrbaudÄ«t, bet mana pirmÄ doma bija: "Ko darÄ«t, ja es instalÄtu 32 bitu Linux?" Tad adreÅ”u telpas augÅ”Äjo daļu aizÅems kodols. JautÄjums tikai, cik bÅ«s aizÅemts: 1 vai 2 Gb.
ProgrammÄtÄja veidÄ (opcija praktiÄ·iem)
IzpÅ«tÄ«sim burbuli adreses telpas augÅ”daļÄ. Es pats nesaprotu, kÄpÄc tas darbojas - tur jau ir jÄbÅ«t kaudzei. Bet "mÄs esam praktiÄ·i: mums viss darbojas, bet neviens nezina, kÄpÄc..."