Qemu.js tare da goyan bayan JIT: har yanzu kuna iya juya mince baya

Bayan 'yan shekarun da suka gabata Fabrice Bellard jslinux ne ya rubuta Kwaikwayon PC ne da aka rubuta da JavaScript. Bayan haka akwai aƙalla ƙari Virtual x86. Amma dukkansu, kamar yadda na sani, masu fassara ne, yayin da Qemu, wanda Fabrice Bellard ya rubuta tun da farko, kuma, mai yiwuwa, duk wani mai kwaikwayi na zamani mai mutunta kansa, yana amfani da JIT harhada lambar baƙo zuwa lambar tsarin masauki. Ya zama a gare ni cewa lokaci ya yi da za a aiwatar da akasin ɗawainiya dangane da wanda masu bincike ke warwarewa: JIT haɗa lambar na'ura zuwa JavaScript, wanda ya zama mafi ma'ana ga tashar Qemu. Zai yi kama, dalilin da yasa Qemu, akwai masu kwaikwayi masu sauƙi da abokantaka masu amfani - VirtualBox iri ɗaya, alal misali - shigar da aiki. Amma Qemu yana da fasali masu ban sha'awa da yawa

  • bude tushen
  • ikon yin aiki ba tare da direban kernel ba
  • iya aiki a yanayin fassara
  • goyon baya ga babban adadin duka masu masaukin baki da gine-ginen baƙi

Game da batu na uku, yanzu zan iya bayyana cewa a zahiri, a cikin yanayin TCI, ba injin ɗin baƙo ya ba da umarni da kansu ana fassara shi ba, amma bytecode da aka samo daga gare su, amma wannan ba ya canza ainihin ainihin - don ginawa da gudu. Qemu akan sabon gine-gine, idan kun yi sa'a, mai tarawa A C ya isa - rubuta janareta na lamba za a iya jinkirta shi.

Kuma yanzu, bayan shekaru biyu na leisurely tinkering tare da Qemu code code a cikin free lokaci, wani aiki samfurin ya bayyana, a cikin abin da za ka iya riga gudu, misali, Kolibri OS.

Menene Emscripten

A zamanin yau, masu tarawa da yawa sun bayyana, wanda ƙarshensa shine JavaScript. Wasu, kamar Nau'in Rubutun, an yi niyya da farko su zama hanya mafi kyau don rubutawa ga gidan yanar gizo. A lokaci guda, Emscripten wata hanya ce ta ɗaukar lambar C ko C++ da ke akwai kuma a haɗa ta cikin hanyar da za a iya karantawa ta mai lilo. Kunna wannan shafin Mun tattara tashoshin jiragen ruwa da yawa na sanannun shirye-shirye: a nanMisali, zaku iya duba PyPy - ta hanya, suna da'awar sun riga sun sami JIT. A gaskiya ma, ba kowane shirin ba ne kawai za a iya haɗa shi kuma a gudanar da shi a cikin mashigin bincike - akwai lamba fasali, wanda dole ne ka haƙura da shi, duk da haka, kamar yadda rubutun da ke wannan shafi ya ce “Emscripten za a iya amfani da shi wajen tattara kusan kowane abu. šaukuwa C/C++ code to JavaScript." Wato, akwai ayyuka da yawa waɗanda ba a fayyace halayensu bisa ga ƙa'idar, amma yawanci suna aiki akan x86 - misali, rashin daidaituwa ga masu canji, wanda gabaɗaya an haramta shi akan wasu gine-gine. Gaba ɗaya , Qemu shirin giciye-dandamali ne kuma , Ina so in yi imani, kuma bai riga ya ƙunshi ɗabi'a da yawa waɗanda ba a bayyana ba - ɗauka kuma ku tattara, sannan ku ɗanɗana kaɗan tare da JIT - kuma kun gama! kaso...

Gwada farko

Gabaɗaya magana, ba ni ne mutum na farko da ya fito da ra'ayin jigilar Qemu zuwa JavaScript ba. Akwai tambaya da aka yi akan dandalin ReactOS idan hakan zai yiwu ta amfani da Emscripten. Ko da a baya, akwai jita-jita cewa Fabrice Bellard ya yi wannan da kansa, amma muna magana ne game da jslinux, wanda, kamar yadda na sani, ƙoƙari ne kawai don samun isasshen aiki da hannu a JS, kuma an rubuta shi daga karce. Daga baya, Virtual x86 an rubuta - an buga majiyoyin da ba a ɓoye ba, kuma, kamar yadda aka bayyana, mafi girman "hakikanin" kwaikwayi ya sa ya yiwu a yi amfani da SeaBIOS azaman firmware. Bugu da kari, an yi aƙalla ƙoƙari ɗaya na tashar jiragen ruwa na Qemu ta amfani da Emscripten - Na yi ƙoƙarin yin wannan socketpair, amma ci gaba, kamar yadda na fahimta, ya daskare.

Don haka, zai zama kamar, ga tushen, ga Emscripten - ɗauka kuma ku tattara. Amma akwai kuma dakunan karatu da Qemu ya dogara da su, da kuma dakunan karatu da wadancan dakunan karatu suka dogara da su da sauransu, daya daga cikinsu shi ne. libfi, wanda glib ya dogara da shi. Akwai jita-jita a Intanet cewa akwai ɗaya a cikin babban tarin tashar jiragen ruwa na ɗakunan karatu don Emscripten, amma yana da wuya a yi imani: da farko, ba a yi niyya don zama sabon mai tarawa ba, na biyu, ya yi ƙasa da ƙasa. ɗakin karatu don ɗauka kawai, kuma a haɗa zuwa JS. Kuma ba batun shigar da taro ba ne kawai - mai yiwuwa, idan kun karkatar da shi, don wasu tarurrukan kira za ku iya samar da hujjojin da suka dace akan tari kuma ku kira aikin ba tare da su ba. Amma Emscripten abu ne mai wayo: don sanya lambar da aka samar ta zama sananne ga mai inganta injin JS mai bincike, ana amfani da wasu dabaru. Musamman, abin da ake kira relooping - janareta na lamba ta amfani da LLVM IR da aka karɓa tare da wasu ƙa'idodin miƙa mulki na ƙayyadaddun ƙayyadaddun ƙayyadaddun ƙayyadaddun ƙayyadaddun ƙa'idodin ke ƙoƙarin sake ƙirƙirar ifs, madaukai, da sauransu. To, ta yaya aka ƙaddamar da muhawara zuwa aikin? A zahiri, a matsayin muhawara ga ayyukan JS, wato, idan zai yiwu, ba ta hanyar tari ba.

A farkon akwai wani ra'ayi don kawai rubuta maye gurbin libffi tare da JS da gudanar da gwaje-gwaje na yau da kullun, amma a ƙarshe na rikice game da yadda ake yin fayilolin rubutuna don su yi aiki tare da lambar da ke akwai - menene zan iya yi, kamar yadda suke cewa, "Shin ayyukan suna da rikitarwa" Shin muna da wauta? Dole ne in yi jigilar libffi zuwa wani gine-gine, don yin magana - sa'a, Emscripten yana da duka macros don haɗin layi (a cikin Javascript, yeah - da kyau, duk abin da gine-gine, don haka mai tarawa), da kuma ikon gudanar da lambar da aka samar a kan tashi. Gabaɗaya, bayan yin tinkering tare da guntun libffi masu dogaro da dandamali na ɗan lokaci, na sami wasu lambobin da aka haɗa kuma na gudanar da shi akan gwajin farko da na ci karo da shi. Ga mamakina, gwajin ya yi nasara. Abin mamaki da gwanina - ba wasa ba, ya yi aiki daga farkon ƙaddamarwa - Ni, har yanzu ban gaskanta idanuna ba, na sake sake duba lambar da aka samu, don kimanta inda zan tono gaba. A nan na yi goro a karo na biyu - kawai abin da aikina ya yi shi ne ffi_call - wannan ya ruwaito kira mai nasara. Babu waya kanta. Don haka na aika buƙatun ja na farko, wanda ya gyara kuskure a cikin gwajin da ya bayyana ga kowane ɗalibin Olympiad - bai kamata a kwatanta lambobi na ainihi kamar a == b da ma yaya a - b < EPS - Har ila yau, kuna buƙatar tunawa da tsarin, in ba haka ba 0 zai zama daidai da 1/3 ... Gabaɗaya, na zo da wani tashar jiragen ruwa na libffi, wanda ya wuce mafi sauƙi gwaje-gwaje, kuma tare da wane glib yake. harhada - Na yanke shawarar zai zama dole, zan ƙara shi daga baya. Duba gaba, zan ce, kamar yadda ya fito, mai tarawa bai haɗa da aikin libffi ba a cikin lambar ƙarshe.

Amma, kamar yadda na riga na fada, akwai wasu iyakoki, kuma daga cikin amfani da kyauta na wasu halaye marasa iyaka, an ɓoye wani abu mara kyau - JavaScript ta ƙira baya goyan bayan multithreading tare da ƙwaƙwalwar ajiya. A ka'ida, wannan yawanci ana iya kiransa kyakkyawan ra'ayi, amma ba don lambar tashar jiragen ruwa wanda gine-ginen ya ɗaure da zaren C ba. Gabaɗaya magana, Firefox tana gwaji tare da tallafawa ma'aikatan da aka raba, kuma Emscripten yana da aiwatar da pthread a gare su, amma ban so in dogara da shi ba. Dole ne in cire multithreading a hankali daga lambar Qemu - wato, gano inda zaren ke gudana, motsa jikin madauki da ke gudana a cikin wannan zaren zuwa wani aiki daban, sannan in kira irin waɗannan ayyuka ɗaya bayan ɗaya daga babban madauki.

Na biyu ƙoƙari

A wani lokaci, ya bayyana a fili cewa har yanzu matsalar tana nan, kuma ba tare da ɓata lokaci ba, tura ƙugiya a kusa da lambar ba zai haifar da wani alheri ba. Kammalawa: muna buƙatar ko ta yaya systematize aiwatar da ƙara crutches. Saboda haka, version 2.4.1, wanda yake sabo ne a wancan lokacin, da aka dauka (ba 2.5.0, domin, wanda ya sani, za a yi kwari a cikin sabon version da cewa ba a riga kama kama, kuma ina da isasshen na kaina kwari. ), kuma abu na farko shine a sake rubuta shi lafiya thread-posix.c. To, wato, a matsayin mai aminci: idan wani ya yi ƙoƙarin yin aikin da zai kai ga toshewa, an kira aikin nan da nan abort() - Tabbas, wannan bai warware duk matsalolin lokaci ɗaya ba, amma aƙalla yana da daɗi ko ta yaya fiye da karɓar bayanan da ba daidai ba.

Gabaɗaya, zaɓuɓɓukan Emscripten suna da taimako sosai wajen aika lambar zuwa JS -s ASSERTIONS=1 -s SAFE_HEAP=1 - suna kama wasu nau'ikan halayen da ba a bayyana ba, kamar kira zuwa adireshin da ba a haɗa shi ba (wanda ko kaɗan bai yi daidai da lambar da aka buga ba kamar su. HEAP32[addr >> 2] = 1) ko kiran aiki tare da kuskuren adadin muhawara.

Af, kurakuran daidaitawa wani lamari ne daban. Kamar yadda na riga na fada, Qemu yana da "lalacewar" fassarar baya don tsara lambar TCI (kananan mai fassarar lambar), da kuma ginawa da gudanar da Qemu akan sabon gine-gine, idan kun yi sa'a, mai tarawa C ya isa. Keywords "idan kayi sa'a". Na yi rashin sa'a, kuma ya zamana cewa TCI tana amfani da damar da ba ta dace ba lokacin da ake tantance lambar ta. Wato, akan kowane nau'in ARM da sauran gine-ginen da dole ne a daidaita su, Qemu yana tattarawa saboda suna da tsarin baya na TCG na yau da kullun wanda ke haifar da lambar asali, amma ko TCI zata yi aiki a kansu wata tambaya ce. Duk da haka, kamar yadda ya juya, takardun TCI sun nuna a fili wani abu makamancin haka. Sakamakon haka, an ƙara kiran aikin don karantawa mara daidaituwa a lambar, waɗanda aka samo a wani ɓangaren Qemu.

Rushewar tsibi

Sakamakon haka, an gyara hanyar da ba ta dace ba zuwa TCI, an ƙirƙiri babban madauki wanda kuma ake kira processor, RCU da wasu ƙananan abubuwa. Don haka na ƙaddamar da Qemu tare da zaɓi -d exec,in_asm,out_asm, wanda ke nufin cewa kana buƙatar faɗi waɗanne tubalan code ake aiwatarwa, da kuma lokacin watsa shirye-shirye don rubuta abin da lambar baƙo ta kasance, menene lambar masaukin ta zama (a wannan yanayin, bytecode). Yana farawa, yana aiwatar da tubalan fassarar da yawa, yana rubuta saƙon gyara kuskuren da na bari cewa RCU zai fara yanzu kuma… abort() cikin wani aiki free(). Ta hanyar tinkering tare da aikin free() Mun yi nasarar gano cewa a cikin header na tarin tsibi, wanda ke cikin bytes takwas da ke gaban ƙwaƙwalwar ajiya, maimakon girman block ko wani abu makamancin haka, akwai shara.

Rushewar tsibi - yadda kyakkyawa ... A irin wannan yanayin, akwai magani mai amfani - daga (idan zai yiwu) maɓuɓɓugar guda ɗaya, tara binary na asali kuma gudanar da shi a ƙarƙashin Valgrind. Bayan wani lokaci, binary ya shirya. Na ƙaddamar da shi tare da zaɓuɓɓuka iri ɗaya - yana faɗuwa ko da lokacin farawa, kafin a kai ga aiwatarwa. Ba shi da daɗi, ba shakka - a fili, tushen ba daidai ba ne, wanda ba abin mamaki ba ne, saboda saita zaɓuka daban-daban, amma ina da Valgrind - da farko zan gyara wannan kwaro, sannan, idan na yi sa'a. , na asali zai bayyana. Ina gudanar da abu iri ɗaya a ƙarƙashin Valgrind ... Y-y-y, y-y, uh-uh, ya fara, ya tafi ta hanyar farawa akai-akai kuma ya ci gaba da wucewa na asali ba tare da gargadi ɗaya ba game da samun damar ƙwaƙwalwar ajiya ba daidai ba, ba a ma maganar faɗuwa ba. Rayuwa, kamar yadda suke faɗa, ba ta shirya ni don wannan ba - wani shiri mai faɗuwa yana tsayawa lokacin da aka ƙaddamar da shi a ƙarƙashin Walgrind. Abin da ya kasance asiri ne. Hasashe na shine cewa sau ɗaya a cikin kusancin koyarwar yanzu bayan haɗari yayin farawa, gdb ya nuna aiki. memset-a tare da ingantacciyar ma'ana ta amfani da ko dai mmx, ko xmm rajista, to, watakila ya kasance wani nau'i na kuskuren daidaitawa, ko da yake yana da wuya a yi imani.

To, da alama Valgrind ba ya taimaka a nan. Kuma a nan abin da ya fi banƙyama ya fara - duk abin da alama ya fara farawa, amma ya rushe don dalilan da ba a sani ba saboda wani taron da zai iya faruwa miliyoyin umarni da suka wuce. Na dogon lokaci, ba a ma bayyana yadda za a tunkari ba. A ƙarshe, har yanzu dole ne in zauna in yi gyara. Buga abin da aka sake rubuta rubutun da shi ya nuna cewa bai yi kama da lamba ba, sai dai wani nau'in bayanan binary. Kuma, ga shi, an samo wannan kirtani na binary a cikin fayil ɗin BIOS - wato, yanzu yana yiwuwa a ce da tabbaci mai ma'ana cewa buffer ne mai ambaliya, kuma a bayyane yake cewa an rubuta shi zuwa wannan buffer. To, to, wani abu kamar wannan - a cikin Emscripten, an yi sa'a, babu bazuwar sararin adireshin, babu ramuka a ciki ko dai, don haka za ku iya rubuta wani wuri a tsakiyar lambar don fitar da bayanai ta hanyar nuna alama daga ƙaddamarwar ƙarshe. duba bayanan, dubi mai nuna, kuma, idan bai canza ba, sami abinci don tunani. Gaskiya, yana ɗaukar mintuna biyu don haɗawa bayan kowane canji, amma menene zaku iya yi? A sakamakon haka, an sami takamaiman layi wanda ya kwafi BIOS daga ma'ajin wucin gadi zuwa ƙwaƙwalwar ajiyar baƙo - kuma, hakika, babu isasshen sarari a cikin buffer. Nemo tushen wannan bakon adireshin buffer ya haifar da aiki qemu_anon_ram_alloc cikin fayil oslib-posix.c - dabarar akwai wannan: wani lokacin yana iya zama da amfani a daidaita adireshin zuwa babban shafi mai girman 2 MB, don haka zamu tambaya. mmap da farko kadan kadan, sa'an nan kuma za mu mayar da abin da ya wuce tare da taimako munmap. Kuma idan ba a buƙatar irin wannan alignment, to, za mu nuna sakamakon maimakon 2 MB getpagesize() - mmap har yanzu zai ba da adireshin da aka daidaita... Don haka a cikin Emscripten mmap kira kawai malloc, amma ba shakka ba ya daidaita a shafin. Gabaɗaya, wani kwaro da ya ba ni takaici na tsawon watanni biyu an gyara shi ta hanyar canji aiki layuka.

Siffofin ayyukan kira

Kuma yanzu processor yana kirga wani abu, Qemu baya fadowa, amma allon bai kunna ba, kuma mai sarrafa na'ura ya shiga cikin madauki da sauri, yana yin hukunci ta hanyar fitarwa. -d exec,in_asm,out_asm. Hasashe ya fito: katsewar lokacin (ko, gabaɗaya, duk katsewa) ba sa isa. Kuma lalle ne, idan kun kwance katsewar daga taron jama'a, wanda saboda wasu dalilai ya yi aiki, kuna samun irin wannan hoto. Amma wannan ba shine amsar ko kadan ba: kwatankwacin abubuwan da aka bayar tare da zabin da ke sama ya nuna cewa hanyoyin aiwatar da hukuncin sun bambanta da wuri. Anan dole ne a faɗi kwatankwacin abin da aka yi rikodin ta amfani da ƙaddamarwa emrun fitarwar gyara kurakurai tare da fitowar taron jama'a ba tsari ne na injiniya gaba ɗaya ba. Ban san ainihin yadda shirye-shiryen da ke gudana a cikin burauza ke haɗuwa da su ba emrun, amma wasu layukan da ke cikin abubuwan da aka fitar sun juya don a sake tsara su, don haka bambamcin bambance-bambancen bai riga ya zama dalilin ɗauka cewa hanyoyin sun bambanta ba. Gabaɗaya, ya bayyana cewa bisa ga umarnin ljmpl akwai sauyawa zuwa adireshi daban-daban, kuma bytecode da aka samar ya bambanta: ɗayan yana ƙunshe da umarni don kiran aikin mataimaki, ɗayan ba ya. Bayan yin amfani da umarnin da kuma nazarin lambar da ke fassara waɗannan umarnin, ya bayyana a fili cewa, da farko, nan da nan kafin shi a cikin rajista. cr0 an yi rikodi - kuma ta amfani da mataimaki - wanda ya canza masarrafar zuwa yanayin kariya, na biyu kuma, cewa sigar js ba ta canza zuwa yanayin kariya ba. Amma gaskiyar ita ce, wani fasalin Emscripten shine ƙin yarda da lambar kamar aiwatar da umarni. call a cikin TCI, wanda kowane mai nuna aikin ke haifar da nau'in long long f(int arg0, .. int arg9) - Dole ne a kira ayyuka tare da madaidaicin adadin muhawara. Idan an keta wannan doka, dangane da saitunan gyarawa, shirin zai ko dai ya fadi (wanda yake da kyau) ko kuma ya kira aikin da ba daidai ba kwata-kwata (wanda zai zama bakin ciki don cirewa). Har ila yau, akwai zaɓi na uku - yana ba da damar tsararrun naɗaɗɗen da ke ƙarawa / cire muhawara, amma a cikin duka waɗannan naɗaɗɗen suna ɗaukar sarari da yawa, duk da cewa a gaskiya ina buƙatar ɗan ƙarami fiye da ɗari. Wannan kadai yana da matukar bakin ciki, amma ya zama matsala mafi tsanani: a cikin lambar da aka samar na ayyukan wrapper, an canza muhawara kuma an canza su, amma wani lokacin aikin tare da muhawarar da aka haifar ba a kira shi ba - da kyau, kamar dai a ciki. aiwatar da libffi na. Wato wasu mataimaka kawai ba a kashe su ba.

Abin farin ciki, Qemu yana da jerin sunayen mataimaka waɗanda za a iya karantawa a cikin nau'in fayil ɗin rubutu kamar

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

Ana amfani da su sosai mai ban dariya: na farko, ana sake fasalin macro a cikin mafi ban mamaki hanya DEF_HELPER_n, sannan ya kunna helper.h. Har zuwa girman macro an fadada shi zuwa tsarin farawa da waƙafi, sa'an nan kuma an bayyana tsararru, kuma a maimakon abubuwa - #include <helper.h> A sakamakon haka, a ƙarshe na sami damar gwada ɗakin karatu a wurin aiki pyparsing, kuma an rubuta rubutun da ke haifar da ainihin waɗancan abubuwan nannade don ainihin ayyukan da ake buƙatar su.

Sabili da haka, bayan haka, mai sarrafawa ya zama kamar yana aiki. Da alama saboda ba a taɓa farawa allon ba, kodayake memtest86+ ya sami damar yin aiki a cikin babban taron. Anan ya zama dole a fayyace cewa Qemu toshe lambar I/O an rubuta shi a cikin coroutines. Emscripten yana da nasa aiwatar da wayo sosai, amma har yanzu yana buƙatar a tallafa masa a cikin lambar Qemu, kuma kuna iya gyara mai sarrafawa yanzu: Qemu yana goyan bayan zaɓuɓɓuka. -kernel, -initrd, -append, wanda da shi zaku iya taya Linux ko, alal misali, memtest86+, ba tare da amfani da na'urorin toshe kwata-kwata ba. Amma ga matsalar: a cikin taro na asali mutum zai iya ganin fitowar kernel Linux zuwa na'ura mai kwakwalwa tare da zaɓi -nographic, kuma babu fitarwa daga mai binciken zuwa tashar daga inda aka ƙaddamar da shi emrun, bai zo ba. Wato, ba a fayyace ba: na'ura mai sarrafawa ba ta aiki ko kuma kayan aikin zane ba ya aiki. Kuma sai ya zo gare ni in jira kadan. Ya bayyana cewa "na'urar sarrafa ba ta barci, amma kawai tana lumshe ido a hankali," kuma bayan kamar minti biyar kernel ya jefa gungun sakonni a kan na'urar kuma ya ci gaba da rataya. Ya bayyana a fili cewa mai sarrafawa, a gaba ɗaya, yana aiki, kuma muna buƙatar tono cikin lambar don aiki tare da SDL2. Abin takaici, ban san yadda zan yi amfani da wannan ɗakin karatu ba, don haka a wasu wurare dole ne in yi aiki ba da gangan ba. A wani lokaci, layin parallel0 ya haskaka akan allon akan bango shuɗi, wanda ya ba da shawarar wasu tunani. A ƙarshe, ya zama cewa matsalar ita ce Qemu yana buɗe windows masu kama da yawa a cikin taga na zahiri guda ɗaya, waɗanda zaku iya canzawa ta amfani da Ctrl-Alt-n: yana aiki a cikin ginin asali, amma ba a cikin Emscripten ba. Bayan kawar da windows da ba dole ba ta amfani da zaɓuɓɓuka -monitor none -parallel none -serial none da umarnin don sake zana gaba ɗaya allon da ƙarfi akan kowane firam, komai ya yi aiki ba zato ba tsammani.

Coroutines

Don haka, kwaikwayi a cikin mai binciken yana aiki, amma ba za ku iya gudanar da wani abu mai ban sha'awa guda ɗaya a ciki ba, saboda babu toshe I / O - kuna buƙatar aiwatar da tallafi ga coroutines. Qemu ya riga yana da goyan baya da yawa, amma saboda yanayin JavaScript da janareta na lambar Emscripten, ba za ku iya fara juggling stacks kawai ba. Zai yi kama da cewa "komai ya ɓace, ana cire filasta," amma masu haɓaka Emscripten sun riga sun kula da komai. Ana aiwatar da wannan abu mai ban dariya: bari mu kira kiran aiki kamar wannan abin tuhuma emscripten_sleep da wasu da yawa masu amfani da tsarin Asyncify, da kuma kira mai nuni da kira zuwa kowane aiki inda ɗayan shari'o'i biyu da suka gabata na iya faruwa a ƙasa tari. Kuma yanzu, kafin kowane kira mai tuhuma, za mu zaɓi mahallin async, kuma nan da nan bayan kiran, za mu bincika ko kiran asynchronous ya faru, kuma idan yana da, za mu adana duk masu canji na gida a cikin wannan mahallin async, nuna wane aiki ne. don canja wurin sarrafawa zuwa lokacin da muke buƙatar ci gaba da aiwatarwa, kuma mu fita aikin na yanzu. Wannan shine inda akwai damar yin nazarin tasirin almubazzaranci - don buƙatun ci gaba da aiwatar da lambar bayan dawowa daga kiran asynchronous, mai tarawa yana haifar da "stubs" na aikin da ke farawa bayan kiran da ake tuhuma - kamar haka: idan akwai n m kira, to, aikin zai fadada wani wuri n/2. sau - wannan har yanzu, idan ba haka ba Ka tuna cewa bayan kowane kira mai yuwuwar asynchronous, kana buƙatar ƙara adana wasu masu canji na gida zuwa ainihin aikin. Daga baya, har ma na rubuta rubutun mai sauƙi a cikin Python, wanda, bisa ga wani tsari na musamman da aka yi amfani da shi wanda ake zaton "ba sa barin asynchrony ya wuce ta kansu" (wato, gabatarwar tari da duk abin da na kwatanta ba sa. aiki a cikin su), yana nuna kira ta hanyar masu nuni wanda masu tara ayyuka yakamata a yi watsi da su don kada waɗannan ayyukan su kasance asynchronous. Sannan fayilolin JS da ke ƙarƙashin 60 MB suna da yawa a fili - bari mu ce aƙalla 30. Ko da yake, da zarar na kafa rubutun taro, kuma da gangan na jefar da zaɓuɓɓukan linker, daga cikinsu akwai -O3. Ina gudanar da lambar da aka ƙirƙira, kuma Chromium yana cinye ƙwaƙwalwar ajiya da faɗuwa. Sai na kalli abin da yake kokarin saukewa a bazata... To, me zan ce, ni ma da na daskare da an ce in yi nazari cikin tunani da inganta Javascript 500+ MB.

Abin takaici, cak ɗin da ke cikin lambar tallafin Asyncify ba su da abokantaka gaba ɗaya longjmp-s waɗanda aka yi amfani da su a cikin lambar ƙirar ƙirar ƙira, amma bayan ƙaramin facin da ke kashe waɗannan cak kuma da ƙarfi ya dawo da mahallin kamar duk abin yana da kyau, lambar ta yi aiki. Kuma a sa'an nan wani bakon abu ya fara: wani lokacin rajistan shiga a cikin code aiki tare da aka jawo - iri guda wadanda suka fadi da code idan, bisa ga kisa dabaru, ya kamata a katange - wani ya yi kokarin ansu rubuce-rubucen da riga kama mutex. Abin farin ciki, wannan ya zama ba matsala mai ma'ana ba a cikin lambar serialized - Ina kawai amfani da daidaitaccen aikin madauki wanda Emscripten ya bayar, amma wani lokacin kiran asynchronous zai warware tari gaba ɗaya, kuma a wannan lokacin zai gaza. setTimeout daga babban madauki - don haka lambar ta shiga babban madauki ba tare da barin abin da ya gabata ba. Sake rubutawa akan madauki mara iyaka kuma emscripten_sleep, da kuma matsalolin da mutexes suka tsaya. Lambar ta zama mafi ma'ana - bayan haka, a zahiri, ba ni da wasu lambar da ke shirya firam ɗin raye-raye na gaba - mai sarrafawa kawai yana ƙididdige wani abu kuma ana sabunta allon lokaci-lokaci. Duk da haka, matsalolin ba su tsaya nan ba: wani lokacin aiwatar da Qemu yakan ƙare shiru kawai ba tare da keɓance ko kurakurai ba. A wannan lokacin na yi watsi da shi, amma, duban gaba, zan ce matsalar ita ce: code code, a gaskiya, ba ya amfani. setTimeout (ko aƙalla ba sau da yawa kamar yadda kuke tunani): aiki emscripten_yield kawai saita tutar kiran asynchronous. Batun gaba daya shine emscripten_coroutine_next ba aikin asynchronous bane: a ciki yana bincika tuta, sake saita ta kuma yana canja wurin sarrafawa zuwa inda ake buƙata. Wato tallata tari ya ƙare a nan. Matsalar ita ce saboda amfani-bayan-kyauta, wanda ya bayyana a lokacin da aka kashe coroutine pool saboda gaskiyar cewa ban kwafi wani muhimmin layi na lambar daga bayanan coroutine na yanzu ba, aikin. qemu_in_coroutine ya dawo gaskiya alhalin ya kamata ya koma karya. Wannan ya haifar da kira emscripten_yield, a sama babu kowa a kan tari emscripten_coroutine_next, tari ya buɗe zuwa sama, amma a'a setTimeout, kamar yadda na fada, ba a nuna ba.

Ƙirƙirar lambar JavaScript

Kuma a nan, a zahiri, an yi alkawarin “juyar da nikakken naman baya.” Ba da gaske ba. Hakika, idan muka gudu Qemu a cikin browser, kuma Node.js a ciki, to, ta halitta, bayan code tsara a Qemu za mu sami gaba daya kuskure JavaScript. Amma duk da haka, wani nau'in canji na baya.

Na farko, kadan game da yadda Qemu ke aiki. Da fatan za a gafarta mini nan da nan: Ni ba ƙwararren mai haɓaka Qemu bane kuma ra'ayina na iya zama kuskure a wasu wurare. Kamar yadda suke cewa, "ra'ayin ɗalibin ba dole ba ne ya yi daidai da ra'ayin malami, Peano's axiomatics da hankali." Qemu yana da ƙayyadaddun adadin kayan gine-ginen baƙi masu goyan bayan kuma ga kowane akwai kundin adireshi kamar target-i386. Lokacin ginawa, zaku iya tantance goyan bayan gine-ginen baƙi da yawa, amma sakamakon zai zama binaries da yawa. Lambar don tallafawa gine-ginen baƙo, bi da bi, yana haifar da wasu ayyukan Qemu na ciki, wanda TCG (Tiny Code Generator) ya rigaya ya zama lambar inji don gine-ginen rundunar. Kamar yadda aka bayyana a cikin fayil ɗin readme dake cikin tcg directory, wannan asalin wani yanki ne na mai tarawa C na yau da kullun, wanda daga baya aka daidaita don JIT. Saboda haka, alal misali, gine-ginen da aka yi niyya dangane da wannan takarda ba gine-ginen baƙo ba ne, amma gine-ginen masauki. A wani lokaci, wani sashi ya bayyana - Tiny Code Interpreter (TCI), wanda yakamata ya aiwatar da lamba (kusan ayyukan cikin gida iri ɗaya) idan babu janareta na lamba don takamaiman gine-ginen rundunar. A zahiri, kamar yadda takaddun ta ke faɗi, wannan mai fassara bazai koyaushe yin aiki kamar janareta na lambar JIT ba, ba kawai gwargwadon sauri ba, har ma da inganci. Ko da yake ban tabbata cewa kwatancinsa ya dace ba.

Da farko na yi ƙoƙarin yin cikakken TCG baya, amma da sauri na ruɗe a cikin lambar tushe da cikakken bayanin umarnin bytecode, don haka na yanke shawarar naɗa mai fassarar TCI. Wannan ya ba da fa'idodi da yawa:

  • Lokacin aiwatar da janareta na lamba, ba za ku iya duba bayanin umarnin ba, amma a lambar fassarar
  • za ku iya samar da ayyuka ba ga kowane tubalan fassarar da aka ci karo da su ba, amma, alal misali, kawai bayan aiwatar da kisa na ɗari
  • idan lambar da aka ƙirƙira ta canza (kuma wannan yana da alama yana yiwuwa, yin la'akari da ayyuka tare da sunaye waɗanda ke ɗauke da facin kalmar), zan buƙaci soke lambar JS da aka samar, amma aƙalla zan sami wani abu don sake haɓaka shi daga.

Game da batu na uku, ban tabbata cewa faci zai yiwu ba bayan an aiwatar da lambar a karon farko, amma maki biyu na farko sun isa.

Da farko, an ƙirƙiri lambar a cikin nau'i na babban canji a adireshin ainihin umarnin bytecode, amma sai, tunawa da labarin game da Emscripten, inganta haɓakar JS da aka sake dawowa, na yanke shawarar samar da ƙarin lambar ɗan adam, musamman tun da empirically. ya nuna cewa kawai hanyar shiga cikin toshe fassarar shine Farawa. Ba da jimawa ba sai an yi, bayan ɗan lokaci muna da janareta na lamba wanda ya haifar da lamba tare da ifs (duk da cewa ba tare da madaukai ba). Amma mummunan sa'a, ya fadi, yana ba da sakon cewa umarnin ya kasance na wasu tsayin da ba daidai ba. Bugu da ƙari, umarni na ƙarshe a wannan matakin maimaitawa shine brcond. Da kyau, zan ƙara rajistan bincike iri ɗaya ga tsarar wannan umarni kafin da bayan kiran maimaitawa kuma… ba ɗayansu da aka kashe ba, amma bayan canjin shedar har yanzu sun kasa. A ƙarshe, bayan nazarin lambar da aka ƙirƙira, na gane cewa bayan sauyawa, ana sake ɗora mai nuni ga koyarwar yanzu daga tarin kuma ƙila an sake rubuta shi ta hanyar lambar JavaScript da aka samar. Hakan kuwa ya kasance. Ƙirƙirar buffer daga megabyte ɗaya zuwa goma bai haifar da komai ba, kuma ya bayyana cewa janareta na code yana gudana a cikin da'ira. Dole ne mu duba cewa ba mu wuce iyakokin tarin fuka na yanzu ba, kuma idan muka yi, sai a ba da adireshin tarin tarin fuka na gaba tare da alamar cirewa don mu ci gaba da aiwatar da kisa. Bugu da ƙari, wannan yana magance matsalar "waɗanne ayyukan da aka samar ya kamata a lalace idan wannan yanki na bytecode ya canza?" - kawai aikin da ya dace da wannan toshewar fassarar yana buƙatar ɓarna. Af, ko da yake na cire duk abin da ke cikin Chromium (tun da na yi amfani da Firefox kuma yana da sauƙi a gare ni in yi amfani da mai bincike daban don gwaje-gwaje), Firefox ta taimaka mini in gyara rashin daidaituwa tare da ma'aunin asm.js, bayan haka lambar ta fara aiki da sauri a ciki. Chromium

Misalin lambar ƙirƙira

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

ƙarshe

Don haka, har yanzu ba a kammala aikin ba, amma na gaji da kawo wannan ginin na dogon lokaci a asirce. Saboda haka, na yanke shawarar buga abin da nake da shi a yanzu. Lambar tana da ɗan ban tsoro a wurare, saboda wannan gwaji ne, kuma ba a bayyana a gaba abin da ake buƙatar yi ba. Wataƙila, to yana da kyau a ba da ayyukan atomic na yau da kullun a saman wasu ƙarin sigar Qemu na zamani. A halin yanzu, akwai zare a cikin Gita a cikin tsarin blog: ga kowane "matakin" wanda aka ƙaddamar da akalla ko ta yaya, an ƙara cikakken sharhi a cikin Rashanci. A haƙiƙa, wannan labarin ya kasance mai faɗi sosai game da ƙarshe git log.

Kuna iya gwada shi duka a nan (hattara da zirga-zirga).

Abin da ke aiki tukuna:

  • x86 Virtual processor yana aiki
  • Akwai samfurin aiki na janareta na lambar JIT daga lambar injin zuwa JavaScript
  • Akwai samfuri don haɗa wasu gine-ginen baƙo na 32-bit: a yanzu za ku iya sha'awar Linux don daskarewar gine-ginen MIPS a cikin mai bincike a matakin lodi.

Me kuma za ku iya yi

  • Saurin kwaikwaya. Ko da a cikin yanayin JIT da alama yana gudana a hankali fiye da Virtual x86 (amma akwai yuwuwar Qemu gabaɗaya tare da kayan aiki da yawa da aka kwaikwayi da gine-gine)
  • Don yin mu'amala ta yau da kullun - a gaskiya, ni ba mai haɓaka gidan yanar gizo ba ne, don haka a yanzu na sake yin daidaitaccen harsashi na Emscripten kamar yadda zan iya.
  • Yi ƙoƙarin ƙaddamar da ƙarin hadaddun ayyukan Qemu - sadarwar sadarwar, ƙaura VM, da sauransu.
  • UPS: kuna buƙatar ƙaddamar da ƴan ci gaban ku da rahotannin kwaro zuwa Emscripten sama, kamar yadda masu ɗaukar kaya na baya na Qemu da sauran ayyukan suka yi. Godiya gare su don samun damar yin amfani da gudummawarsu ga Emscripten a fakaice a matsayin wani ɓangare na aikina.

source: www.habr.com

Add a comment