I-Qemu.js ngokusekelwa kwe-JIT: usengabuyisela i-mince emuva

Eminyakeni embalwa edlule uFabrice Bellard ibhalwe ngu-jslinux iyisimulator ye-PC ebhalwe nge-JavaScript. Ngemva kwalokho kwaba khona okungenani okwengeziwe I-Virtual x86. Kodwa bonke, ngokwazi kwami, babengabahumushi, kuyilapho u-Qemu, ebhalwe ngaphambili kakhulu nguFabrice Bellard ofanayo, futhi, mhlawumbe, nanoma yimuphi umlingisi wesimanje ozihloniphayo, usebenzisa ukuhlanganiswa kwe-JIT yekhodi yesivakashi ibe ikhodi yesistimu yokusingatha. Kimina kwabonakala sengathi kwase kuyisikhathi sokwenza umsebenzi ophambene maqondana nalowo oxazululwa yiziphequluli: Ukuhlanganiswa kwe-JIT yekhodi yomshini ibe yi-JavaScript, okwabonakala kunengqondo kakhulu ukuthungatha i-Qemu. Kungase kubonakale, kungani i-Qemu, kukhona ama-emulators alula futhi asebenziseka kalula - i-VirtualBox efanayo, isibonelo - efakiwe futhi isebenza. Kodwa uQemu unezici ezimbalwa ezithokozisayo

  • umthombo ovulekile
  • ikhono lokusebenza ngaphandle komshayeli we-kernel
  • ikhono lokusebenza kwimodi yomtoliki
  • ukusekelwa kwenani elikhulu lakho kokubili i-host host kanye ne-architecture yesivakashi

Ngokuphathelene nephuzu lesithathu, manje sengingakwazi ukuchaza ukuthi empeleni, kumodi ye-TCI, akuyona imiyalelo yomshini wezivakashi ngokwayo ehunyushwa, kodwa i-bytecode etholwe kubo, kodwa lokhu akushintshi ingqikithi - ukuze kwakhiwe futhi kusebenze. I-Qemu ekwakhiweni okusha, uma unenhlanhla, i-A C compiler yanele - ukubhala i-code generator kungahlehliswa.

Futhi manje, ngemva kweminyaka emibili yokuzilibazisa ngekhodi yomthombo we-Qemu ngesikhathi sami samahhala, kwavela i-prototype esebenzayo, lapho usuvele ugijima khona, isibonelo, i-Kolibri OS.

Yini i-Emscripten

Namuhla, abahlanganisi abaningi baye bavela, umphumela wokugcina yiJavaScript. Ezinye, njenge-Type Script, zayihloselwe ukuthi zibe indlela engcono kakhulu yokubhalela iwebhu. Ngesikhathi esifanayo, i-Emscripten iyindlela yokuthatha ikhodi ekhona ye-C noma i-C++ bese uyihlanganisa ibe ifomu elifundeka isiphequluli. Vuliwe leli khasi Siqoqe izikebhe eziningi zezinhlelo ezaziwayo: laphaIsibonelo, ungabheka i-PyPy - ngendlela, bathi sebenayo kakade i-JIT. Eqinisweni, akuzona zonke izinhlelo ezingase zihlanganiswe futhi zisebenze kusiphequluli - kukhona inombolo izici, okufanele ubekezele, nokho, njengoba umbhalo osekhasini elifanayo uthi “I-Emscripten ingasetshenziselwa ukuhlanganisa cishe noma yikuphi eziphathwayo C/C++ ikhodi ye-JavaScript". Okusho ukuthi, kunenombolo yemisebenzi engachazwanga ukuziphatha ngokwezinga, kodwa ngokuvamile isebenza ku-x86 - isibonelo, ukufinyelela okungahleliwe kokuguquguqukayo, okuvamise ukunqatshelwa kwezinye izakhiwo. Ngokuvamile , i-Qemu iwuhlelo lwe-cross-platform futhi, bengifuna ukukholelwa, futhi ayikuqukethe ukuziphatha okuningi okungachazwanga - kuthathe futhi ukuhlanganise, bese ucubungula kancane nge-JIT - futhi usuqedile! icala...

Zama kuqala

Ngokuvamile, angiyena umuntu wokuqala oza nombono wokuthumela u-Qemu ku-JavaScript. Kube nombuzo obuzwe kuforamu ye-ReactOS uma lokhu kungenzeka kusetshenziswa i-Emscripten. Ngisho nangaphambili, kwakukhona amahemuhemu okuthi u-Fabrice Bellard wenze lokhu mathupha, kodwa sasikhuluma nge-jslinux, lokho, ngokwazi kwami, kuwumzamo nje wokufeza ukusebenza okwanele ku-JS, futhi yabhalwa kusukela ekuqaleni. Kamuva, kwabhalwa i-Virtual x86 - imithombo engacacile yathunyelwa ngayo, futhi, njengoba kushiwo, "iqiniso" elikhulu lokulingisa lenze kwaba nokwenzeka ukusebenzisa i-SeaBIOS njenge-firmware. Ngaphezu kwalokho, kube khona okungenani umzamo owodwa wokuthungatha u-Qemu usebenzisa i-Emscripten - ngizamile ukwenza lokhu i-socketpair, kodwa intuthuko, ngokuqonda kwami, yaba yiqhwa.

Ngakho-ke, kubonakala sengathi, nansi imithombo, nansi i-Emscripten - ithathe futhi uyihlanganise. Kodwa kukhona nemitapo yolwazi uQemu ancike kuyo, kanye nemitapo yolwazi leyo mitapo yolwazi, njll., kanti omunye wayo ngu libfi, okuyinto i-glib encike kuyo. Bekunamahemuhemu ku-inthanethi okuthi bekukhona eyodwa eqoqweni elikhulu lamachweba wemitapo yolwazi ye-Emscripten, kodwa kwakunzima ngandlela thize ukukholelwa: okokuqala, bekungahlosiwe ukuba kube umdidiyeli omusha, okwesibili, bekusezingeni eliphansi kakhulu. umtapo wolwazi ongavele uwuthathe, bese uhlanganisela ku-JS. Futhi akuyona nje indaba yokufakwa komhlangano - mhlawumbe, uma ukusonta, kwezinye izingqungquthela zokushaya ungakhiqiza izimpikiswano ezidingekayo esitakini bese ubiza umsebenzi ngaphandle kwazo. Kepha i-Emscripten iyinto ekhohlisayo: ukuze wenze ikhodi ekhiqiziwe ibukeke ijwayelekile kusiphequluli se-JS injini optimizer, kusetshenziswa amaqhinga athile. Ikakhulukazi, lokho okubizwa ngokuthi i-relooping - ijeneretha yekhodi esebenzisa i-LLVM IR eyamukelwe enemiyalo ethile yenguquko engabonakali izama ukuphinda idale ama-ifs azwakalayo, amalophu, njll. Hhayi-ke, izimpikiswano zidluliselwa kanjani emsebenzini? Ngokwemvelo, njengezimpikiswano zemisebenzi ye-JS, okungukuthi, uma kungenzeka, hhayi ngesitaki.

Ekuqaleni kwakunombono wokuthi ngimane ngibhale esikhundleni se-libffi nge-JS futhi ngiqhube izivivinyo ezijwayelekile, kodwa ekugcineni ngadideka mayelana nendlela yokwenza amafayela ami kanhlokweni ukuze asebenze nekhodi ekhona - yini engingayenza, njengoba bethi, "Ingabe imisebenzi iyinkimbinkimbi "Ingabe siyiziphukuphuku?" Kwadingeka ngithumele i-libffi kwenye i-architecture, ngakho-ke ukukhuluma - ngenhlanhla, i-Emscripten inawo womabili ama-macros omhlangano ongaphakathi (ku-Javascript, yebo - kahle, noma yikuphi ukwakheka, ngakho-ke umhlanganisi), kanye nekhono lokusebenzisa ikhodi ekhiqizwa endizeni. Ngokuvamile, ngemva kokucubungula ngezingcezu ze-libffi ezincike epulatifomu isikhathi esithile, ngathola ikhodi ehlanganisiwe futhi ngayiqhuba esivivinyweni sokuqala engahlangana naso. Ngamangala lapho uvivinyo lwaphumelela. Ngimangazwe ubuhlakani bami - alikho ihlaya, kusebenze kusukela ekuqalisweni kokuqala - mina, ngingakawakholwa amehlo ami, ngahamba ngayobheka ikhodi ewumphumela futhi, ukuze ngihlole ukuthi ngimbe kuphi ngokulandelayo. Lapha ngike ngaphuma amantongomane okwesibili - okuwukuphela kwento engiyenzile kwaba ffi_call - lokhu kubike ikholi eyimpumelelo. Alukho ucingo ngokwalo. Ngakho ngithumele isicelo sami sokuqala sokudonsa, esalungisa iphutha esivivinyweni elicace kunoma yimuphi umfundi we-Olympiad - izinombolo zangempela akufanele ziqhathaniswe a == b futhi kanjani a - b < EPS - udinga futhi ukukhumbula imojula, ngaphandle kwalokho u-0 uzolingana kakhulu no-1/3 ... Ngokuvamile, ngiqhamuke nechweba elithile le-libffi, elidlula izivivinyo ezilula, futhi iyiphi i-glib ekhona. kuhlanganiswe - nginqume ukuthi kuzodingeka, ngizokwengeza kamuva. Uma ngibheka phambili, ngizosho ukuthi, njengoba kwavela, umdidiyeli akazange afake ngisho nomsebenzi we-libffi kukhodi yokugcina.

Kodwa, njengoba ngishilo kakade, kukhona ukulinganiselwa, futhi phakathi kokusetshenziswa kwamahhala kokuziphatha okuhlukahlukene okungachazwanga, isici esingathandeki kakhulu sifihliwe - i-JavaScript ngokuklama ayisekeli ukufundwa okuningiliziwe ngememori eyabiwe. Empeleni, lokhu ngokuvamile kungabizwa ngisho nombono omuhle, kodwa hhayi ngekhodi yokuthwala ukwakheka kwayo kuhlanganiswe nezintambo zika-C. Ngokuvamile, iFirefox izama ukusekela izisebenzi ezabiwe, futhi i-Emscripten inokusebenzisa i-pthread kubo, kodwa bengingafuni ukuncika kuyo. Kwadingeka ngikhiphe kancane kancane ukufunda okuningi kusuka kukhodi ye-Qemu - okungukuthi, ngithole ukuthi izintambo zisebenza kuphi, ngihambise umzimba weluphu egijima kulo ntambo ngiyenze umsebenzi ohlukile, bese ngibiza imisebenzi enjalo ngayinye ngayinye ukusuka ku-loop eyinhloko.

Zama okwesibili

Ngesinye isikhathi, kwacaca ukuthi inkinga isekhona, nokuthi ukusunduza ngokunganaki izinduku eduze kwekhodi ngeke kuholele kunoma iyiphi into enhle. Isiphetho: sidinga ukuthi ngandlela thize sihlele inqubo yokwengeza izinduku. Ngakho-ke, inguqulo 2.4.1, eyayintsha ngaleso sikhathi, yathathwa (hhayi 2.5.0, ngoba, ngubani owaziyo, kuzoba nezimbungulu enguqulweni entsha ezingakabanjwa, futhi nginezimbungulu ezanele ), futhi into yokuqala kwakuwukubhala kabusha ngokuphepha thread-posix.c. Nokho, okungukuthi, njengoba kuphephile: uma othile ezama ukwenza ukuhlinzwa okuholela ekuvimbeni, umsebenzi wabizwa ngokushesha abort() - Yebo, lokhu akuzange kuxazulule zonke izinkinga ngesikhathi esisodwa, kodwa okungenani kwakumnandi ngandlela-thile kunokwamukela buthule idatha engahambisani.

Ngokuvamile, izinketho ze-Emscripten ziwusizo kakhulu ekuthumeleni ikhodi ku-JS -s ASSERTIONS=1 -s SAFE_HEAP=1 - babamba ezinye izinhlobo zokuziphatha okungachazwanga, okufana nezingcingo eziya ekhelini elingahlelekile (elingahambisani nhlobo nekhodi yamalungu afanayo athayiphiwe njenge HEAP32[addr >> 2] = 1) noma ukushayela umsebenzi ngenombolo engalungile yezimpikiswano.

Ngendlela, amaphutha okuqondanisa ayindaba ehlukile. Njengoba bese ngishilo, u-Qemu une-backend yokutolika “ewohlokayo” yokwenza ikhodi i-TCI (umhumushi wekhodi omncane), kanye nokwakha nokusebenzisa i-Qemu esakhiweni esisha, uma unenhlanhla, i-C compiler yanele. Amagama angukhiye "uma unenhlanhla". Ngibe neshwa, futhi kwavela ukuthi i-TCI isebenzisa ukufinyelela okungahleliwe lapho ihlaziya i-bytecode yayo. Okungukuthi, kuzo zonke izinhlobo ze-ARM nezinye izakhiwo ezinokufinyelela okulinganiselwe, i-Qemu ihlanganisa ngoba ine-backend evamile ye-TCG ekhiqiza ikhodi yomdabu, kodwa ukuthi i-TCI izosebenza yini kuwo omunye umbuzo. Kodwa-ke, njengoba kwavela, imibhalo ye-TCI ikhombise ngokusobala into efanayo. Njengomphumela, izingcingo zokusebenza zokufunda okungahleliwe zengezwe kukhodi, ezitholwe kwenye ingxenye ye-Qemu.

Ukubhujiswa kwenqwaba

Ngenxa yalokho, ukufinyelela okungahleliwe ku-TCI kwalungiswa, kwadalwa iluphu eyinhloko leyo yona ebizwa ngokuthi iprosesa, i-RCU nezinye izinto ezincane. Futhi ngakho ngethula i-Qemu ngenketho -d exec,in_asm,out_asm, okusho ukuthi udinga ukusho ukuthi yimaphi amabhlogo wekhodi asetshenziswayo, futhi nangesikhathi sokusakazwa ukuze ubhale ukuthi yayiyini ikhodi yesivakashi, iyiphi ikhodi yosokhaya (kulokhu, i-bytecode). Iqala, yenze amabhulokhi ambalwa wokuhumusha, ibhale umlayezo wokususa iphutha engiwushiye wokuthi i-RCU manje isizoqala futhi... iphahlazeke abort() ngaphakathi komsebenzi free(). Ngokucubungula ngomsebenzi free() Sikwazile ukuthola ukuthi kunhlokweni yebhulokhi yenqwaba, etholakala kumabhayithi ayisishiyagalombili andulela inkumbulo eyabelwe, esikhundleni sosayizi webhulokhi noma into efanayo, bekunodoti.

Ukubhujiswa kwenqwaba - kuhle kangakanani... Esimeni esinjalo, kukhona ikhambi eliwusizo - kusuka (uma kungenzeka) emithonjeni efanayo, hlanganisa kanambambili yomdabu bese uyiqhuba ngaphansi kwe-Valgrind. Ngemva kwesikhathi esithile, kanambambili isilungile. Ngiyethula ngezinketho ezifanayo - iyaphahlazeka ngisho nangesikhathi sokuqalisa, ngaphambi kokufinyelela ekusebenzeni. Akujabulisi, yiqiniso - ngokusobala, imithombo ibingafani ncamashi, okungamangazi, ngoba lungiselela izinketho ezihlukile, kepha ngineValgrind - okokuqala ngizolungisa lesi bug, bese, uma nginenhlanhla. , eyokuqala izovela. Ngisebenzisa into efanayo ngaphansi kwe-Valgrind ... Y-y-y, y-y-y, uh-uh, iqalile, yadlula ekuqaliseni ngokujwayelekile futhi yadlulela ku-bug yasekuqaleni ngaphandle kwesixwayiso esisodwa mayelana nokufinyelela kwememori okungalungile, ingasaphathwa ngokuwa. Impilo, njengoba besho, ayizange ingilungiselele lokhu - uhlelo oluqhumayo luyayeka ukuphahlazeka lapho lwethulwa ngaphansi kwe-Walgrind. Ukuthi bekuyini kuyimfihlakalo. I-hypothesis yami iwukuthi kanye endaweni yomyalelo wamanje ngemva kokuphahlazeka ngesikhathi sokuqalisa, i-gdb ibonise umsebenzi. memset-a ngesikhombi esisebenzayo usebenzisa noma yikuphi mmx, noma xmm amarejista, khona-ke mhlawumbe bekuwuhlobo oluthile lwephutha lokuqondanisa, nakuba kusenzima ukukukholelwa.

Kulungile, u-Valgrind akabonakali engasiza lapha. Futhi lapha into enyanyekayo kakhulu yaqala - yonke into ibonakala iqala, kodwa iphahlazeka ngenxa yezizathu ezingaziwa ngokuphelele ngenxa yomcimbi owawungenzeka izigidi zemiyalelo edlule. Kwaphela isikhathi eside kungacaci ukuthi kumele kuqhamuke kanjani. Ekugcineni, kwakusadingeka ngihlale phansi ngilungise iphutha. Ukuphrinta lokho unhlokweni owawubhalwe kabusha ngakho kwabonisa ukuthi akubukeki njengenombolo, kodwa kunalokho uhlobo oluthile lwedatha kanambambili. Futhi, bheka futhi, le ntambo kanambambili itholwe efayeleni le-BIOS - okungukuthi, manje kwakungenzeka ukusho ngokuqiniseka okunengqondo ukuthi kwakuyi-buffer echichimayo, futhi kucace ngisho nokuthi yabhalwa kule buffer. Nokho, khona-ke into enjengale - ku-Emscripten, ngenhlanhla, akukho okungahleliwe kwesikhala sekheli, azikho izimbobo kuso noma, ukuze ukwazi ukubhala endaweni ethile phakathi kwekhodi ukuze ukhiphe idatha nge-pointer kusukela ekuqalisweni kokugcina, bheka idatha, bheka i-pointer, futhi, uma ingashintshile, thola ukudla okucabangayo. Yiqiniso, kuthatha imizuzu embalwa ukuxhuma ngemva kwanoma yiluphi ushintsho, kodwa yini ongayenza? Ngenxa yalokho, kwatholakala umugqa othize okopishe i-BIOS kusuka kusigcinalwazi sesikhashana kuya kumemori yesivakashi - futhi, ngempela, sasingekho isikhala esanele ku-buffer. Ukuthola umthombo walelo kheli lebhafa elingajwayelekile kuphumele emsebenzini qemu_anon_ram_alloc kufayela oslib-posix.c - umqondo owawukhona wawulokhu: ngezinye izikhathi kungaba usizo ukuvumelanisa ikheli nekhasi elikhulu lika-2 MB ngosayizi, kulokhu sizokubuza mmap okokuqala kancane, bese sizobuyisela okweqile ngosizo munmap. Futhi uma ukulungiswa okunjalo kungadingeki, khona-ke sizobonisa umphumela esikhundleni se-2 MB getpagesize() - mmap isazonikeza ikheli eliqondanisiwe... Ngakho ku-Emscripten mmap izingcingo nje malloc, kodwa vele ayihambisani nekhasi. Ngokuvamile, iphutha elangikhungathekisa izinyanga ezimbalwa lalungiswa ngokushintsha двух imigqa.

Izici zemisebenzi yokubiza

Futhi manje iphrosesa ibala okuthile, i-Qemu ayiphahlazeki, kodwa isikrini asivuli, futhi iphrosesa ingena ngokushesha kuma-loops, ihlulela ngokuphumayo. -d exec,in_asm,out_asm. I-hypothesis isivele: ukuphazamisa isikhathi (noma, ngokuvamile, konke ukuphazamiseka) akufiki. Futhi ngempela, uma ukhulula iziphazamiso ezivela emhlanganweni wendabuko, okwasebenza ngesizathu esithile, uthola isithombe esifanayo. Kodwa lena kwakungeyona impendulo nhlobo: ukuqhathaniswa kwemikhondo ekhishwe nenketho engenhla kubonise ukuthi izindlela zokubulala zahlukana kusenesikhathi. Lapha kufanele kushiwo ukuthi ukuqhathanisa lokho okuqoshwe kusetshenziswa isiqalisi emrun okukhiphayo kokususa iphutha ngokukhiphayo komhlangano womdabu akuyona inqubo yomshini ngokuphelele. Angazi kahle ukuthi uhlelo olusebenza kusiphequluli luxhumeka kanjani emrun, kodwa eminye imigqa kokuphumayo iphenduka ihlelwe kabusha, ngakho-ke umehluko ku-diff awukabi isizathu sokucabanga ukuthi ama-trajectories ahlukene. Ngokuvamile, kwacaca ukuthi ngokusho imiyalelo ljmpl kukhona ukushintshela kumakheli ahlukene, futhi i-bytecode ekhiqizwayo ihluke ngokuyisisekelo: eyodwa iqukethe umyalelo wokubiza umsebenzi womsizi, enye ayinawo. Ngemuva kokungena imiyalo nokufunda ikhodi ehumusha le miyalo, kwacaca ukuthi, okokuqala, ngaphambi nje kwayo kurejista. cr0 kwaqoshwa - futhi kusetshenziswa umsizi - owashintsha iphrosesa kumodi evikelekile, futhi okwesibili, ukuthi inguqulo ye-js ayizange ishintshele kumodi evikelekile. Kodwa iqiniso liwukuthi esinye isici se-Emscripten ukungabaza kwayo ukubekezelela ikhodi njengokusebenzisa imiyalelo. call ku-TCI, lapho noma yisiphi isikhombisi somsebenzi siphumela ohlotsheni long long f(int arg0, .. int arg9) - imisebenzi kumele ibizwe ngenani elifanele lama-agumenti. Uma lo mthetho wephulwa, kuye ngezilungiselelo zokususa iphutha, uhlelo luzophahlazeka (oluhle) noma lubize umsebenzi ongalungile nhlobo (okuzoba lusizi ukulungisa iphutha). Kukhona futhi inketho yesithathu - vumela isizukulwane se-wrappers engeza / esusa izingxabano, kodwa sezizonke lezi zigoqa zithatha isikhala esiningi, naphezu kweqiniso lokuthi empeleni ngidinga kuphela ama-wrappers angaphezu kwekhulu. Lokhu kukodwa kudabukisa kakhulu, kodwa kube nenkinga enkulu kakhulu: kukhodi ekhiqiziwe yemisebenzi ye-wrapper, izimpikiswano zaguqulwa futhi zaguqulwa, kodwa ngezinye izikhathi umsebenzi ngezingxabano ezikhiqiziwe awuzange ubizwe - kahle, njengaku ukuqaliswa kwami ​​​​kwe-libffi. Okusho ukuthi, abanye abasizi ababulawanga.

Ngenhlanhla, u-Qemu unohlu lwabasizi abangafundwa ngomshini ngendlela yefayela elingasekhanda njenge

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

Asetshenziswa ngokuhlekisayo: okokuqala, ama-macros achazwa kabusha ngendlela eyinqaba kakhulu DEF_HELPER_n, bese ivula helper.h. Ngokwezinga lapho i-macro inwetshwa khona ibe isiqalisi sesakhiwo kanye nokhefana, bese kuchazwa uhlu, futhi esikhundleni sezakhi - #include <helper.h> Ngenxa yalokho, ekugcineni ngathola ithuba lokuzama umtapo wezincwadi emsebenzini i-pyparsing, futhi kwabhalwa umbhalo okhiqiza lawo ma-wrappers ncamashi imisebenzi adingeka kuwo.

Futhi-ke, ngemva kwalokho iprosesa yabonakala isebenza. Kubonakala sengathi isikrini asizange siqaliswe, nakuba i-memtest86+ ikwazile ukusebenza kumhlangano womdabu. Lapha kuyadingeka ukucacisa ukuthi ikhodi ye-Qemu block I / O ibhalwe kuma-coroutines. I-Emscripten inokuqaliswa kwayo okukhohlisayo, kodwa isadinga ukusekelwa kukhodi ye-Qemu, futhi ungakwazi ukulungisa iphutha manje iphrosesa: I-Qemu isekela izinketho. -kernel, -initrd, -append, ongaqalisa ngayo i-Linux noma, isibonelo, i-memtest86+, ngaphandle kokusebenzisa nhlobo amadivaysi e-block. Kepha nansi inkinga: emhlanganweni wendabuko umuntu angabona ukuphuma kwe-Linux kernel kukhonsoli ngenketho -nographic, futhi akukho okukhiphayo kusuka kusiphequluli kuya kutheminali kusukela lapho yethulwe khona emrun, akafikanga. Okusho ukuthi, akucaci: iprosesa ayisebenzi noma okukhiphayo kwehluzo akusebenzi. Kwabe sekufika kimina ukuthi ngime kancane. Kuvele ukuthi "iprosesa ayilali, kodwa icwayiza kancane," futhi ngemuva kwemizuzu emihlanu i-kernel yaphonsa inqwaba yemiyalezo kukhonsoli futhi yaqhubeka nokulenga. Kwacaca ukuthi iphrosesa, ngokuvamile, iyasebenza, futhi sidinga ukumba ikhodi yokusebenza nge-SDL2. Ngeshwa, angazi ukuthi ngiwusebenzisa kanjani lo mtapo wolwazi, ngakho kwezinye izindawo kwakudingeka ngenze okungahleliwe. Ngesinye isikhathi, umugqa u-parallel0 wawukhanya esikrinini kungemuva eliluhlaza okwesibhakabhaka, okuphakamisa imicabango ethile. Ekugcineni, kwavela ukuthi inkinga ukuthi i-Qemu ivula amafasitela ambalwa abonakalayo efasiteleni elilodwa elingokwenyama, ongashintsha phakathi kwalo usebenzisa i-Ctrl-Alt-n: isebenza ekwakhiweni kwendabuko, kodwa hhayi ku-Emscripten. Ngemuva kokuqeda amafasitela angadingekile usebenzisa izinketho -monitor none -parallel none -serial none kanye nemiyalelo yokudweba kabusha isikrini ngenkani kufreyimu ngayinye, yonke into yasebenza kungazelelwe.

Ama-Coroutines

Ngakho-ke, ukulingisa esipheqululini kuyasebenza, kepha awukwazi ukusebenzisa noma yini ethokozisayo ye-floppy eyodwa kuyo, ngoba ayikho i-block I/O - udinga ukusebenzisa ukwesekwa kwama-coroutines. I-Qemu isivele inama-backends ambalwa e-coroutine, kodwa ngenxa yemvelo ye-JavaScript kanye ne-Emscripten code generator, awukwazi ukuvele uqale ukuhlanganisa izitaki. Kungase kubonakale sengathi "konke kuhambile, ukhonkolo uyasuswa," kodwa abathuthukisi be-Emscripten sebevele banakekele yonke into. Lokhu kusetshenziswa okuhlekisayo: ake sibize ucingo lomsebenzi olufana nalolu olusolisayo emscripten_sleep kanye nabanye abambalwa abasebenzisa indlela ye-Asyncify, kanye nezingcingo zesikhombi namakholi kunoma yimuphi umsebenzi lapho enye yezimo ezimbili zangaphambilini ingase yenzeke ngokuqhubekayo phansi kwesitaki. Futhi manje, ngaphambi kocingo ngalunye olusolisayo, sizokhetha umongo we-async, futhi ngokushesha ngemva kocingo, sizohlola ukuthi ingabe ikholi e-asynchronous yenzekile, futhi uma kwenzekile, sizogcina zonke izinto eziguquguqukayo zendawo kulo mongo we-async, sibonise ukuthi yimuphi umsebenzi. ukuze sidlulisele ukulawula lapho sidinga ukuqhubeka nokusebenzisa , futhi siphume emsebenzini wamanje. Lapha yilapho kunobubanzi bokufunda umphumela ukumosha - ngezidingo zokuqhubeka nokwenziwa kwekhodi ngemuva kokubuya ocingweni olungavumelani, umhlanganisi ukhiqiza "ama-stubs" omsebenzi aqala ngemva kocingo olusolisayo - kanje: uma kukhona izingcingo ezi-n ezisolisayo, umsebenzi uzokwandiswa ndawana thize n/2 izikhathi — lokhu kusenjalo, uma kungenjalo Khumbula ukuthi ngemva kocingo ngalunye olungavumelanisi, udinga ukwengeza ukulondoloza okuguquguqukayo kwasendaweni kumsebenzi wokuqala. Kamuva, kwadingeka ngibhale umbhalo olula ku-Python, okuthi, ngokusekelwe kusethi enikeziwe yemisebenzi esetshenziswe ngokweqile okuthiwa "ayivumeli i-asynchrony ukuba idlule ngokwayo" (okungukuthi, ukukhushulwa kwe-stack nakho konke engisanda kukuchaza. sebenza kuzo), ikhombisa izingcingo ngokusebenzisa izikhombi lapho imisebenzi kufanele inganakwa ngumqambi ukuze le misebenzi ingathathwa njenge-asynchronous. Futhi-ke amafayela e-JS angaphansi kuka-60 MB ngokusobala maningi kakhulu - ake sithi okungenani 30. Nakuba, ngake ngamisa umbhalo womhlangano, futhi ngephutha ngalahla izinketho zokuxhumanisa, phakathi kwazo okwakukhona. -O3. Ngisebenzisa ikhodi ekhiqiziwe, futhi i-Chromium idla inkumbulo nokuphahlazeka. Ngabe sengibheka ngephutha ukuthi yini abezama ukuyilanda... Hhayi-ke, ngingathini, nami ngabe ngiqandisiwe ukube bengicelwe ukuthi ngifunde ngokucophelela futhi ngigcwalise i-Javascript engu-500+ MB.

Ngeshwa, amasheke kukhodi yelabhulali yosekelo ye-Asyncify ayengenabo ubungane ngokuphelele longjmp-ezisetshenziswa kukhodi yephrosesa ebonakalayo, kodwa ngemva kwesiqeshana esincane esikhubaza lokhu kuhlola futhi sibuyisele ngokunamandla okuqukethwe sengathi konke kuhamba kahle, ikhodi isebenzile. Futhi-ke into engavamile yaqala: ngezinye izikhathi amasheke kukhodi yokuvumelanisa aqalwa - lawo afanayo aphahlaza ikhodi uma, ngokusho komqondo wokwenza, kufanele ivinjwe - othile uzame ukubamba isimungulu esivele sithunjiwe. Ngenhlanhla, lokhu akuzange kube yinkinga enengqondo kukhodi ye-serialized - bengimane ngisebenzisa ukusebenza kwe-loop okujwayelekile okuhlinzekwa yi-Emscripten, kodwa ngezinye izikhathi ucingo olungavumelanisiwe lwaluvula ngokuphelele isitaki, futhi ngaleso sikhathi lwalungeke lwehluleke. setTimeout kusukela ku-loop eyinhloko - ngaleyo ndlela, ikhodi ifake i-loop iteration eyinhloko ngaphandle kokushiya i-iteration yangaphambilini. Bhala kabusha ku-loop engapheli futhi emscripten_sleep, futhi izinkinga ngezimumu zanqamuka. Ikhodi isize yaba nokunengqondo nakakhulu - ngemva kwakho konke, empeleni, anginayo ikhodi ethile elungiselela uhlaka olulandelayo lokugqwayiza - iphrosesa ivele ibale okuthile futhi isikrini sibuyekezwa ngezikhathi ezithile. Nokho, izinkinga azigcinanga lapho: ngezinye izikhathi ukubulawa kuka-Qemu kwakuvele kuphele buthule ngaphandle kokuhlukile noma amaphutha. Ngaleso sikhathi ngiyekile, kodwa, ngibheka phambili, ngizothi inkinga yayiwukuthi: ikhodi ye-coroutine, empeleni, ayisebenzisi. setTimeout (noma okungenani hhayi kaningi njengoba ungase ucabange): umsebenzi emscripten_yield umane usetha ifulegi lekholi elingavumelaniyo. Iphuzu lonke liwukuthi emscripten_coroutine_next akuwona umsebenzi ongavumelanisi: ngaphakathi ihlola ifulegi, ilisethe kabusha futhi idlulisele ukulawula lapho idingeka khona. Okusho ukuthi, ukukhushulwa kwesitaki kuphelela lapho. Inkinga yayiwukuthi ngenxa yokusetshenziswa ngemva kwamahhala, okwavela lapho ichibi le-coroutine likhutshaziwe ngenxa yokuthi angizange ngikopishe umugqa obalulekile wekhodi kusuka ku-backend ekhona ye-coroutine, umsebenzi qemu_in_coroutine kubuyiselwe iqiniso kanti empeleni bekumele kubuye kungamanga. Lokhu kuholele ocingweni emscripten_yield, ngaphezu kwalokho kwakungekho muntu esitakini emscripten_coroutine_next, isitaki sembuleke phezulu, kodwa cha setTimeout, njengoba sengishilo, ayizange iboniswe.

Ukwakhiwa kwekhodi yeJavaScript

Futhi lapha, empeleni, isithembiso "sokubuyisela inyama egayiwe." Akunjalo Empeleni. Yiqiniso, uma sisebenzisa i-Qemu esipheqululini, kanye ne-Node.js kuyo, khona-ke, ngokwemvelo, ngemva kokukhiqizwa kwekhodi ku-Qemu sizothola i-JavaScript engalungile ngokuphelele. Kodwa noma kunjalo, uhlobo oluthile lokuguqulwa okuphambene.

Okokuqala, kancane mayelana nendlela uQemu asebenza ngayo. Ngicela ungixolele ngokushesha: Angiyena umthuthukisi we-Qemu ochwepheshe futhi iziphetho zami zingase zibe nephutha kwezinye izindawo. Njengoba besho, “umbono womfundi akudingeki uhambisane nombono kathisha, i-axiomatics kaPeano kanye nengqondo ephusile.” I-Qemu inenani elithile lezakhiwo zesivakashi ezisekelwayo futhi ngayinye kukhona uhla lwemibhalo olufana nalo target-i386. Lapho wakha, ungacacisa usekelo lwezakhiwo ezimbalwa zesivakashi, kodwa umphumela uzoba amabhinari ambalwa nje. Ikhodi yokusekela izakhiwo zesivakashi, yona, ikhiqiza imisebenzi ethile yangaphakathi ye-Qemu, i-TCG (I-Tiny Code Generator) isivele iyiguqule ibe ikhodi yomshini yezakhiwo zomsingathi. Njengoba kushiwo kufayela le-readme elitholakala kuhla lwemibhalo lwe-tcg, lokhu ekuqaleni bekuyingxenye ye-compiler evamile ye-C, kamuva eyaguqulelwa i-JIT. Ngakho-ke, isibonelo, ukwakheka okuhlosiwe ngokwale dokhumenti akuseyona i-architecture yesivakashi, kodwa isingewomakhiwo. Ngesinye isikhathi, kwavela enye ingxenye - I-Tiny Code Interpreter (TCI), okufanele yenze ikhodi (cishe imisebenzi efanayo yangaphakathi) lapho kungekho generator ikhodi yezakhiwo ezithile zokubamba. Eqinisweni, njengoba imibhalo yayo isho, lo mhumushi angeke enze njalo kanye nejeneretha yekhodi ye-JIT, hhayi nje ngobuningi ngokwejubane, kodwa futhi nangekhwalithi. Nakuba ngingaqiniseki ukuthi incazelo yakhe ihambisana ngokuphelele.

Ekuqaleni ngazama ukwenza i-backend ye-TCG egcwele ngokugcwele, kodwa ngokushesha ngadideka kukhodi yomthombo kanye nencazelo engacacile ngokuphelele yemiyalelo ye-bytecode, ngakho-ke nganquma ukugoqa umhumushi we-TCI. Lokhu kwanikeza izinzuzo eziningana:

  • lapho usebenzisa i-code generator, awukwazi ukubheka incazelo yemiyalelo, kodwa ikhodi yomtoliki
  • ungakwazi ukukhiqiza imisebenzi hhayi kuwo wonke amabhulokhi wokuhumusha okuhlangatshezwane nawo, kodwa, isibonelo, kuphela ngemva kokukhishwa kwekhulu
  • uma ikhodi ekhiqiziwe ishintsha (futhi lokhu kubonakala kungenzeka, ukwahlulela ngemisebenzi enamagama aqukethe isiqeshana samagama), ngizodinga ukwenza ikhodi ekhiqiziwe ye-JS ingasebenzi, kodwa okungenani ngizoba nokuthile engingayenza kabusha

Mayelana nephuzu lesithathu, angiqiniseki ukuthi ukuchibiyela kungenzeka ngemuva kokuthi ikhodi ikhishwe okokuqala, kodwa amaphuzu amabili okuqala anele.

Ekuqaleni, ikhodi yenziwa ngendlela yokushintsha okukhulu ekhelini le-bytecode yokufundisa yasekuqaleni, kodwa-ke, ngikhumbula isihloko mayelana ne-Emscripten, ukwenziwa kahle kwe-JS ekhiqiziwe kanye nokuphinda kufakwe kabusha, nganquma ukukhiqiza ikhodi yomuntu eyengeziwe, ikakhulukazi njengoba i-empirically it. kwavela ukuthi ukuphela kwendawo yokungena ebhulokhini lokuhumusha yi-Start yayo. Ngokushesha nje, ngemva kwesikhashana saba nejeneretha yekhodi eyakhiqiza ikhodi nge-ifs (nakuba ngaphandle kwama-loops). Kodwa ngeshwa, yaphahlazeka, yanikeza umlayezo wokuthi imiyalelo yayinobude obungalungile. Ngaphezu kwalokho, umyalo wokugcina kuleli zinga lokuphindaphinda kwaba brcond. Kulungile, ngizongeza isheke elifanayo ekukhiqizeni lo myalelo ngaphambi nangemuva kocingo oluphindaphindayo futhi... akukho neyodwa yazo ekhishiwe, kodwa ngemva kokushintsha i-assert basahluleka. Ekugcineni, ngemva kokutadisha ikhodi ekhiqiziwe, ngabona ukuthi ngemva kokushintsha, i-pointer eya emfundweni yamanje ilayishwa kabusha kusukela ku-stack futhi cishe ibhalwe phezu kwekhodi ye-JavaScript ekhiqiziwe. Futhi kwaba njalo. Ukwandisa isigcinalwazi sisuka kumegabhayithi eyodwa siye kweshumi akuzange kuholele entweni, futhi kwacaca ukuthi ijeneretha yekhodi yayisebenza emibuthanweni. Kwadingeka sihlole ukuthi asidluli yini imingcele ye-TB yamanje, futhi uma senzile, bese sikhipha ikheli le-TB elilandelayo elinophawu lokususa ukuze siqhubeke nokubulawa. Ngaphezu kwalokho, lokhu kuxazulula inkinga "iyiphi imisebenzi ekhiqiziwe okufanele ingasebenzi uma lesi siqeshana se-bytecode sishintshile?" — umsebenzi ohambisana nalokhu kuhumusha kuphela odinga ukwenziwa ungasebenzi. Ngendlela, nakuba ngisuse iphutha yonke into ku-Chromium (njengoba ngisebenzisa iFirefox futhi kulula kimi ukusebenzisa isiphequluli esihlukile sokuhlola), iFirefox yangisiza ukulungisa ukungahambisani nezinga le-asm.js, ngemva kwalokho ikhodi yaqala ukusebenza ngokushesha I-Chromium.

Isibonelo sekhodi ekhiqiziwe

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

isiphetho

Ngakho-ke, umsebenzi awukaqedwa, kodwa ngikhathele ukuletha lokhu kwakhiwa okuhlala isikhathi eside ekupheleleni ngasese. Ngakho-ke, nginqume ukushicilela enginakho okwamanje. Ikhodi iyesabeka kancane ezindaweni, ngoba lokhu kuyisivivinyo, futhi akucaci kusengaphambili ukuthi yini okufanele yenziwe. Mhlawumbe, khona-ke kufanelekile ukukhipha izibophezelo ze-athomu ezijwayelekile ngaphezulu kwenguqulo yesimanje ye-Qemu. Phakathi naleso sikhathi, kukhona intambo ku-Gita ngefomethi yebhulogi: "kwizinga" ngalinye eliye ladlula ngandlela-thile, ukuphawula okuningiliziwe ngesiRashiya kuye kwanezelwa. Eqinisweni, lesi sihloko ngokwezinga elikhulu siwukulandisa kabusha kwesiphetho git log.

Ungazama konke lapha (qaphela traffic).

Okuvele kuyasebenza:

  • iprosesa ye-x86 esebenzayo
  • Kunesibonelo esisebenzayo se-JIT code generator kusuka kukhodi yomshini kuya ku-JavaScript
  • Kukhona isifanekiso sokuhlanganisa ezinye izakhiwo zezivakashi ezingama-32-bit: njengamanje ungababaza i-Linux ye-MIPS yokuqandisa kwezakhiwo esipheqululini esigabeni sokulayisha.

Yini enye ongayenza

  • Sheshisa ukulingisa. Ngisho nakumodi ye-JIT ibonakala ihamba kancane kune-Virtual x86 (kodwa kungenzeka ukuthi kukhona i-Qemu ephelele enezingxenyekazi eziningi ezilingisiwe nezakhiwo)
  • Ukwenza isixhumi esibonakalayo esivamile - ngokungagwegwesi, angiyena umakhi wewebhu omuhle, ngakho okwamanje ngenze kabusha igobolondo elivamile le-Emscripten ngokusemandleni ami.
  • Zama ukwethula imisebenzi ye-Qemu eyinkimbinkimbi - ukuxhumana, ukufuduka kwe-VM, njll.
  • I-UPS: uzodinga ukuthumela ukuthuthukiswa kwakho okumbalwa kanye nemibiko yesiphazamisi ku-Emscripten enhla nomfula, njengoba abathwali bangaphambili be-Qemu kanye namanye amaphrojekthi benza. Ngiyabonga kubo ngokukwazi ukusebenzisa umnikelo wabo ngokungagunci ku-Emscripten njengengxenye yomsebenzi wami.

Source: www.habr.com

Engeza amazwana