Qemu.js oo leh taageerada JIT: waxaad weli dib u celin kartaa shiidka

Dhowr sano ka hor Fabrice Bellard waxaa qoray jslinux waa emulator PC oo ku qoran JavaScript. Intaa ka dib waxaa jiray ugu yaraan wax ka badan Virtual x86. Laakiin dhammaantood, inta aan ogahay, waxay ahaayeen turjubaano, halka Qemu, oo uu hore u qoray isla Fabrice Bellard, iyo, malaha, ku dayashada casriga ah ee is-ixtiraamta, ayaa u adeegsanaysa ururinta JIT ee koodka martida galay koodka nidaamka martida loo yahay. Waxay iila muuqatay in la gaadhay waqtigii la hirgalin lahaa hawsha ka soo horjeeda ee la xidhiidha midda daalacayaashu xalliyaan: JIT ururinta koodhka mashiinka JavaScript, kaas oo ay ugu muuqatay mid macquul ah dekedda Qemu. Waxay u ekaan kartaa, sababta Qemu, waxaa jira emulators ka fudud oo isticmaale-saaxiibtinimo - VirtualBox la mid ah, tusaale ahaan - rakibay oo shaqeeya. Laakin Qemu waxa ay leedahay dhowr astaamood oo xiisa leh

  • il furan
  • karti shaqo la'aan darawal kernel ah
  • kartida shaqo ee qaabka turjubaanka
  • taageero tiro badan oo ka mid ah dhismayaasha martida iyo martida labadaba

Marka la eego qodobka saddexaad, waxaan hadda sharxi karaa in xaqiiqda, qaabka TCI, ma aha mashiinka martida ee laftigooda in la fasiro, laakiin bytecode iyaga laga helay, laakiin tani ma beddeleyso nuxurka - si loo dhiso oo loo ordo. Qemu oo ku saabsan qaab-dhismeedka cusub, haddii aad nasiib leedahay, A C compiler ayaa kugu filan - qorista kombuyuutar kood dib ayaa loo dhigi karaa.

Oo hadda, ka dib laba sano oo nasasho leh oo aan si firaaqo ah ula macaamilay koodhka isha Qemu wakhtigayga firaaqada ah, waxaa soo baxay prototype shaqo, kaas oo aad horeba ugu socon karto, tusaale ahaan, Kolibri OS.

Waa maxay Emscripten

Beryahan dambe waxaa soo baxay isku-dubaridyaal badan, kuwaas oo natiijadoodu tahay JavaScript. Qaar, sida Nooca Qoraalka, waxaa markii hore loogu talagalay inay noqdaan habka ugu wanaagsan ee wax loogu qoro shabakadda. Isla mar ahaantaana, Emscripten waa hab lagu qaato koodhka C ama C++ ee jira oo lagu ururiyo foom browser-la akhriyi karo. Daar boggan Waxaan soo ururinay dekedo badan oo barnaamijyo caan ah: halkanTusaale ahaan, waxaad eegi kartaa PyPy - jidka, waxay sheeganayaan inay hore u leeyihiin JIT. Dhab ahaantii, ma aha barnaamij kasta si fudud loo ururin karaa oo ku shaqeeya browser - waxaa jira tiro Astaamaha, taas oo ay tahay inaad u dulqaadato, si kastaba ha ahaatee, sida ku qoran isla bogga ayaa leh "Emscripten waxaa loo isticmaali karaa in lagu ururiyo ku dhowaad kasta qaadi karo C/C++ code to JavaScript". Taasi waa, waxaa jira tiro hawlgallo ah oo aan la qeexin sida waafaqsan heerka caadiga ah, laakiin inta badan ka shaqeeya x86 - tusaale ahaan, helitaan la'aanta ah ee doorsoomayaasha, taas oo guud ahaan ka mamnuuc ah dhismayaasha qaarkood. Guud ahaan. , Qemu waa barnaamij iskutallaab ah oo , waxaan rabay inaan rumaysto, oo aysan horey ugu jirin dabeecado badan oo aan la qeexin - qaado oo isku diyaari, ka dibna wax yar ku dheji JIT - oo aad dhammaysay! Laakiin taasi maaha kiis...

Marka hore isku day

Guud ahaan, ma ihi qofkii ugu horreeyay ee la yimaada fikradda u wareejinta Qemu ee JavaScript. Waxaa jirtay su'aal lagu weydiiyay golaha ReactOS haddii tani ay suurtagal tahay iyadoo la adeegsanayo Emscripten. Xitaa hore, waxaa jiray warar xan ah oo sheegaya in Fabrice Bellard uu tan shakhsi ahaan u sameeyay, laakiin waxaan ka hadalnay jslinux, taas oo, inta aan ogahay, kaliya isku day ah in gacanta lagu gaaro waxqabadka ku filan ee JS, oo laga qoray xoqan. Ka dib, Virtual x86 ayaa la qoray - ilo aan qarsoodi ahayn ayaa loo dhajiyay, iyo, sida la sheegay, "xaqiiqda" weyn ee ku dayashada ayaa suurtogalisay in SeaBIOS loo isticmaalo qalab ahaan. Intaa waxaa dheer, waxaa jiray ugu yaraan hal isku day oo lagu dekedo Qemu iyadoo la adeegsanayo Emscripten - waxaan isku dayay inaan tan sameeyo socketpair, laakiin horumarka, inta aan fahmay, waa la qaboojiyey.

Markaa, waxay u ekaan kartaa, waa kuwan ilaha, halkan waa Emscripten - qaado oo ururi. Waxa kale oo jira maktabado ay Qemu ku tiirsan yihiin, iyo maktabado ay maktabadahaasi ku tiirsan yihiin, iwm, waxaana ka mid ah maktabadahaas. libffi, taas oo glib ku xiran tahay. Waxaa jiray xanta internetka in ay jirto mid ka mid ah ururinta ballaaran ee dekedaha maktabadaha ee Emscripten, laakiin si uun bay u adkeyd in la rumaysto: marka hore, looguma talagalin inay noqoto mid cusub, marka labaad, waxay ahayd heer aad u hooseeya maktabadda si aad u soo qaadato, oo aad u ururiso JS. Ma aha oo kaliya arrin ku saabsan xirmooyinka golaha - malaha, haddii aad maroojiso, qaar ka mid ah heshiisyada wacitaanka waxaad abuuri kartaa doodaha lagama maarmaanka ah ee xirmooyinka oo wac shaqada la'aantood. Laakiin Emscripten waa shay dhib badan: si koodhka la soo saaray uu u ekaado mid la yaqaan browserka JS engine optimizer, tabaha qaar ayaa la isticmaalaa. Gaar ahaan, waxa loogu yeero dib-u-celinta - koronto-dhaliye isticmaalaya LLVM IR ee la helay oo leh qaar ka mid ah tilmaamaha kala-guurka ee aan la taaban karin ayaa isku dayaya inuu dib u abuuro ifs, wareegyo, iwm. Hagaag, sidee doodaha loogu gudbiyaa shaqada? Dabcan, sida doodaha hawlaha JS, taas oo ah, haddii ay suurtagal tahay, maaha iyada oo loo marayo xirmooyinka.

Bilowgii waxaa jirtay fikrad ah in si fudud loogu qoro beddelka libffi JS oo aan sameeyo imtixaannada caadiga ah, laakiin ugu dambeyntii waxaan ku wareeray sida loo sameeyo faylalka madaxayga si ay ula shaqeeyaan koodhka jira - maxaan samayn karaa, sida ay yiraahdaan, "Hawshu miyay aad u adag yihiin" Ma sidaas ayaanu nacas u nahay?" Waxaan ku qasbanaa inaan libffi u soo dejiyo qaab dhismeedka kale, si aan u hadlo - nasiib wanaag, Emscripten wuxuu leeyahay labadaba macros ee shirarka khadka ah (Javascript, haa - si fiican, wax kasta oo qaab dhismeedka, sidaas darteed ururiyaha), iyo awoodda uu u leeyahay inuu ku socodsiiyo koodka duullimaadka. Guud ahaan, ka dib markii aan ku dhajiyay jajabyada libffi-ku-tiirsan ee in muddo ah, waxaan helay kood la ururin karo oo ku orday imtixaankii ugu horreeyay ee aan la kulmo. Waxaa yaab igu noqotay, imtixaankii waa lagu guuleystay. La yaabay caqligeyga - kaftan la'aan, waxay ka shaqeysay bilawgii ugu horreeyay - Anigu, weli ma rumaysan indhahayga, waxaan aaday si aan u eego koodka natiijada mar kale, si aan u qiimeeyo meesha xigta ee lagu qodo. Halkan waxaan galay nuts markii labaad - waxa kaliya ee shaqadayda qabtay waxay ahayd ffi_call - Tani waxay sheegtay wacitaanka guulaysta. Ma jirin wax la isku wacay. Markaa waxaan diray codsigeyga jiidashada koowaad, kaas oo saxay qaladkii imtixaanka oo u cad arday kasta oo Olympiad ah - lambarada dhabta ah waa in aan la barbar dhigin sida a == b iyo xataa sida a - b < EPS - sidoo kale waxaad u baahan tahay inaad xasuusato moduleka, haddii kale 0 waxay u noqon doontaa mid aad u siman oo la mid ah 1/3 la soo ururiyey - Waxaan go'aansaday inay lagama maarmaan noqoto, waxaan ku dari doonaa mar dambe. Markaan horay u sii eegayo, waxaan dhihi doonaa, sida ay soo baxday, iskudubariduhu xitaa kuma darin shaqada libffi ee koodka kama dambaysta ah.

Laakiin, sidaan horeba u idhi, waxaa jira xaddidaadyo, iyo isticmaalka bilaashka ah ee dabeecadaha kala duwan ee aan la qeexin, muuqaal aad u xun ayaa la qariyay - JavaScript by design ma taageerto multithreading leh xusuusta la wadaago. Mabda 'ahaan, tan badanaa xitaa waxaa loogu yeeri karaa fikrad wanaagsan, laakiin maaha code-ka-dejinta kaas oo qaab-dhismeedkiisu ku xiran yahay dunta C. Guud ahaan, Firefox waxa ay tijaabinaysaa taageeridda shaqaalaha la wadaago, Emscripten-na waxa ay u leedahay dhaqan-gelin phread ah, laakiin ma aanan rabin in aan ku tiirsanaado. Waxa ay ahayd in aan si tartiib ah u xidido isku xidhka badan ee Qemu code - taas oo ah, in aan ogaado halka ay duntu ka socoto, u dhaqaaq jidhka siddo ee ku dhex socda duntan shaqo gooni ah, oo aan mid mid uga wacaa hawlahan loop weyn.

Isku day labaad

Mar waxa caddaatay in dhibaatadu weli taagan tahay, oo si hagar la’aan ah koodhka loogu dhufto biraha aanay wax wanaag ah soo kordhinayn. Gabagabo: waxaan u baahanahay in aan si uun u habaynno habka wax lagu daro ulaha. Sidaa darteed, version 2.4.1, kaas oo ahaa mid cusub wakhtigaas, ayaa la qaaday (ma aha 2.5.0, sababtoo ah, yaa og, waxaa jiri doona cayayaanka nooca cusub ee aan weli la qaban, oo aan haysto ku filan cayayaankayga. ), oo waxa ugu horreeya waxay ahayd in dib loo qoro si badbaado leh thread-posix.c. Waa hagaag, taasi waa, sida badbaado leh: haddii qof isku dayo inuu sameeyo qalliin horseedaya xannibaadda, shaqada ayaa isla markiiba loo yeedhay abort() - Dabcan, tani ma xallin dhibaatooyinka oo dhan hal mar, laakiin ugu yaraan waxay ahayd mid aad uga farxad badan marka loo eego si aamusnaan ah oo loo helo xog aan is waafaqsanayn.

Guud ahaan, doorashooyinka Emscripten ayaa aad waxtar ugu leh soo-dejinta koodka JS -s ASSERTIONS=1 -s SAFE_HEAP=1 - waxay qabtaan qaar ka mid ah dabeecadaha aan la qeexin, sida wicitaanada ciwaanka aan toosnayn (kaas oo aan haba yaraatee waafaqsanayn koodka qormooyinka teebaysan sida HEAP32[addr >> 2] = 1) ama wac hawl leh tiro doodood oo khaldan.

Jid ahaan, khaladaadka toosinta waa arin gooni ah. Sidaan horeyba u idhi, Qemu waxay leedahay dib-u-eegis tafsiir ah oo β€œxumaaday” oo loogu talagalay jiilka koodka TCI (turjumaan kood yar), iyo in lagu dhiso oo lagu maamulo Qemu qaab dhismeed cusub, haddii aad nasiib leedahay, iskudubarid C ayaa ku filan. "haddii aad nasiib leedahay". Nasiib darro, oo waxaa ii soo baxday in TCI ay isticmaasho marin aan toos ahayn marka la kala saarayo bytecode. Taasi waa, dhammaan noocyada kala duwan ee ARM iyo naqshadaha kale ee leh helitaanka daruuriga ah, Qemu waxay soo ururisaa sababtoo ah waxay leeyihiin dhabarka caadiga ah ee TCG kaas oo soo saara koodka asalka ah, laakiin haddii TCI ay ku shaqeyn doonto iyaga waa su'aal kale. Si kastaba ha noqotee, sida ay soo baxday, dukumeentiyada TCI waxay si cad u muujiyeen wax la mid ah. Natiijo ahaan, baaqyo shaqo oo akhrin aan toos ahayn ayaa lagu daray koodka, kaas oo laga helay qayb kale oo Qemu ah.

Taallo burbur

Natiijo ahaan, gelitaanka TCI ee aan toosnayn ayaa la saxay, loop weyn ayaa la sameeyay kaas oo isna loo yaqaan processor-ka, RCU iyo waxyaabo kale oo yaryar. Oo sidaas daraaddeed waxaan bilaabay Qemu ikhtiyaarka -d exec,in_asm,out_asm, taas oo macnaheedu yahay inaad u baahan tahay inaad sheegto blocks-ka code ee la fulinayo, iyo sidoo kale wakhtiga baahinta si aad u qorto code-ka martida, waxa code martigeliyaha noqday (kiiskan, bytecode). Wuu bilaabmaa, fuliya dhawr baloog oo turjumaad ah, wuxuu qorayaa fariinta khaladka ah ee aan uga tagay in RCU hadda bilaaban doonto oo... abort() gudaha shaqo free(). Adigoo ku tinkeker shaqada free() Waxa aanu ku guulaysanay in aanu ogaano in madaxa dhismaha taallo, kaas oo ku yaalla siddeedda bayt ee ka horreeya xusuusta loo qoondeeyay, halkii ay ka ahaan lahayd xajmiga baloogga ama wax la mid ah, uu ku jiro qashin.

Burburinta tuubada - sida quruxda badan ... Xaaladdan oo kale, waxaa jira daawo faa'iido leh - laga bilaabo (haddii ay suurtagal tahay) ilo isku mid ah, soo ururi binary asal ah oo ku hoos mari Valgrind. Muddo ka dib, binary-ga ayaa diyaar ahaa. Waxaan ku bilaabay isla doorashooyin isku mid ah - way burburtaa xitaa inta lagu jiro bilawga, ka hor intaanay dhab ahaantii gaarin fulinta. Waa wax aan fiicneyn, dabcan - sida muuqata, ilo-wareedyadu isku mid ma ahayn, taas oo aan la yaab lahayn, sababtoo ah qaabeynta ayaa soo saartay doorashooyin kala duwan, laakiin waxaan haystaa Valgrind - marka hore waxaan hagaajin doonaa cayayaankan, ka dibna, haddii aan nasiib leeyahay , kan asalka ah ayaa soo bixi doona. Waxaan ku socdaa wax la mid ah Valgrind hoostiisa ... Y-y-y, y-y-y, uh-uh, way bilaabatay, waxay u martay bilawga si caadi ah waxayna u gudubtay bug asalka ah iyada oo aan hal digniin ah oo ku saabsan gelitaanka xusuusta qaldan, aan la sheegin wax ku saabsan dhicis. Noloshu, sida ay yiraahdaan, iimay diyaarin tan - barnaamij burburay ayaa joogsada shilka markii lagu bilaabay Walgrind. Waxa ay ahayd qarsoodi. Mala-awaalkeygu waa in hal mar agagaarka tilmaamaha hadda jira ka dib shil intii lagu jiray bilowga, gdb wuxuu muujiyay shaqo memset-a leh tilmaame sax ah oo isticmaalaya midkood mmx, ama xmm diiwangelinta, ka dibna laga yaabaa inay ahayd nooc ka mid ah qalad toosinta, in kasta oo ay weli adag tahay in la rumaysto.

Hagaag, Valgrind uma eka inuu halkan ku caawinayo. Oo halkan waxa bilaabmay waxa ugu karaahiyo badan - wax walba waxay u muuqdaan inay xitaa bilaabaan, laakiin waxay ku burburaan sababo aan la garanayn sababtoo ah dhacdo dhici karta malaayiin tilmaamo ka hor. Muddo dheer, xitaa ma cadda sida loo wajaho. Dhammaadkii, wali waa in aan fadhiistaa oo aan saxo. Daabacaadda waxa madaxa dib loogu qoray waxa ay muujisay in aanu u ekayn lambar, balse uu u ekaado nooc ka mid ah xogta binary. Oo, bal eeg, xadhigan binary-ga ah waxaa laga helay faylka BIOS - taas oo ah, hadda waxaa suurtagal ah in la yiraahdo kalsooni macquul ah in ay ahayd bakhaar xad-dhaaf ah, xitaa way caddahay in loo qoray baqshaddan. Hagaag, ka dibna wax sidan oo kale ah - Emscripten, nasiib wanaag, ma jiro randomization booska cinwaanka, ma jiraan wax godad ah sidoo kale, si aad u qori karto meel dhexda koodhka si aad xogta uga soo saarto tilmaame ka soo bilawgii ugu dambeeyay, Eeg xogta, eeg tilmaameha, oo, haddii aanay isbeddelin, hel cunto aad ku fikirto. Run, waxay qaadataa dhowr daqiiqo in la isku xidho isbeddel kasta ka dib, laakiin maxaad samayn kartaa? Natiijo ahaan, khad gaar ah ayaa la helay kaas oo ka soo guuriyay BIOS-ka ku-meel-gaadhka ah ee ku-meel-gaadhka ah ee xusuusta martida - iyo, runtii, ma jirin meel ku filan kaydinta. Helitaanka isha ciwaanka qariibka ah waxa ay keentay shaqo qemu_anon_ram_alloc faylka ku jira oslib-posix.c - caqli-galku wuxuu ahaa tan: mararka qaarkood waxay noqon kartaa mid faa'iido leh in la waafajiyo cinwaanka bog weyn oo 2 MB ah, tan waxaan ku weydiin doonaa mmap marka hore in yar oo dheeraad ah, ka dibna waxaan ku soo celin doonaa dheeraadka ah iyadoo la kaashanayo munmap. Oo haddii lays sida aan loo baahnayn, markaas waxaan ku tilmaami doonaa natiijada halkii 2 MB getpagesize() - mmap wali waxay bixin doontaa ciwaan toosan... Markaa Emscripten mmap kaliya wac malloc, laakiin dabcan kuma toosna bogga. Guud ahaan, bug iga niyad jabiyay dhowr bilood ayaa lagu saxay isbeddelka Dwux khadadka.

Tilmaamaha hawlaha wacitaanka

Haddana Processor-ku wax buu tirinayaa, Qemu ma shido, laakiin shaashaddu ma daarato, Processor-ku si degdeg ah ayuu u gelayaa wareegyada, iyadoo la eegayo natiijada ka soo baxday. -d exec,in_asm,out_asm. Mala-awaal ayaa soo baxday: Saacadaha gooya (ama, guud ahaan, dhammaan carqaladaha) ma yimaadaan. Oo runtii, haddii aad ka furto carqaladaynta ka timid golaha deegaanka, taas oo sabab uun u shaqeysay, waxaad heleysaa sawir la mid ah. Laakiin tani ma ahayn jawaabta gabi ahaanba: isbarbardhigga raadadka la soo saaray ee xulashada kore waxay muujisay in dhabbihii fulinta ay kala duwanaayeen goor hore. Halkan waa in la dhahaa isbarbardhigga waxa la duubay iyadoo la adeegsanayo soo-saareha emrun wax-soo-saarka wax-soo-saarka ee leh wax-soo-saarka golaha waddaniga ah ma aha hab-socodka farsamada oo dhammaystiran. Ma garanayo sida saxda ah ee barnaamijka ku shaqeeya browser-ka uu ugu xidhmo emrun, laakiin qaar ka mid ah xadhkaha wax-soo-saarka ayaa isu beddela in dib loo habeeyo, markaa farqiga u dhexeeya kala-duwanaanta weli maaha sabab loo qaato in hababku kala duwan yihiin. Guud ahaan, waxaa caddaatay in sida ku cad tilmaamaha ljmpl Waxaa jira u gudub cinwaanno kala duwan, iyo bytecode soo saaray asal ahaan waa ka duwan yahay: mid ka mid ah waxaa ku jira tilmaamo loogu yeero shaqada caawiye, ka kalena ma. Ka dib markii la googooyay tilmaamaha oo aan darsay koodka tarjuma tilmaamahan, waxaa caddaatay in, marka hore, isla markiiba ka hor diiwaanka. cr0 duubis ayaa la sameeyay - sidoo kale iyadoo la adeegsanayo caawiyaha - kaas oo u beddelay processor-ka qaab la ilaaliyo, iyo marka labaad, in nooca js uusan waligiis u wareegin qaab la ilaaliyo. Laakiin xaqiiqadu waxay tahay in sifada kale ee Emscripten ay tahay diidmadeeda u dulqaadashada koodka sida fulinta tilmaamaha. call gudaha TCI, kaas oo tilmaame kasta oo hawleed uu keeno nooca long long f(int arg0, .. int arg9) - Hawlaha waa in lagu magacaabaa tirada saxda ah ee doodaha. Haddii sharcigan la jebiyo, iyadoo ku xiran goobaha cilladaha, barnaamijku wuu burburi doonaa (taas oo wanaagsan) ama wici doona shaqada khaldan gabi ahaanba (taas oo noqon doonta murugo si loo saxo). Waxa kale oo jira ikhtiyaarka saddexaad - awood u yeelashada jiilka duubista ee ku dara / ka saara doodaha, laakiin guud ahaan duubayaashani waxay qaataan meelo badan, inkastoo xaqiiqda ah in aan kaliya u baahanahay wax yar oo ka badan boqol duub. Tani kaliya waa mid aad u murugo leh, laakiin waxaa soo baxday in ay noqoto dhibaato aad u daran: in code-ka la soo saaray ee hawlaha duubista, doodaha ayaa la beddelay oo la beddelay, laakiin mararka qaarkood shaqada doodaha la soo saaray lama magacaabin - si fiican, sida in hirgelinta libffi. Taasi waa, caawiyayaasha qaar si fudud looma dilin.

Nasiib wanaag, Qemu waxa ay haysaa liisaska caawinta ee mashiinka-akhrisan karo oo ah qaabka faylka madaxa sida

DEF_HELPER_0(lock, void)
DEF_HELPER_0(unlock, void)
DEF_HELPER_3(write_eflags, void, env, tl, i32)

Waxaa loo adeegsadaa si aad u qosol badan: marka hore, macros ayaa dib loo qeexay sida ugu yaabka badan DEF_HELPER_n, ka dibna shid helper.h. Ilaa xad in makro lagu balaadhiyo qaab-dhismeedka bilowga ah iyo comma, ka dibna array ayaa la qeexay, iyo halkii curiyeyaasha - #include <helper.h> Natiijo ahaan, waxaan ugu dambeyntii fursad u helay inaan tijaabiyo maktabadda shaqada pyparsing, waxaana la qoray qoraal ka soo saaraya sida saxda ah duubabka loogu talagalay shaqooyinka loo baahan yahay.

Oo sidaas daraaddeed, in ka dib processor-ku wuxuu u muuqday inuu shaqeeyo. Waxay u muuqataa inay tahay sababtoo ah shaashadda weligeed lama bilaabin, in kasta oo memtest86+ uu awooday inuu ku shaqeeyo golaha deegaanka. Halkan waxaa lagama maarmaan ah in lagu caddeeyo in Qemu block I/O code uu ku qoran yahay coroutines. Emscripten waxay leedahay hirgalinteeda aad u qalafsan, laakiin wali waxay u baahneyd in lagu taageero koodka Qemu, oo waxaad hadda ka saari kartaa processor-ka: Qemu waxay taageertaa xulashooyinka -kernel, -initrd, -append, kaas oo aad ku dhejin karto Linux ama, tusaale ahaan, memtest86+, adigoon isticmaalin qalabka xannibaadda gabi ahaanba. Laakiin waa kan dhibaatadu: golaha deegaanka mid ka mid ah ayaa arki kara wax soo saarka kernel Linux ee console oo leh ikhtiyaar -nographic, oo aan wax soo saar ah ka soo bixin browser-ka oo u socda terminalka meesha laga soo saaray emrun, ma iman. Taasi waa, ma cadda: processor-ku ma shaqeynayo ama wax soo saarka garaafyada ma shaqeynayo. Dabadeed waxa igu soo dhacday in aan wax yar sugo. Waxay soo baxday in "processor-yarehu aanu hurdo lahayn, balse si tartiib ah u libiqsanayaa," qiyaastii shan daqiiqo ka dib kernelku wuxuu ku tuuray farriimaha faraha badan ee konsole-ka oo uu sii waday inuu soo laadlaadsado. Waxaa caddaatay in processor-ku, guud ahaan, uu shaqeeyo, waxaanan u baahanahay inaan qodno koodhka la shaqaynta SDL2. Nasiib darro, ma garanayo sida loo isticmaalo maktabaddan, sidaa darteed meelaha qaar waxa aan ku khasbanaaday in aan u dhaqmo si aan kala sooc lahayn. Halkaa marka ay marayso, xariiqda parallel0 ayaa ka soo ifbaxday shaashadda oo ku taal midab buluug ah, kaas oo soo jeediyay fikrado. Ugu dambeyntii, waxaa soo baxday in dhibaatadu ay ahayd in Qemu uu furay dhowr daaqadood oo muuqaal ah hal daaqad oo muuqaal ah, kaas oo u dhexeeya oo aad ku beddeli karto adigoo isticmaalaya Ctrl-Alt-n: waxay ka shaqeysaa dhismaha asalka ah, laakiin kuma jiro Emscripten. Ka dib markii laga takhaluso daaqadaha aan loo baahnayn iyadoo la adeegsanayo ikhtiyaarrada -monitor none -parallel none -serial none iyo tilmaamo si xoog leh loogu sawiro dhammaan shaashadaha ku yaal jir kasta, wax walba si lama filaan ah ayey u shaqeeyeen.

Corotines

Marka, ku dayashada browserka ayaa shaqeysa, laakiin ma wadi kartid wax xiiso leh oo hal-floppy ah, sababtoo ah ma jiro xannibaad I / O - waxaad u baahan tahay inaad hirgeliso taageerada coroutines. Qemu waxay horey u leedahay dhowr geesood oo coroutine ah, laakiin dabeecadda JavaScript iyo koodhka Emscripten awgeed, kaliya ma bilaabi kartid xirmooyinka juggling. Waxay u egtahay in "wax walba ay tageen, malaasta waa la saarayaa," laakiin horumarinta Emscripten ayaa mar hore wax walba daryeelay. Kani waa mid aad u qosol badan: aynu u yeedhno wicitaan hawleed sidan oo kale ah mid shaki leh emscripten_sleep iyo kuwo kale oo badan oo isticmaalaya habka Asyncify, iyo sidoo kale wicitaanada tilmaamayaasha iyo wicitaanada shaqo kasta halkaas oo mid ka mid ah labadii kiis ee hore laga yaabo inuu hoos u dhaco. Hadda, ka hor wicitaan kasta oo shaki leh, waxaanu dooran doonaa macnaha async, isla markiiba ka dib wicitaanka, waxaanu hubin doonaa in wicitaan asynchronous ah uu dhacay, iyo haddii uu leeyahay, waxaan badbaadin doonaa dhammaan doorsoomayaasha maxaliga ah ee macnaha guud ee async, tilmaamaya shaqada si aan u wareejino xakamaynta marka aan u baahanahay inaan sii wadno fulinta, oo aan ka baxno shaqada hadda jirta. Tani waa meesha ay ka jirto baaxadda daraasadda saamaynta wax ku dhufasho - baahida sii socota fulinta code ka dib markii laga soo laabtay call asynchronous, compiler-ku wuxuu soo saaraa "stubs" ee shaqada bilaabaya ka dib wicitaanka shakiga - sida tan: haddii ay jiraan wicitaano shaki leh, ka dibna shaqada waxaa lagu ballaarin doonaa meel n / 2 waqti - tani wali waa, haddii aysan maskaxda ku hay in ka dib wicitaan kasta oo suurtagal ah, waxaad u baahan tahay inaad ku darto badbaadinta doorsoomayaal maxalli ah shaqada asalka ah. Ka dib, xitaa waa inaan ku qoraa qoraal fudud Python, kaas oo, ku salaysan qaybo la bixiyay oo ah hawlo si gaar ah loo isticmaalo oo loo malaynayo "uma oggola in asynchrony ay dhex maraan" (taas oo ah, dhiirigelinta xirmooyinka iyo wax kasta oo aan hadda ku tilmaamay ma aha. ka dhex shaqeeyo iyaga), waxa uu tilmaamayaa wicitaano loo marayo tilmaamo ay tahay in hawlaha ay tahay in uu iska indho tiro isku-dubariduhu si aan hawlahan loogu tixgalin asynchronous. Kadibna faylasha JS ee ka hooseeya 60 MB ayaa si cad u badan - aynu nidhaahno ugu yaraan 30. Inkasta oo, mar aan dejinayay qoraalka golaha, oo aan si qalad ah u tuuray ikhtiyaarrada isku xidhka, kuwaas oo ay ka mid ahaayeen -O3. Waxaan wadaa koodka la sameeyay, Chromium-na waxa uu cunaa xusuusta oo wuu burburaa. Ka dib waxaan si lama filaan ah u eegay waxa uu isku dayayo inuu soo dejiyo...Hagaag, maxaan odhan karaa, sidoo kale waan barafoobayn lahaa haddii la i waydiin lahaa inaan si feker leh u barto oo aan u wanaajiyo 500+ MB Javascript.

Nasiib darro, jeegaggii ku jiray code-ka maktabadda taageerada Asyncify gabi ahaanba saaxiib lama ahayn longjmp-s kuwaas oo loo isticmaalo koodhka processor-ka dalwaddii, laakiin ka dib balastar yar oo joojiya jeegagaas oo si xoog leh u soo celiya xaaladaha sida haddii wax walba ay fiicnaayeen, koodka ayaa shaqeeyay. Kadibna wax la yaab leh ayaa bilaabmay: mararka qaarkood hubinta koodhka isku xidhka ayaa kiciyay - isla kuwii burburay koodka haddii, sida ku cad macquulnimada fulinta, waa in la xannibaa - qof ayaa isku dayay inuu qabsado mutex hore loo qabtay. Nasiib wanaag, tani waxay u soo baxday inaysan ahayn dhibaato macquul ah oo ku jirta koodka taxanaha ah - waxaan si fudud u isticmaalayay habka caadiga ah ee loop-ka ee ay bixiso Emscripten, laakiin mararka qaarkood wicitaanka asynchronous wuxuu si buuxda u furfuri doonaa xirmada, isla markaana markaas wuu guuldareysan doonaa. setTimeout laga bilaabo wareegga ugu muhiimsan - sidaas darteed, koodka wuxuu galay soo-celinta wareegga ugu weyn isaga oo aan ka tagin dib-u-eegistii hore. Dib ugu qor wareeg aan xad lahayn iyo emscripten_sleep, iyo dhibaatooyinkii mutex-yada ayaa joogsaday. Koodhku xitaa wuxuu noqday mid macquul ah - ka dib oo dhan, dhab ahaantii, ma haysto kood u diyaariya qaabka animation-ka ee soo socda - processor-ku kaliya wax ayuu xisaabiyaa oo shaashadda si joogto ah ayaa loo cusbooneysiiyaa. Si kastaba ha ahaatee, dhibaatooyinku halkaas kuma joogsan: mararka qaarkood fulinta Qemu ayaa si fudud u joogsata aamusnaan iyada oo aan wax laga reebo ama khaladaad ahayn. Waqtigaas waan ka quustay, laakiin, horay u sii eegaya, waxaan dhihi doonaa dhibaatadu waxay ahayd tan: code coroutine, dhab ahaantii, ma isticmaalo setTimeout (ama ugu yaraan maaha sida ugu badan ee aad u malaynayso): shaqeyn emscripten_yield si fudud u dejinaya calanka call asynchronous. Ujeeddadu waa taas emscripten_coroutine_next ma aha hawl asynchronous ah: gudaha waxay hubisaa calanka, dib u dejisaa oo u wareejisaa xakamaynta meesha looga baahan yahay. Taasi waa, kor u qaadida raasamaalku halkaas ayuu ku dhamaanayaa. Dhibaatadu waxay ahayd in ay sabab u tahay isticmaalka-ka dib-free, kaas oo u muuqday markii barkada coroutine la naafo sababtoo ah xaqiiqda ah in aanan koobi ka dhigin khad muhiim ah oo kood ah oo ka socda dhabarka coroutine ee jira, shaqada qemu_in_coroutine soo noqday run markii ay xaqiiqadu ahayd inay been ku soo noqoto. Tani waxay keentay in la waco emscripten_yield, taas oo kor ku xusan aysan jirin cid saarnayd emscripten_coroutine_next, raasamaalku wuxuu u kala baxay xagga sare, laakiin maya setTimeout, sidaan horeba u sheegay, lama soo bandhigin.

Jiilka code JavaScript

Oo halkan, dhab ahaantii, waa ballanqaadkii "soo celinta hilibka duqadda ah." Runtii maaha. Dabcan, haddii aan ku soconno Qemu browserka, iyo Node.js ee ku jira, ka dibna, dabiici ahaan, ka dib markii code code ee Qemu waxaan heli doonaa gebi ahaanba khaldan JavaScript. Laakiin weli, nooc ka mid ah isbeddelka beddelka ah.

Marka hore, wax yar oo ku saabsan sida Qemu u shaqeeyo. Fadlan isla markiiba i cafi: Anigu ma ihi horumariye Qemu ah, gabagabadayduna waxa laga yaabaa inay khalad tahay meelaha qaarkood. Sida ay yiraahdaan, "fikirka ardaygu maaha inuu ku beegmo ra'yiga macalinka, Peano's axiomatics iyo caqli-galnimada." Qemu waxay leedahay tiro cayiman oo dhismooyin martida ah oo la taageeray mid walbana wuxuu leeyahay hage la mid ah target-i386. Markaad dhiseyso, waxaad qeexi kartaa taageerada dhowr dhismeyaal martida ah, laakiin natiijadu waxay noqon doontaa dhowr binary. Koodhka lagu taageerayo qaab dhismeedka martida, isna, wuxuu abuuraa qaar ka mid ah hawlgallada Qemu ee gudaha, kaas oo TCG (Qodobka Yaryar ee Koodhka) mar hore u beddelaya koodka mashiinka dhismaha martida loo yahay. Sida lagu sheegay feylka akhrinta ee ku yaal tusaha tcg, tani waxay asal ahaan ka ahayd qayb ka mid ah ururiyaha C ee caadiga ah, kaas oo markii dambe loo habeeyey JIT. Sidaa darteed, tusaale ahaan, qaab-dhismeedka bartilmaameedka marka loo eego dukumeentigan hadda ma aha naqshad-dhismeed martida, laakiin qaab-dhismeedka martida loo yahay. Marmarka qaarkood, qayb kale ayaa soo baxday - Turjubaanka Koodhka Tiny (TCI), kaas oo fulin doona koodka (ku dhawaad ​​​​ isla hawlgal gudaha ah) iyada oo maqnaanshaha kombuyuutarka koodhka ee naqshadaha martida gaarka ah. Dhab ahaantii, sida dukumeentiyadeedu sheegayo, turjumaankan waxaa laga yaabaa inuusan had iyo jeer u shaqeyn sidoo kale koronto-dhaliye JIT, ma aha oo kaliya tiro ahaan marka loo eego xawaaraha, laakiin sidoo kale si tayo leh. Inkasta oo aanan hubin in sifooyinkiisu ay si buuxda u khuseeyaan.

Markii hore waxaan isku dayay inaan sameeyo dhabarka dambe ee TCG oo dhamaystiran, laakiin si dhakhso ah ayaan ugu wareeray koodhka isha iyo sharaxaad aan si buuxda u caddayn tilmaamaha bytecode, sidaa darteed waxaan go'aansaday inaan ku duubo turjumaanka TCI. Tani waxay bixisay faa'iidooyin dhowr ah:

  • Markaad hirgelinayso koronto-dhaliye kood, ma eegi kartid sharraxaadda tilmaamaha, laakiin ma fiirin kartid koodka tarjumaanka
  • ma abuuri kartid hawlo kasta oo turjumaada la kulmo, laakiin, tusaale ahaan, kaliya ka dib fulinta boqolaad
  • Haddii koodhka la soo saaray uu isbeddelo (tani waxay u muuqataa inay suurtogal tahay, marka la eego shaqooyinka leh magacyo ay ku jiraan ereyga ereyga), waxaan u baahan doonaa inaan buriyo koodhka JS ee la sameeyay, laakiin ugu yaraan waxaan heli doonaa wax aan dib uga soo celiyo.

Marka la eego qodobka saddexaad, ma hubo in dhejisku suurtogal yahay ka dib marka koodhka la fuliyo markii ugu horeysay, laakiin labada dhibcood ee hore ayaa ku filan.

Markii hore, koodhka waxaa loo soo saaray qaab beddelaad weyn oo ciwaanka asalka ah ee tilmaamaha bytecode, laakiin markaa, xusuusta maqaalka ku saabsan Emscripten, hagaajinta JS ee la soo saaray iyo dib u soo celinta, waxaan go'aansaday inaan soo saaro koodka bini'aadamka, gaar ahaan tan iyo si macquul ah Waxaa soo baxday in meesha kaliya ee laga soo galo block tarjumaada ay tahay Bilawgeeda. Si dhakhso ah ayaa loo sheegay intii la sameeyay, muddo ka dib waxaan haysanay koronto-dhaliye kaas oo soo saaray koodka ifs (inkasta oo aan lahayn wareegyo). Laakiin nasiib xumo, way burburtay, taasoo siisay fariin ah in tilmaamuhu ay ahaayeen kuwo dhererkoodu khaldan yahay. Waxaa intaa dheer, tilmaantii ugu dambeysay ee heerkan soo noqnoqoshada waxay ahayd brcond. Hagaag, waxaan ku dari doonaa jeeg isku mid ah jiilka tilmaamahan ka hor iyo ka dib wicitaanka soo noqnoqda iyo...midna lama fulin, laakiin ka dib wareejinta caddaynta wali way ku guuldareysteen. Dhammaadkii, ka dib markii aan bartay koodka la soo saaray, waxaan ogaaday in beddelka ka dib, tilmaame tilmaamaha hadda laga soo dejiyo xirmooyinka oo ay u badan tahay in lagu beddelay koodka JavaScript ee la sameeyay. Sidaas ayayna ku noqotay. Kordhinta kaydka hal megabyte ilaa toban waxba ma horseedayn, waxaana caddaatay in koronto-dhaliyaha koodhka uu ku socdo wareegyo. Waxay ahayd inaan hubinno inaanan dhaafin xadka Qaaxada hadda jirta, haddii aan sameynayna, soo saarno ciwaanka TB-da xigta oo leh calaamad laga jaray si aan u sii wadno fulinta. Intaa waxaa dheer, tani waxay xallisaa dhibaatada "hawlaha la soo saaray waa in la buriyo haddii qaybta bytecode-ka la beddelo?" - kaliya shaqada u dhiganta xannibaadda tarjumaada ayaa u baahan in la buriyo. Jid ahaan, in kasta oo aan ka saaray wax kasta oo Chromium ah (maadaama aan isticmaalo Firefox oo ay ii fududahay in aan isticmaalo browser gooni ah tijaabooyinka), Firefox ayaa iga caawisay in aan saxo khaladaadka asm.js ee caadiga ah, ka dib koodhka ayaa bilaabay inuu si dhakhso leh ugu shaqeeyo Chromium

Tusaalaha koodka la sameeyay

Compiling 0x15b46d0:
CompiledTB[0x015b46d0] = function(stdlib, ffi, heap) {
"use asm";
var HEAP8 = new stdlib.Int8Array(heap);
var HEAP16 = new stdlib.Int16Array(heap);
var HEAP32 = new stdlib.Int32Array(heap);
var HEAPU8 = new stdlib.Uint8Array(heap);
var HEAPU16 = new stdlib.Uint16Array(heap);
var HEAPU32 = new stdlib.Uint32Array(heap);

var dynCall_iiiiiiiiiii = ffi.dynCall_iiiiiiiiiii;
var getTempRet0 = ffi.getTempRet0;
var badAlignment = ffi.badAlignment;
var _i64Add = ffi._i64Add;
var _i64Subtract = ffi._i64Subtract;
var Math_imul = ffi.Math_imul;
var _mul_unsigned_long_long = ffi._mul_unsigned_long_long;
var execute_if_compiled = ffi.execute_if_compiled;
var getThrew = ffi.getThrew;
var abort = ffi.abort;
var qemu_ld_ub = ffi.qemu_ld_ub;
var qemu_ld_leuw = ffi.qemu_ld_leuw;
var qemu_ld_leul = ffi.qemu_ld_leul;
var qemu_ld_beuw = ffi.qemu_ld_beuw;
var qemu_ld_beul = ffi.qemu_ld_beul;
var qemu_ld_beq = ffi.qemu_ld_beq;
var qemu_ld_leq = ffi.qemu_ld_leq;
var qemu_st_b = ffi.qemu_st_b;
var qemu_st_lew = ffi.qemu_st_lew;
var qemu_st_lel = ffi.qemu_st_lel;
var qemu_st_bew = ffi.qemu_st_bew;
var qemu_st_bel = ffi.qemu_st_bel;
var qemu_st_leq = ffi.qemu_st_leq;
var qemu_st_beq = ffi.qemu_st_beq;

function tb_fun(tb_ptr, env, sp_value, depth) {
  tb_ptr = tb_ptr|0;
  env = env|0;
  sp_value = sp_value|0;
  depth = depth|0;
  var u0 = 0, u1 = 0, u2 = 0, u3 = 0, result = 0;
  var r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0;
  var r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0, r16 = 0, r17 = 0, r18 = 0, r19 = 0;
  var r20 = 0, r21 = 0, r22 = 0, r23 = 0, r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0;
  var r30 = 0, r31 = 0, r41 = 0, r42 = 0, r43 = 0, r44 = 0;
    r14 = env|0;
    r15 = sp_value|0;
  START: do {
    r0 = HEAPU32[((r14 + (-4))|0) >> 2] | 0;
    r42 = 0;
    result = ((r0|0) != (r42|0))|0;
    HEAPU32[1445307] = r0;
    HEAPU32[1445321] = r14;
    if(result|0) {
    HEAPU32[1445322] = r15;
    return 0x0345bf93|0;
    }
    r0 = HEAPU32[((r14 + (16))|0) >> 2] | 0;
    r42 = 8;
    r0 = ((r0|0) - (r42|0))|0;
    HEAPU32[(r14 + (16)) >> 2] = r0;
    r1 = 8;
    HEAPU32[(r14 + (44)) >> 2] = r1;
    r1 = r0|0;
    HEAPU32[(r14 + (40)) >> 2] = r1;
    r42 = 4;
    r0 = ((r0|0) + (r42|0))|0;
    r2 = HEAPU32[((r14 + (24))|0) >> 2] | 0;
    HEAPU32[1445307] = r0;
    HEAPU32[1445308] = r1;
    HEAPU32[1445309] = r2;
    HEAPU32[1445321] = r14;
    HEAPU32[1445322] = r15;
    qemu_st_lel(env|0, r0|0, r2|0, 34, 22759218);
if(getThrew() | 0) abort();
    r0 = 3241038392;
    HEAPU32[1445307] = r0;
    r0 = qemu_ld_leul(env|0, r0|0, 34, 22759233)|0;
if(getThrew() | 0) abort();
    HEAPU32[(r14 + (24)) >> 2] = r0;
    r1 = HEAPU32[((r14 + (12))|0) >> 2] | 0;
    r2 = HEAPU32[((r14 + (40))|0) >> 2] | 0;
    HEAPU32[1445307] = r0;
    HEAPU32[1445308] = r1;
    HEAPU32[1445309] = r2;
    qemu_st_lel(env|0, r2|0, r1|0, 34, 22759265);
if(getThrew() | 0) abort();
    r0 = HEAPU32[((r14 + (24))|0) >> 2] | 0;
    HEAPU32[(r14 + (40)) >> 2] = r0;
    r1 = 24;
    HEAPU32[(r14 + (52)) >> 2] = r1;
    r42 = 0;
    result = ((r0|0) == (r42|0))|0;
    if(result|0) {
    HEAPU32[1445307] = r0;
    HEAPU32[1445308] = r1;
    }
    HEAPU32[1445307] = r0;
    HEAPU32[1445308] = r1;
    return execute_if_compiled(22759392|0, env|0, sp_value|0, depth|0) | 0;
    return execute_if_compiled(23164080|0, env|0, sp_value|0, depth|0) | 0;
    break;
  } while(1); abort(); return 0|0;
}
return {tb_fun: tb_fun};
}(window, CompilerFFI, Module.buffer)["tb_fun"]

gunaanad

Markaa, shaqadu wali lama dhammaystirin, laakiin waan ka daalay inaan si qarsoodi ah u keeno dhismahan muddada-dheer ee dhammaystiran. Sidaa darteed, waxaan go'aansaday inaan daabaco waxa aan haysto hadda. Koodhku waa wax yar oo cabsi ah meelaha, sababtoo ah tani waa tijaabo, oo horay uma cadda waxa loo baahan yahay in la sameeyo. Malaha, markaas waxaa mudan in lagu soo saaro fal-dambiyeedyada atomiga caadiga ah oo ka sarreeya nooc cusub oo Qemu ah. Dhanka kale, waxaa jira dun Gita ah oo qaab blog ah: "heerka" kasta oo ugu yaraan si uun loo gudbiyay, faallo faahfaahsan oo Ruush ah ayaa lagu daray. Dhab ahaantii, maqaalkani waa mid si weyn uga hadlaya gabagabada git log.

Waad isku dayi kartaa dhammaan halkan (iska jir gaadiidka).

Maxaa hadaba shaqaynaya:

  • x86 processor-ka dalwaddii oo socda
  • Waxa jira nooc shaqaynaya oo ah curiyaha koodhka JIT ee ka imanaya koodka mashiinka ilaa JavaScript
  • Waxaa jira qaab-dhismeedka isku-dhafka 32-bit ee dhismooyinka kale ee martida: hadda waxaad u bogi kartaa Linux qaab dhismeedka MIPS ee qaboojinta browserka heerka rarida

Maxaa kale oo aad sameyn kartaa

  • Dadaji ku dayashada. Xataa qaabka JIT waxay umuuqataa inuu ka gaabinayo Virtual x86 (laakiin waxaa suurtogal ah inuu jiro Qemu oo dhan oo leh qalab badan oo lagu daydo iyo qaab dhismeedka)
  • Si aan u sameeyo is-dhexgal caadi ah - run ahaantii, ma ihi horumariye mareegaha wanaagsan, markaa hadda waxaan dib u sameeyay qolofka caadiga ah ee Emscripten sida ugu wanaagsan ee aan awoodo.
  • Isku day inaad bilowdo hawlo badan oo kakan oo Qemu ah - isku xidhka, guuritaanka VM, iwm.
  • UPS: waxaad u baahan doontaa inaad u soo gudbiso dhowrka horumar eeada iyo warbixinaha kutaannada Emscripten korkeeda, sida xamaaliyadii hore ee Qemu iyo mashaariicda kale ay sameeyeen. Waad ku mahadsan tahay inay awoodeen inay si aan toos ahayn ugu adeegsadaan wax ku biirintooda Emscripten qayb ka mid ah hawshayda.

Source: www.habr.com

Add a comment