I-Qemu.js ngenkxaso ye-JIT: usenako ukuyijika i-mince ngasemva

Kwiminyaka embalwa edlulileyo uFabrice Belard ibhalwe ngu jslinux sisilinganisi sePC esibhalwe kwiJavaScript. Emva koko kwakukho ubuncinane ngakumbi I-x86 ebonakalayo. Kodwa bonke, ngokokwazi kwam, babezitoliki, ngelixa uQemu, ebhalwe ngaphambili kakhulu nguFabrice Bellard ofanayo, kwaye, mhlawumbi, nawuphi na umlingisi ozihloniphayo wale mihla, usebenzisa ukuhlanganiswa kweJIT yekhowudi yeendwendwe kwikhowudi yenkqubo yokusingatha. Kwabonakala kum ukuba yayilixesha lokuphumeza umsebenzi owahlukileyo ngokunxulumene nalowo usonjululwa ngabakhangeli: I-JIT yokuhlanganiswa kwekhowudi yomatshini kwiJavaScript, ekubonakala ngathi isengqiqweni kakhulu kwi-port Qemu. Kubonakala ngathi, kutheni i-Qemu, kukho i-emulators elula kunye ne-user-friendly - i-VirtualBox efanayo, umzekelo - efakwe kwaye isebenza. Kodwa uQemu uneempawu ezininzi ezinomdla

  • Vula Umnikezi
  • ukukwazi ukusebenza ngaphandle komqhubi we-kernel
  • ukukwazi ukusebenza kwimo yokutolika
  • inkxaso yenani elikhulu lazo zombini iindwendwe kunye nezakhiwo zeendwendwe

Ngokumalunga nenqaku lesithathu, ngoku ndiyakwazi ukucacisa ukuba ngokwenene, kwimodi ye-TCI, ayisiyiyo imiyalelo yomatshini weendwendwe ngokwayo etolikwayo, kodwa i-bytecode efunyenwe kubo, kodwa oku akutshintshi undoqo - ukuze kwakhiwe kwaye kuqhutywe. Qemu kwi-architecture entsha, ukuba unethamsanqa, i-C compiler yanele - ukubhala ikhowudi yejenereyitha kunokuhlehliswa.

Kwaye ngoku, emva kweminyaka emibini yokuzonwabisa kunye nekhowudi yomthombo weQemu ngexesha lam lokukhulula, kwavela iprototype esebenzayo, apho unokuthi uqhube khona, umzekelo, i-Kolibri OS.

Yintoni i-Emscripten

Namhlanje, abaqulunqi abaninzi baye bavela, umphumo wokugqibela yiJavaScript. Ezinye, ezinje ngoHlobo lweSikripthi, zazenzelwe ukuba zibe yeyona ndlela ilungileyo yokubhalela iwebhu. Ngexesha elifanayo, i-Emscripten yindlela yokuthatha ikhowudi yeC okanye i-C ++ ekhoyo kwaye iqulunqe kwifom efundekayo yesiphequluli. Vula kweli phepha Siqokelele amazibuko amaninzi eenkqubo ezaziwayo-kakuhle: aphaUmzekelo, unokujonga kwiPyPy - ngendlela, bathi sele benayo iJIT. Ngapha koko, ayizizo zonke iinkqubo ezinokudityaniswa kwaye ziqhutywe kwisikhangeli - kukho inani Iimbonakalo, ekufuneka unyamezele, nangona kunjalo, njengoko umbhalo okwiphepha elifanayo lisithi "I-Emscripten ingasetyenziselwa ukuqokelela phantse nayiphi na into. ephathekayo C/C++ ikhowudi kwiJavaScript". Oko kukuthi, kukho inani lemisebenzi engachazwanga yokuziphatha ngokomgangatho, kodwa ngokuqhelekileyo isebenza kwi-x86 - umzekelo, ukufikelela okungalungelelanisiweyo kwizinto eziguquguqukayo, ezingavumelekanga ngokubanzi kwezinye izakhiwo. Ngokubanzi. , IQemu yinkqubo yeqonga elinqamlezileyo kwaye, bendifuna ukukholelwa, kwaye ayiqulathanga uninzi lokuziphatha okungachazwanga - yithathe kwaye uqokelele, emva koko ujonge kancinci ngeJIT - kwaye ugqibile! ityala...

Zama kuqala

Ngokubanzi, andingomntu wokuqala ukuza nombono wokuhambisa uQemu kwiJavaScript. Kwakukho umbuzo obuzwe kwiforum ye-ReactOS ukuba oku kunokwenzeka usebenzisa i-Emscripten. Ngaphambili, kwakukho amahemuhemu okuba uFabrice Bellard wenza oku ngokwakhe, kodwa sasithetha nge-jslinux, leyo, njengoko ndiyazi, ngumzamo nje wokufezekisa ukusebenza okwaneleyo kwi-JS, kwaye yabhalwa ukusuka ekuqaleni. Emva kwexesha, i-Virtual x86 yabhalwa - imithombo engabonakaliyo yathunyelwa kuyo, kwaye, njengoko kuchaziwe, "inyani" enkulu yokulinganisa yenza ukuba kube lula ukusebenzisa i-SeaBIOS njenge-firmware. Ukongeza, bekukho umzamo omnye wokufaka i-Qemu usebenzisa i-Emscripten- ndizamile ukwenza oku socketpair, kodwa uphuhliso, ngokokuqonda kwam, lwaba ngumkhenkce.

Ke, kubonakala ngathi, nantsi imithombo, nantsi i-Emscripten - yithathe kwaye uqokelele. Kodwa akhona amathala eencwadi axhomekeke kuwo uQemu, kunye namathala eencwadi axhomekeke kuwo loo mathala, njl. libfi, eyiphi i-glib exhomekeke kuyo. Kwakukho amahemuhemu kwi-Intanethi ukuba kukho enye kwingqokelela enkulu yamazibuko eelayibrari ze-Emscripten, kodwa kwakunzima ngandlela thile ukukholelwa: okokuqala, yayingajoliswanga ukuba ibe ngumqambi omtsha, okwesibini, yayikwinqanaba eliphantsi kakhulu. ilayibrari yokuthatha nje, kwaye uhlanganisele kwi-JS. Kwaye ayisiyonto nje yokufakwa kwendibano-mhlawumbi, ukuba uyayijija, kwezinye iindibano zokufowuna unokuvelisa iingxoxo eziyimfuneko kwisitaki kwaye ubize umsebenzi ngaphandle kwazo. Kodwa i-Emscripten yinto ekhohlisayo: ukuze wenze ikhowudi evelisiweyo ibonakale iqhelekile kwisikhangeli se-JS injini ye-optimizer, amanye amaqhinga asetyenziswa. Ngokukodwa, into ebizwa ngokuba yi-relooping-ijenereyitha yekhowudi esebenzisa i-LLVM IR efunyenweyo kunye nemiyalelo yenguqu engabonakaliyo izama ukuphinda wenze i-ifs enokwenzeka, iilophu, njl. Ewe, iingxoxo zigqithiswa njani kumsebenzi? Ngokwendalo, njengeengxoxo kwimisebenzi ye-JS, oko kukuthi, ukuba kuyenzeka, hayi ngesitaki.

Ekuqaleni bekukho umbono wokubhala ngokulula ukutshintshwa kwe-libffi nge-JS kwaye ndiqhube iimvavanyo eziqhelekileyo, kodwa ekugqibeleni ndabhideka malunga nendlela yokwenza iifayile zentloko yam ukuze zisebenze kunye nekhowudi ekhoyo - ndingenza ntoni, njengoko besithi, "Ngaba imisebenzi enzima kangaka "Ngaba sisidenge?" Kwafuneka ndikhuphe i-libffi kwelinye i-architecture, ukuze ndithethe-ngethamsanqa, i-Emscripten inezo zombini ii-macros zendibano ye-inline (kwi-Javascript, ewe-ewe, nokuba yeyiphi na i-architecture, ngoko ke i-assembler), kunye nokukwazi ukuqhuba ikhowudi eyenziwe kwimpukane. Ngokubanzi, emva kokuphonononga ngamaqhekeza e-libffi axhomekeke kwiqonga kangangexesha elithile, ndiye ndafumana ikhowudi edibeneyo kwaye ndayiqhuba kuvavanyo lokuqala endadibana nalo. Okwandimangalisayo kukuba, olo vavanyo lwaphumelela. Ndothuswe bubulumko bam - akukho qhula, kusebenze ukusukela kuphehlelelo lokuqala - mna, ndingekawakholelwa amehlo am, ndaya kujonga ikhowudi efunyenweyo kwakhona, ukuvavanya indawo yokumba ngokulandelayo. Apha ndiye ndahamba okwesibini-into kuphela into endiyenzileyo ffi_call - oku kuxelwe umnxeba ophumeleleyo. Kwakungekho mnxeba ngokwawo. Ke ndathumela isicelo sam sokuqala sokutsala, esilungisa impazamo kuvavanyo olucacileyo kuye nawuphi na umfundi weOlympiad - amanani okwenyani akufuneki athelekiswe njengawo. a == b nokuba njani a - b < EPS - kufuneka kwakhona ukhumbule imodyuli, kungenjalo u-0 uya kuvela alingane kakhulu no-1/3... Ngokubanzi, ndeza nezibuko elithile le-libffi, eliphumelela iimvavanyo ezilula, kwaye yeyiphi i-glib. ihlanganiswe - ndigqibe kwelokuba iyakufuneka, ndizakuyidibanisa kamva. Ukujonga phambili, ndiya kuthetha ukuba, njengoko kwavela, umqambi akazange afake nomsebenzi we-libffi kwikhowudi yokugqibela.

Kodwa, njengoko besenditshilo, kukho imida, kwaye phakathi kokusetyenziswa simahla kokuziphatha okwahlukeneyo okungachazwanga, into engathandekiyo ngakumbi ifihliwe - iJavaScript ngoyilo ayixhasi ukufundwa kwemininzi ngememori ekwabelwanayo ngayo. Ngokomgaqo, oku kunokude kubizwe ngokuba luluvo olulungileyo, kodwa hayi ikhowudi yokufaka ulwakhiwo lubotshelelwe kwimisonto ye-C. Ngokubanzi, iFirefox izama ukuxhasa abasebenzi ekwabelwana ngabo, kwaye i-Emscripten inokuphunyezwa kwe-pthread kubo, kodwa andizange ndifune ukuxhomekeka kuyo. Kwafuneka ndincothule ngokucothayo ukuncothula ufundo oluninzi kwikhowudi yeQemu - oko kukuthi, ndifumanise apho imisonto ibaleka khona, ndishukumise umzimba welophu ebaleka kulo msonto ukuya kumsebenzi owahlukileyo, kwaye ndibize imisebenzi elolo hlobo nganye nganye ukusuka kwiluphu ephambili.

Inzame yesibini

Ngaxa lithile, kuye kwacaca ukuba ingxaki isekho, nokuba iintonga zokududula ngokungacwangciswanga kwikhowudi kwakungayi kukhokelela kuyo nayiphi na into elungileyo. Ukuqukumbela: kufuneka ngandlela ithile sicwangcise inkqubo yokongeza iintonga. Ngoko ke, inguqulo 2.4.1, eyayintsha ngelo xesha, yathathwa (hayi 2.5.0, kuba, ngubani owaziyo, kuya kubakho iibhugi kwinguqulo entsha engekabanjwa, kwaye ndonele ngokwaneleyo kwiimpazamo zam. ), kwaye into yokuqala yayikukuyibhala kwakhona ngokukhuselekileyo thread-posix.c. Ewe, oko kukuthi, ngokukhuselekileyo: ukuba umntu uzame ukwenza umsebenzi okhokelela ekuthinteleni, umsebenzi wabizwa ngoko nangoko abort() - ngokuqinisekileyo, oku akuzange kuzisombulule zonke iingxaki ngexesha elinye, kodwa ubuncinci kwakumnandi ngandlela-thile kunokufumana ngokuthe cwaka idatha engahambelaniyo.

Ngokubanzi, iinketho ze-Emscripten ziluncedo kakhulu kwikhowudi yokufaka kwi-JS -s ASSERTIONS=1 -s SAFE_HEAP=1 - babambisa ezinye iindidi zokuziphatha okungachazwanga, njengeefowuni eziya kwidilesi engalungiswanga (engahambelaniyo kwaphela nekhowudi yoluhlu oluchwetheziweyo njenge HEAP32[addr >> 2] = 1) okanye ukubiza umsebenzi ngenani elingalunganga leempikiswano.

Ngendlela, iimpazamo zokulungelelaniswa zingumba owahlukileyo. Njengoko besenditshilo, u-Qemu une-backend "ehlazileyo" yokutolika ikhowudi yokuvelisa i-TCI (itoliki yekhowudi encinci), kunye nokwakha kunye nokuqhuba i-Qemu kwisakhiwo esitsha, ukuba unethamsanqa, umqokeleli we-C wanele. "ukuba unethamsanqa". Bendingenathamsanqa, kwaye kwavela ukuba i-TCI isebenzisa ufikelelo olungacwangciswanga xa isahlulahlula i-bytecode yayo. Oko kukuthi, kuzo zonke iintlobo ze-ARM kunye nezinye izakhiwo ezinokufikelela ngokuyimfuneko, i-Qemu iqokelela ngenxa yokuba ine-backend ye-TCG eqhelekileyo eyenza ikhowudi yendalo, kodwa ukuba i-TCI iya kusebenza kubo ngomnye umbuzo. Nangona kunjalo, njengoko kwavelayo, amaxwebhu e-TCI abonisa ngokucacileyo into efanayo. Ngenxa yoko, iifowuni zomsebenzi wokufundwa okungalungelelanisiweyo zongezwa kwikhowudi, efunyenwe kwenye indawo yeQemu.

Ukutshatyalaliswa kwemfumba

Ngenxa yoko, ufikelelo olungalungelelanisiweyo lwe-TCI lwalungiswa, i-loop ephambili yenziwa eyathi yabizwa ngokuba yiprosesa, i-RCU kunye nezinye izinto ezincinci. Kwaye ke ndisungula uQemu ngokhetho -d exec,in_asm,out_asm, oku kuthetha ukuba kufuneka utsho ukuba zeziphi iibhloko zekhowudi eziphunyeziweyo, kwaye ngexesha lokusasazwa ukuze ubhale ukuba yeyiphi ikhowudi yeendwendwe, yintoni ikhowudi yomkhosi eyaba yiyo (kule meko, bytecode). Iqala, iphumeze iibhloko ezininzi zokuguqulela, ibhala umyalezo osusa iimpazamo endiwushiye ukuba i-RCU ngoku izakuqala kwaye... abort() ngaphakathi komsebenzi free(). Ngokuphonononga umsebenzi free() Sikwazile ukufumanisa ukuba kwi-header yebloko yemfumba, elele kwiibyte ezisibhozo ezandulela imemori eyabelweyo, endaweni yobungakanani bebhloko okanye into efanayo, bekukho inkunkuma.

Ukutshatyalaliswa kwemfumba - indlela enhle ngayo ... Kwimeko enjalo, kukho unyango oluluncedo - ukusuka (ukuba kunokwenzeka) kwimithombo efanayo, hlanganisa i-binary yendalo kwaye uyiqhube phantsi kweValgrind. Emva kwexesha elithile, i-binary yayilungile. Ndiyisungula ngeenketho ezifanayo - iyantlitheka naxa iqaliswa, ngaphambi kokuba ifikelele ekuphumezeni. Ayimnandanga, kunjalo-ngokucacileyo, imithombo yayingafani ncam, oko akumangalisi, kuba uqwalaselo lukhangelwe iinketho ezahlukeneyo, kodwa ndineValgrind - okokuqala ndiza kuyilungisa le bug, kwaye ke, ukuba ndinethamsanqa. , eyokuqala iya kuvela. Ndiqalisa into efanayo phantsi kweValgrind ... Y-y-y, y-y-y, uh-uh, yaqala, yahamba ngokuqaliswa ngokuqhelekileyo kwaye yaqhubela phambili kwi-bug yangaphambili ngaphandle kwesilumkiso esisodwa malunga nokufikelela kwimemori engalunganga, kungathethi malunga nokuwa. Ubomi, njengoko besitsho, abuzange bundilungiselele oku - inkqubo yokuwohloka iyeka ukuwohloka xa isungulwa phantsi kweWalgrind. Ukuba yayiyintoni na yimfihlelo. Ingqikelelo yam yeyokuba kanye kwindawo yomyalelo wangoku emva kwengozi ngexesha lokuqalisa, i-gdb ibonise umsebenzi. memset-a enesalathisi esisebenzayo usebenzisa nokuba yeyiphi na mmx, okanye xmm iirejista, ngoko mhlawumbi yayiyimpazamo yokulungelelanisa, nangona kusenzima ukuyikholelwa.

Kulungile, uValgrind akabonakali eluncedo apha. Kwaye apha eyona nto ilizothe yaqala-yonke into ibonakala ngathi iqala, kodwa ingqubana ngenxa yezizathu ezingaziwayo ngenxa yesiganeko ebesinokuthi senzeke kwizigidi zemiyalelo edlulileyo. Kangangexesha elide, kwakungacacanga nendlela yokufikelela. Ekugqibeleni, kwakusafuneka ndihlale phantsi ndilungise ingxaki. Ukuprinta ukuba iheader yabhalwa ngantoni kwakhona ibonise ukuba ayikhange ibukeke njengenani, kodwa kunolunye uhlobo lwedatha yokubini. Kwaye, khangela kwaye ubone, le ntambo yokubini ifunyenwe kwifayile ye-BIOS - oko kukuthi, ngoku kwakunokwenzeka ukuthetha ngokuzithemba okufanelekileyo ukuba kwakuyi-buffer ephuphumayo, kwaye kucacile ukuba kubhaliwe kule buffer. Ewe, ke into enje - kwi-Emscripten, ngethamsanqa, akukho randomisation yendawo yedilesi, akukho mingxunya kuyo nokuba, ukuze ukwazi ukubhala kwindawo ethile embindini wekhowudi ukuvelisa idatha ngesalathisi ukusuka kuphehlelelo lokugqibela, jonga idatha, jonga isalathisi, kwaye, ukuba ayitshintshanga, fumana ukutya okucingayo. Kuyinyani, kuthatha imizuzu embalwa ukudibanisa emva kwalo naluphi na utshintsho, kodwa ungenza ntoni? Ngenxa yoko, umgca othile wafunyanwa okhuphele i-BIOS ukusuka kwi-buffer yethutyana ukuya kwimemori yeendwendwe - kwaye, eneneni, kwakungekho ndawo yaneleyo kwi-buffer. Ukufumana imvelaphi yedilesi engaqhelekanga yesithinteli kubangele umsebenzi qemu_anon_ram_alloc kwifayile oslib-posix.c -ingqiqo kwakukho oku: ngamanye amaxesha kunokuba luncedo ukulungelelanisa idilesi kwiphepha elikhulu le-2 MB ngobukhulu, oku siza kubuza mmap kuqala kancinci, kwaye emva koko siya kubuyisela ukugqithisa ngoncedo munmap. Kwaye ukuba ulungelelwaniso olunjalo alufunwa, ngoko siya kubonisa umphumo endaweni ye-2 MB getpagesize() - mmap isaza kukhupha idilesi elungelelanisiweyo... Ngoko ke kwi-Emscripten mmap iminxeba nje malloc, kodwa ngokuqinisekileyo ayihambelani kwiphepha. Ngokubanzi, i-bug eyandikhathazayo kwiinyanga ezimbalwa yalungiswa ngotshintsho Π΄Π²ΡƒΡ… imigca.

Iimpawu zemisebenzi yokufowuna

Kwaye ngoku iprosesa ibala into, i-Qemu ayiphahlaki, kodwa isikrini asivuli, kwaye iprosesa ingena ngokukhawuleza kwi-loops, igweba ngemveliso. -d exec,in_asm,out_asm. Kuye kwavela i-hypothesis: i-timer interrupts (okanye, ngokubanzi, zonke iziphazamisi) azifiki. Kwaye eneneni, ukuba ukhulula iziphazamiso kwindibano yemveli, esebenze ngesizathu esithile, ufumana umfanekiso ofanayo. Kodwa le ibingeyompendulo kwaphela: uthelekiso lwemikhondo ekhutshwe ngolu khetho lungentla lubonise ukuba iindlela zokubulawa zahlukana kwangoko. Apha kufuneka kuthiwe uthelekiso lwento erekhodiweyo kusetyenziswa isiqalisi emrun ukulungisa ingxaki ngemveliso yendibano yemveli asiyonkqubo yomatshini ngokupheleleyo. Andazi ncam ukuba inkqubo esebenza kwisikhangeli idibana njani nayo emrun, kodwa ezinye iilayini kwimveliso zijika zicwangciswe ngokutsha, ngoko ke umahluko kwi-diff awukabi sisizathu sokucinga ukuba iindlela zokuziphatha ziye zahlukana. Ngokubanzi, kwacaca ukuba ngokwemiyalelo ljmpl kukho ukutshintshela kwiidilesi ezahlukeneyo, kwaye i-bytecode eyenziwe yahluke kakhulu: enye iqulethe umyalelo wokubiza umsebenzi womncedisi, enye ayinayo. Emva kokukhangela imiyalelo kunye nokufunda ikhowudi eguqulela le miyalelo, kwacaca ukuba, okokuqala, ngokukhawuleza phambi kwayo kwirejista. cr0 ukurekhoda kwenziwa - kwakhona kusetyenziswa umncedisi - owatshintshela iprosesa kwimo ekhuselweyo, kwaye okwesibini, ukuba i-js version ayizange itshintshele kwimo ekhuselweyo. Kodwa inyani kukuba enye into ye-Emscripten kukungafuni ukunyamezela ikhowudi efana nokuphunyezwa kwemiyalelo. call kwi-TCI, apho nayiphi na isalathisi somsebenzi isiphumo sohlobo long long f(int arg0, .. int arg9) - imisebenzi kufuneka ibizwe ngenani elichanekileyo leengxoxo. Ukuba lo mgaqo waphulwa, kuxhomekeke kwizicwangciso zolungiso lweempazamo, inkqubo iya kuphazamiseka (elungileyo) okanye ibize umsebenzi ongalunganga kwaphela (okuya kuba lusizi ukulungisa ingxaki). Kukwakho nokhetho lwesithathu - vumela ukuveliswa kwee-wrappers ezongeza / ezisusa iingxoxo, kodwa xa zizonke ezi zisonga zithatha indawo eninzi, nangona enyanisweni ndifuna kuphela ngaphezulu kwekhulu lokusonga. Oku kukodwa kubuhlungu kakhulu, kodwa kuye kwakho ingxaki enkulu ngakumbi: kwikhowudi eyenziweyo yemisebenzi ye-wrapper, iingxoxo zaguqulwa kwaye zaguqulwa, kodwa ngamanye amaxesha umsebenzi kunye neengxabano ezenziweyo awuzange ubizwe - kakuhle, njengaku. ukuphunyezwa kwam libffi. Oko kukuthi, abanye abancedi abazange babulawe.

Ngethamsanqa, uQemu unoluhlu olufundeka ngomatshini lwabancedisi ngokohlobo lwefayile yeheader efana

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

Zisetyenziswa ngokuhlekisayo: okokuqala, iimacros zichazwa ngokutsha ngeyona ndlela ingaqhelekanga DEF_HELPER_n, kwaye emva koko ivule helper.h. Ukuya kuthi ga kwinqanaba lokuba i-macro yandiswe ibe sisiqalisi sesakhiwo kunye nekoma, emva koko kuchazwe uluhlu, kwaye endaweni yezinto - #include <helper.h> Ngenxa yoko, ekugqibeleni ndafumana ithuba lokuzama ithala leencwadi emsebenzini pyparsing, kunye neskripthi sabhalwa esivelisa kanye loo maphepha asongayo ukwenzela kanye imisebenzi ayifunayo.

Kwaye ke, emva koko iprosesa yabonakala isebenza. Kubonakala ngathi kungenxa yokuba isikrini asizange siqaliswe, nangona i-memtest86 + yakwazi ukuqhuba kwindibano yemveli. Apha kuyimfuneko ukucacisa ukuba ikhowudi ye-Qemu block I / O ibhalwe kwii-coroutines. I-Emscripten inokuphunyezwa kwayo okukhohlisayo, kodwa bekusafuneka ixhaswe kwikhowudi yeQemu, kwaye ungalungisa iprosesa ngoku: Qemu ixhasa iinketho. -kernel, -initrd, -append, onokuthi uqale ngayo i-Linux okanye, umzekelo, i-memtest86+, ngaphandle kokusebenzisa izixhobo zebhloko konke konke. Kodwa nantsi ingxaki: kwindibano yemveli umntu unokubona iLinux kernel ephuma kwiconsole ngokhetho -nographic, kwaye akukho mveliso ukusuka kwisikhangeli ukuya kwi-terminal ukusuka apho yasungulwa khona emrun, akazange eze. Oko kukuthi, akucaci: iprosesa ayisebenzi okanye imveliso yegraphics ayisebenzi. Kwaye kwathi qatha kum ukuba ndilinde kancinci. Kuye kwavela ukuba "iprosesa ayilali, kodwa iqhwanyaza kancinci," kwaye emva kwemizuzu emihlanu i-kernel yaphosa iqela lemiyalezo kwi-console kwaye yaqhubeka nokuxhoma. Kwacaca ukuba iprosesa, ngokubanzi, isebenza, kwaye kufuneka simbe kwikhowudi yokusebenza kunye ne-SDL2. Ngelishwa, andiyazi indlela yokusebenzisa eli thala leencwadi, ngoko kwezinye iindawo kwakufuneka ndenze okuthile. Ngaxa lithile, umgca parallel0 wadanyaza kwiscreen ngasemva blue, nto leyo ecebisa ezinye iingcinga. Ekugqibeleni, kwavela ukuba ingxaki yayikukuba uQemu uvula iifestile ezininzi ezinenyani kwifestile yenyama enye, onokuthi utshintshe phakathi kwayo usebenzisa i-Ctrl-Alt-n: isebenza kulwakhiwo lwemveli, kodwa hayi kwi-Emscripten. Emva kokulahla iifestile ezingeyomfuneko usebenzisa iinketho -monitor none -parallel none -serial none kunye nemiyalelo yokuzoba ngokutsha ngenkani isikrini sonke kwisakhelo ngasinye, yonke into yasebenza ngequbuliso.

IiCoroutines

Ke, ukulinganisa kwi-browser kuyasebenza, kodwa awukwazi ukuqhuba nantoni na enomdla-floppy kuyo, kuba akukho block I / O - kufuneka uphumeze inkxaso ye-coroutines. I-Qemu sele inee-backends ezininzi ze-coroutine, kodwa ngenxa yobume beJavaScript kunye ne-Emscripten ikhowudi yejenereyitha, awunakuvele uqalise ukujija izitaki. Kubonakala ngathi "yonke into ihambile, i-plaster iyasuswa," kodwa abaphuhlisi be-Emscripten sele behoyile yonke into. Oku kuphunyezwa ngokuhlekisayo: masibize umnxeba womsebenzi onje ngokukrokrisayo emscripten_sleep kunye nezinye ezininzi zisebenzisa i-Asyncify mechanism, kunye neefowuni zesalathisi kunye neefowuni kuwo nawuphi na umsebenzi apho enye yeemeko ezimbini ezidlulileyo inokuthi yenzeke ngakumbi ezantsi kwistakhi. Kwaye ngoku, phambi komnxeba ngamnye okrokrelayo, siya kukhetha umxholo we-async, kwaye kwangoko emva kokufowuna, siya kujonga ukuba umnxeba ongahambelaniyo wenzekile na, kwaye ukuba kwenzekile, siya kugcina zonke iinguqu zasekhaya kulo mxholo we-async, bonisa ukuba ngowuphi umsebenzi. ukudlulisa ulawulo xa sifuna ukuqhubeka nokwenziwa , kwaye uphume umsebenzi wangoku. Apha kulapho kukho umda wokufunda isiphumo ukuchitha - kwiimfuno zokuqhubeka kokwenziwa kwekhowudi emva kokubuya kwifowuni engavumelaniyo, umqambi uvelisa "i-stubs" yomsebenzi oqala emva komnxeba okrokrelayo - ngolu hlobo: ukuba kukho iifowuni ezikrokrelayo, ngoko umsebenzi uya kwandiswa kwindawo ethile n/2 amaxesha β€” oku kusenjalo, ukuba akunjalo Gcina ukhumbula ukuba emva kokufowuna okunokubakho kwi-asynchronous, kufuneka udibanise ukugcina iinguqu ezithile zasekuhlaleni kumsebenzi wokuqala. Emva koko, kuye kwafuneka ndibhale iskripthi esilula kwiPython, ethi, ngokusekwe kwiseti enikiweyo yemisebenzi esetyenziswa kakhulu ekucingelwa ukuba "ayivumeli i-asynchrony ukuba idlule ngokwazo" (oko kukuthi, ukunyuswa kwesitaki kunye nayo yonke into endisandul' ukuyichaza ayenzi. sebenza kuzo), ibonisa iifowuni ngokusebenzisa izikhombisi apho imisebenzi kufuneka ingahoywa ngumqambi ukuze le misebenzi ingathathwa njenge-synchronous. Kwaye ke iifayile ze-JS phantsi kwe-60 MB zicacile kakhulu - masithi ubuncinane i-30. Nangona, xa ndandiseta i-script yendibano, kwaye ngengozi ndalahla iinketho zekhonkco, phakathi kwazo kwakukho. -O3. Ndiqhuba ikhowudi eyenziweyo, kwaye iChromium itya inkumbulo kunye nokuphazamiseka. Ndaye ndajonga ngempazamo into awayezama ukuyikhuphela... Ewe, ndingathini, nam ngendikhe ndakhenkceza ukuba bendicelwe ukuba ndifunde ngokucinga kwaye ndongeze iJavascript eyi-500+.

Ngelishwa, iitshekhi kwikhowudi yethala yenkxaso ye-Asyncify yayingenabuhlobo ngokupheleleyo nayo longjmp-ezisetyenziswa kwikhowudi yeprosesa enenyani, kodwa emva kwesiqwengana esincinci esikhubaza ezi zitshekisho kwaye zibuyisele ngamandla iimeko ngokungathi yonke into yayilungile, ikhowudi yasebenza. Kwaye ke into engaqhelekanga yaqala: ngamanye amaxesha iitshekhi kwikhowudi yongqamaniso zaye zavulwa - ezifanayo eziphazamisa ikhowudi ukuba, ngokwengqiqo yokuphumeza, kufuneka ivalwe - umntu uzame ukubamba i-mutex esele ibanjwe. Ngethamsanqa, oku akuzange kube yingxaki esengqiqweni kwikhowudi yolandelelwano- bendisebenzisa usetyenziso olusezantsi lwelophu olunikezwe ngu-Emscripten, kodwa ngamanye amaxesha umnxeba ongahambelaniyo uya kuvula ngokupheleleyo isitaki, kwaye ngaloo mzuzu iya kusilela. setTimeout ukusuka kwi-loop engundoqo - ngaloo ndlela, ikhowudi ifake i-loop iteration engundoqo ngaphandle kokushiya i-iteration yangaphambili. Bhala kwakhona kwilophu engapheliyo kwaye emscripten_sleep, kwaye iingxaki zemutexes zayeka. Ikhowudi iye yaqina ngakumbi - emva kwayo yonke loo nto, enyanisweni, andinayo ikhowudi elungiselela isakhelo soopopayi esilandelayo - iprosesa ibala nje into kwaye isikrini sihlaziywa ngamaxesha athile. Nangona kunjalo, iingxaki azizange ziphelele apho: ngamanye amaxesha ukubulawa kuka-Qemu kuya kupheliswa nje cwaka ngaphandle kokukhetha okanye iimpazamo. Ngelo xesha ndayiyeka, kodwa, ndijonge phambili, ndiza kuthi ingxaki yile: ikhowudi ye-coroutine, enyanisweni, ayisebenzisi. setTimeout (okanye hayi rhoqo njengoko unokucinga): umsebenzi emscripten_yield icwangcisa ngokulula iflegi yomnxeba engahambelaniyo. Inqaku elipheleleyo kukuba emscripten_coroutine_next ayingomsebenzi ongahambelaniyo: ngaphakathi ijonga iflegi, iyimise ngokutsha kwaye idlulisele ulawulo apho ifuneka khona. Oko kukuthi, ukunyuswa kwesitaki kuphelela apho. Ingxaki yayikukuba ngenxa yokusetyenziswa-emva kwe-free, eyavela xa i-pool ye-coroutine ivaliwe ngenxa yokuba andizange ndikhuphe umgca obalulekileyo wekhowudi kwi-backend ekhoyo ye-coroutine, umsebenzi. qemu_in_coroutine ibuyiselwe inyani xa enyanisweni bekufanele ukuba ibuyile bubuxoki. Oku kukhokhelele ekufowuneni emscripten_yield, ngaphezu koko kwakungekho mntu kwisitaki emscripten_coroutine_next, isitaki sityhilwe phezulu, kodwa hayi setTimeout, njengoko besenditshilo, ayizange iboniswe.

Ukuveliswa kwekhowudi yeJavaScript

Kwaye apha, eneneni, sisithembiso "sokubuyisela inyama ecoliweyo." Hayi ncma. Ngokuqinisekileyo, ukuba siqhuba i-Qemu kwisiphequluli, kunye ne-Node.js kuyo, ngoko, ngokwemvelo, emva kokuveliswa kwekhowudi eQemu siya kufumana iJavaScript ephosakeleyo ngokupheleleyo. Kodwa kunjalo, uhlobo oluthile lokuguqulwa kwenguqu.

Okokuqala, kancinci malunga nendlela uQemu asebenza ngayo. Ndicela undixolele ngoko nangoko: Andingomqambi weQemu oqeqeshiweyo kwaye izigqibo zam zinokuba yimpazamo kwezinye iindawo. Njengoko besitsho, "uluvo lomfundi akufuneki luhambelane noluvo lukatitshala, i-axiomatics kaPeano kunye nengqiqo." I-Qemu inenani elithile lolwakhiwo lweendwendwe oluxhaswayo kwaye kwindawo nganye kukho uvimba weefayili onje target-i386. Xa usakha, ungakhankanya inkxaso yolwakhiwo lweendwendwe ezininzi, kodwa isiphumo siya kuba ngamabhinari amaninzi. Ikhowudi yokuxhasa ulwakhiwo lweendwendwe, ngokulandelelana, ivelisa imisebenzi yangaphakathi ye-Qemu, leyo i-TCG (i-Tiny Code Generator) esele ijike ibe yikhowudi yomatshini wolwakhiwo lwe-host host. Njengoko kuchaziwe kwifayile ye-readme ebekwe kulawulo lwe-tcg, le ekuqaleni yayiyinxalenye ye-C compiler eqhelekileyo, eyathi kamva yalungiselelwa iJIT. Ngoko ke, umzekelo, ulwakhiwo olujoliswe kuyo ngokwemigaqo yolu xwebhu ayiselulo ulwakhiwo lweendwendwe, kodwa lulwakhiwo lwenginginya. Ngexesha elithile, elinye icandelo lavela - i-Tiny Code Interpreter (TCI), ekufuneka iqhube ikhowudi (phantse imisebenzi efanayo yangaphakathi) ngokungabikho kwejeneretha yekhowudi ye-architecture ethile yomkhosi. Enyanisweni, njengoko uxwebhu lwayo luchaza, le toliki ayinakuhlala iqhuba kakuhle kunye ne-JIT code generator, kungekhona nje ngokomlinganiselo wesantya, kodwa nangomgangatho. Nangona andiqinisekanga ukuba inkcazo yakhe ifanelekile ngokupheleleyo.

Ekuqaleni ndazama ukwenza i-backend ye-TCG epheleleyo, kodwa ngokukhawuleza ndadideka kwikhowudi yomthombo kunye nenkcazo engacacanga ngokupheleleyo yemiyalelo ye-bytecode, ngoko ndagqiba ekubeni ndisonge i-TCI itoliki. Oku kwanika iingenelo ezininzi:

  • xa uphumeza ikhowudi generator, awukwazi ukujonga inkcazo yemiyalelo, kodwa kwikhowudi yetoliki
  • ungavelisa imisebenzi hayi kwibhloko nganye yoguqulelo odibene nayo, kodwa, umzekelo, kuphela emva kophumezo lwekhulu
  • ukuba ikhowudi evelisiweyo iyatshintsha (kwaye oku kubonakala ngathi kuyenzeka, ukugweba ngemisebenzi enamagama aqulathe isiziba segama), ndiya kufuna ukuyenza ingasebenzi ikhowudi ye-JS eyenziweyo, kodwa noko ndiza kuba nento yokuphinda ndiyivelise kwakhona.

Ngokumalunga nenqaku lesithathu, andiqinisekanga ukuba ukupakisha kunokwenzeka emva kokuba ikhowudi iqhutywe okokuqala, kodwa amanqaku amabini okuqala anele.

Ekuqaleni, ikhowudi yaveliswa ngendlela yokutshintsha okukhulu kwidilesi yomyalelo we-bytecode yasekuqaleni, kodwa emva koko, ukukhumbula inqaku malunga ne-Emscripten, ukulungelelaniswa kwe-JS eveliswayo kunye ne-relooping, ndagqiba ekubeni ndivelise ikhowudi yabantu abaninzi, ngakumbi ekubeni i-empirically it. kwavela ukuba ekuphela kwendawo yokungena kwibhloko yokuguqulela kukuQala kwayo. Kungekudala, emva kwexesha sinejeneretha yekhowudi eyenza ikhowudi kunye ne-ifs (nangona ngaphandle kwee-loops). Kodwa ilishwa, yawa, inika umyalezo wokuba imiyalelo yayinobude obungachanekanga. Ngaphezu koko, umyalelo wokugqibela kweli nqanaba lokuphindaphinda wawu brcond. Kulungile, ndiza kongeza itshekhi efanayo kwisizukulwana salo myalelo ngaphambi nangemva kokufowuna okuphindaphindiweyo kwaye ... akukho namnye kubo oye wabulawa, kodwa emva kokutshintshwa kwe-assert baye bahluleka. Ekugqibeleni, emva kokufunda ikhowudi eyenziwe, ndaqonda ukuba emva kokutshintsha, isalathisi kumyalelo wangoku silayishwa kwakhona kwi-stack kwaye mhlawumbi ibhalwe kwikhowudi yeJavaScript eyenziwe. Kwaye kwaba njalo. Ukwandisa i-buffer ukusuka kwi-megabyte enye ukuya kwishumi akuzange kukhokelele nantoni na, kwaye kwacaca ukuba i-code generator yayisebenza kwizangqa. Kwafuneka sijonge ukuba asigqithanga ngaphaya kwemida ye-TB ekhoyo, kwaye ukuba siyenzile, ngoko ke sikhuphe idilesi ye-TB elandelayo enophawu lokuthabatha ukuze siqhubeke sibulawa. Ukongeza, oku kusombulula ingxaki "yeyiphi imisebenzi eyenziweyo ekufuneka ingasebenzi ukuba le nxalenye ye-bytecode itshintshile?" β€” kuphela umsebenzi ohambelana nale bloko yokuguqulela ekufuneka ingasebenzi. Ngendlela, nangona ndilungisa yonke into kwiChromium (ekubeni ndisebenzisa iFirefox kwaye kulula ukuba ndisebenzise isikhangeli esahlukileyo sovavanyo), iFirefox yandinceda ukulungisa ukungahambelani nomgangatho we-asm.js, emva koko ikhowudi yaqala ukusebenza ngokukhawuleza I-Chromium.

Umzekelo wekhowudi eyenziweyo

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"]

isiphelo

Ngoko ke, umsebenzi awukagqitywa, kodwa ndidiniwe ukuzisa ngokufihlakeleyo olu lwakhiwo lwexesha elide kwimfezeko. Ngoko ke, ndigqibe ekubeni ndipapashe oko ndinako ngoku. Ikhowudi iyinto encinci eyoyikisayo kwiindawo, kuba oku kuvavanyo, kwaye akucaci kwangaphambili ukuba yintoni ekufuneka yenziwe. Mhlawumbi, ke kufanelekile ukukhupha izibophelelo eziqhelekileyo zeathomu ngaphezulu kolunye uhlobo lwangoku lweQemu. Okwangoku, kukho intambo kwi-Gita kwifomathi yeblogi: "kwinqanaba" ngalinye eliye ladlula ngandlela-thile, inkcazo ecacileyo ngesiRashiya yongezwa. Enyanisweni, eli nqaku kumlinganiselo omkhulu lichaza kwakhona isiphelo git log.

Ungazama konke apha (zilumkele izithuthi).

Yintoni esele isebenza:

  • x86 iprosesa enenyani esebenzayo
  • Kukho iprototype esebenzayo yeJIT code generator ukusuka kwikhowudi yomatshini ukuya kwiJavaScript
  • Kukho itemplate yokuhlanganisa ezinye ii-32-bit zezakhiwo zeendwendwe: ngoku ungayithanda i-Linux yolwakhiwo lwe-MIPS olubanda kwisikhangeli kwinqanaba lokulayisha.

Yintoni enye onokuyenza

  • Ukukhawulezisa ukulinganisa. Nakwimowudi yeJIT ibonakala ihamba kade kune-x86 ebonakalayo (kodwa kukho iQemu epheleleyo enezixhobo ezininzi ezilinganisiweyo kunye noyilo lwezakhiwo)
  • Ukwenza ujongano oluqhelekileyo- ngokungafihlisiyo, andinguye umakhi wewebhu olungileyo, okwangoku ndiyenzile iqokobhe le-Emscripten elisemgangathweni kangangoko ndinako.
  • Zama ukuqalisa imisebenzi ye-Qemu entsonkothileyo - uthungelwano, ukufuduka kweVM, njl.
  • IUPS: Kuya kufuneka ungenise uphuhliso lwakho olumbalwa kunye neengxelo zebug ku-Emscripten phezulu, njengoko abathwali bangaphambili beQemu kunye nezinye iiprojekthi benzayo. Enkosi kubo ngokukwazi ukusebenzisa igalelo labo kwi-Emscripten njengenxalenye yomsebenzi wam.

umthombo: www.habr.com

Yongeza izimvo