Qemu.js miaraka amin'ny fanohanan'ny JIT: mbola azonao atao ny mampihemotra ny mince

Taona vitsy lasa izay i Fabrice Bellard nosoratan'i jslinux dia emulator PC voasoratra amin'ny JavaScript. Taorian'izay dia nisy mihoatra izany farafaharatsiny virtoaly x86. Saingy izy rehetra, raha ny fahalalako azy, dia mpandika teny, raha i Qemu, nosoratan'i Fabrice Bellard teo aloha ihany, ary, angamba, izay emulator maoderina manaja tena, dia mampiasa JIT compilation ny code guest ho code system host. Toa ahy fa tonga ny fotoana hampiharana ny asa mifanohitra amin'ny iray izay mamaha ny navigateur: JIT compilation ny code machine ho JavaScript, izay toa mitombina indrindra amin'ny port Qemu. Toa, nahoana Qemu, misy emulators tsotra sy mora ampiasaina - mitovy VirtualBox, ohatra - napetraka sy miasa. Saingy manana endri-javatra mahaliana maromaro i Qemu

  • loharano misokatra
  • fahafahana miasa tsy misy mpamily kernel
  • fahafahana miasa amin'ny fomba mpandika teny
  • fanohanana ho an'ny maro be ny trano fandraisam-bahiny sy ny vahiny

Momba ny teboka fahatelo, dia azoko hazavaina izao fa raha ny marina, amin'ny fomba TCI, dia tsy ny torolalan'ny milina vahiny no adika, fa ny bytecode azo avy amin'izy ireo, saingy tsy manova ny maha-izy azy izany - mba hananganana sy hihazakazaka. Qemu amin'ny maritrano vaovao, raha tsara vintana ianao, dia ampy ny A C compiler - ny fanoratana code generator dia azo ahemotra.

Ary ankehitriny, taorian'ny roa taona nitazonana ny code source Qemu tamin'ny fotoana malalaka, dia nisy prototype miasa, izay ahafahanao mihazakazaka, ohatra, Kolibri OS.

Inona no atao hoe Emscripten

Amin'izao fotoana izao, maro ny compiler niseho, ny vokatra farany dia JavaScript. Ny sasany, toa ny Type Script, dia natao ho fomba tsara indrindra hanoratana ho an'ny tranonkala. Mandritra izany fotoana izany, ny Emscripten dia fomba iray haka ny kaody C na C ++ efa misy ary manangona azy ho endrika azo vakiana amin'ny navigateur. On ity pejy ity Nanangona seranana maro misy fandaharana malaza izahay: etoOhatra, azonao jerena ny PyPy - raha ny marina, milaza izy ireo fa efa manana JIT. Raha ny marina, tsy ny programa rehetra dia azo amboarina fotsiny ary mandeha amin'ny navigateur - misy isa Toetoetra, izay tsy maintsy atrehinao anefa, araka ny voalazan'ny soratra eo amin'io pejy io ihany hoe “Emscripten dia azo ampiasaina hanangonana saika izay rehetra portable C/C++ code to JavaScript". Izany hoe, misy hetsika maromaro tsy voafaritra araka ny fenitra, fa matetika miasa amin'ny x86 - ohatra, ny fidirana tsy mifanentana amin'ny variables, izay voarara amin'ny ankapobeny amin'ny architectures sasany. Amin'ny ankapobeny , Qemu dia programa cross-platform ary , te-hino aho, ary tsy mbola misy fitondran-tena tsy voafaritra be dia be izy io - alaivo ary amboary, dia mitsambikina kely amin'ny JIT - dia vita ianao! raharaha...

Andrana voalohany

Amin'ny ankapobeny, tsy izaho no olona voalohany tonga tamin'ny hevitra handefasana Qemu amin'ny JavaScript. Nisy fanontaniana napetraka tao amin'ny forum ReactOS raha azo atao izany amin'ny fampiasana Emscripten. Na dia teo aloha aza dia nisy ny tsaho fa i Fabrice Bellard no nanao izany manokana, saingy niresaka momba ny jslinux izahay, izay, raha ny fahalalako azy, dia fiezahana hanatratrarana fampisehoana ampy amin'ny JS, ary nosoratana hatrany am-boalohany. Taty aoriana dia nosoratana ny Virtual x86 - loharanom-baovao tsy fantatra no navoaka ho azy, ary, araka ny voalaza, ny "realism" lehibe kokoa amin'ny emulation dia nahafahana nampiasa ny SeaBIOS ho firmware. Fanampin'izay, nisy andrana iray farafahakeliny handefasana an'i Qemu mampiasa Emscripten - nanandrana nanao izany aho socketpair, fa ny fampandrosoana, raha ny fahazoako azy, dia nivaingana.

Noho izany, toa, ireto ny loharano, eto ny Emscripten - raiso ary amboary. Fa misy ihany koa ny tranomboky iankinan'ny Qemu, sy ny tranomboky iankinan'ireo tranomboky ireo, sns., ary ny iray amin'izy ireo dia libffi, izay miankina amin'ny glib. Nisy tsaho tao amin'ny Internet fa misy iray ao amin'ireo seranan-tsambon'ny trano famakiam-boky ho an'ny Emscripten, saingy sarotra inoana izany: voalohany, tsy natao ho mpanangom-baovao izy io, faharoa, ambany loatra izy io. tranomboky mba haka fotsiny, ary hanangona ao amin'ny JS. Ary tsy resaka fampidirana fivoriambe fotsiny izany - angamba, raha manodina azy ianao, ho an'ny fivoriambe fiantsoana sasany dia azonao atao ny mamorona hevitra ilaina amin'ny stack ary miantso ny fiasa tsy misy azy ireo. Saingy zavatra sarotra ny Emscripten: mba hahatonga ny kaody vokarina ho fantatry ny navigateur JS engine optimizer, dia misy tetika ampiasaina. Indrindra indrindra, ilay antsoina hoe relooping - mpamorona kaody mampiasa ny LLVM IR voaray miaraka amin'ny toromarika transition abstract sasany dia manandrana mamerina ny ifs, loops, sns. Eny ary, ahoana no ampitaina amin'ny asa ireo hevitra? Mazava ho azy, toy ny tohan-kevitra amin'ny JS miasa, izany hoe, raha azo atao, tsy amin'ny alalan'ny stack.

Tany am-piandohana dia nisy hevitra hanoratra fanoloana libffi amin'ny JS fotsiny ary hanao fitsapana mahazatra, saingy tamin'ny farany dia very hevitra aho momba ny fomba hanaovana ny rakitra lohako mba hiarahan'izy ireo amin'ny code efa misy - inona no azoko atao, araka ny filazan'izy ireo hoe: "Sarotra be ve ny asa "Adala ve isika?" Tsy maintsy nampita libffi ho any amin'ny architecture hafa aho, raha lazaina izany - soa ihany fa Emscripten dia manana macros roa ho an'ny fivoriambe inline (amin'ny Javascript, eny - eny, na inona na inona ny maritrano, ka ny assembler), ary ny fahafahana mampandeha kaody vokarina amin'ny lalitra. Amin'ny ankapobeny, rehefa avy nijery ireo sombintsombin'ny libffi miankina amin'ny sehatra nandritra ny fotoana kelikely, dia nahazo code compilable aho ary nihazakazaka tamin'ny fitsapana voalohany hitako. Gaga aho fa nahomby ilay fitsapana. Gaga tamin'ny fahaizako - tsy vazivazy, niasa hatramin'ny fanombohana voalohany - izaho, izay mbola tsy mino ny masoko, dia nandeha nijery indray ny code aterak'izany, mba hanombanana hoe aiza no handavaka manaraka. Taty aoriana aho dia lasa nijaly fanindroany - ny hany zavatra nataoko dia ffi_call - Nitatitra antso nahomby io. Tsy nisy antso mihitsy. Noho izany dia nandefa ny fangatahako fisintonana voalohany aho, izay nanitsy ny fahadisoana tamin'ny fitsapana izay mazava ho an'ny mpianatra Olympiad - tsy tokony hampitahaina amin'ny isa tena izy a == b ary na dia ahoana aza a - b < EPS - mila tadidinao koa ilay module, raha tsy izany dia hitovy be amin'ny 0/1 ny 3... Amin'ny ankapobeny dia tonga amin'ny seranan-tsambo libffi aho, izay mandalo fitsapana tsotra indrindra, ary misy ny glib. compiled - Nanapa-kevitra aho fa ilaina izany, ampiako izany any aoriana. Raha mijery ny ho avy aho dia hilaza fa, araka ny hita, ny compiler dia tsy nampiditra ny libffi amin'ny code farany.

Saingy, araka ny efa nolazaiko, dia misy fetrany, ary eo amin'ny fampiasana maimaim-poana ny fitondran-tena tsy voafaritra, misy endri-javatra tsy mahafinaritra kokoa nafenina - JavaScript by design dia tsy manohana multithreading miaraka amin'ny fahatsiarovana iombonana. Amin'ny ankapobeny dia azo antsoina hoe hevitra tsara izany, fa tsy ho an'ny code porting izay mifamatotra amin'ny kofehy C ny maritrano. Amin'ny ankapobeny, Firefox dia manandrana manohana ireo mpiasa ifampizarana, ary Emscripten dia manana fampiharana pthread ho azy ireo, saingy tsy te hiankina amin'izany aho. Tsy maintsy nesoriko tsikelikely ny multithreading avy amin'ny kaody Qemu - izany hoe, fantaro hoe aiza no mandeha ny kofehy, mamindra ny vatan'ny tadivavarana mandeha amin'ity kofehy ity amin'ny fiasa misaraka, ary miantsoa tsirairay avy amin'ny tadivavarana lehibe.

Faharoa faharoa

Tamin'ny fotoana iray dia nanjary nazava fa mbola teo ny olana, ary tsy hitondra soa akory ny fanosehana tsangam-bato manodidina ny kaody. Famaranana: mila mandamina ny dingana amin'ny fampidirana crutches isika. Noho izany dia nalaina ny version 2.4.1, izay vaovao tamin'izany fotoana izany (fa tsy 2.5.0, satria, iza no mahalala fa hisy bibikely ao amin'ny dikan-teny vaovao izay tsy mbola tratra, ary ampy ny bibikely ahy. ), ary ny zavatra voalohany nataoko dia ny namerina nanoratra izany soa aman-tsara thread-posix.c. Eny ary, izany hoe azo antoka: raha nisy nanandrana nanao fandidiana nitarika ho amin'ny fanakanana, dia nantsoina avy hatrany ilay asa abort() - mazava ho azy fa tsy nahavaha ny olana rehetra indray mandeha izany, fa farafaharatsiny dia nahafinaritra kokoa noho ny fandraisana an-tsoratra tsy mifanaraka.

Amin'ny ankapobeny, ny safidy Emscripten dia tena manampy amin'ny fandefasana code amin'ny JS -s ASSERTIONS=1 -s SAFE_HEAP=1 - izy ireo dia mahazo karazana fihetsika tsy voafaritra, toy ny antso amin'ny adiresy tsy mifanentana (izay tsy mifanaraka amin'ny fehezan-dalàna ho an'ny array voatendry toy ny HEAP32[addr >> 2] = 1) na fiantsoana asa miaraka amin'ny isa diso hevitra.

Raha ny marina, olana misaraka ny fahadisoana amin'ny fampifanarahana. Araka ny efa nolazaiko, Qemu dia manana backend fandikana "miharatsy" ho an'ny famokarana kaody TCI (mpandika kaody kely), ary hanangana sy hampandehanana Qemu amin'ny maritrano vaovao, raha tsara vintana ianao dia ampy ny compiler C. Keywords "raha tsara vintana ianao". Tsy tsara vintana aho, ary hita fa ny TCI dia mampiasa fidirana tsy mifanentana amin'ny famakiana ny bytecode. Izany hoe, amin'ny karazana ARM rehetra sy ny maritrano hafa miaraka amin'ny fidirana azo alaina, Qemu dia manangona satria manana backend TCG mahazatra izy ireo izay miteraka kaody teratany, fa ny TCI dia hiasa amin'izy ireo dia fanontaniana hafa. Na izany aza, araka ny hita, ny antontan-taratasin'ny TCI dia nanondro mazava zavatra mitovy. Vokatr'izany dia nampidirina tao amin'ny kaody ny antso ho an'ny famakiana tsy mifanaraka, izay hita tany amin'ny faritra hafa ao Qemu.

Fandringanana antontam-bato

Vokatr'izany dia nahitsy ny fidirana tsy mifanaraka amin'ny TCI, noforonina ny loop lehibe iray izay antsoina hoe processeur, RCU ary zavatra kely hafa. Ary noho izany dia manomboka Qemu aho miaraka amin'ny safidy -d exec,in_asm,out_asm, izay midika fa mila milaza hoe iza amin'ireo bloc of code no tanterahana, ary koa amin'ny fotoana fampielezam-peo hanoratana hoe inona ny kaody vahiny, inona no lasa kaody mpampiantrano (amin'ity tranga ity, bytecode). Manomboka izany, manatanteraka sakana fandikan-teny maromaro, manoratra ny hafatra debug navelako fa hanomboka izao ny RCU ary ... fianjerana abort() ao anatin'ny asa iray free(). Amin'ny fikojakojana ny asa free() Hitanay fa tao amin'ny lohatenin'ny bloc heap, izay mipetraka amin'ny bytes valo mialoha ny fahatsiarovana nomena, fa tsy ny haben'ny sakana na zavatra mitovy amin'izany, dia nisy fako.

Famotehana ny antontam - tena mahafatifaty ... Amin'ny toe-javatra toy izany, misy fanafody mahasoa - avy amin'ny (raha azo atao) avy amin'ny loharano iray ihany, manangona binary teratany ary mandehana eo ambanin'ny Valgrind. Rehefa afaka kelikely, dia vonona ny binary. Alefako miaraka amin'ireo safidy mitovy ihany izany - mianjera izy na dia mandritra ny fanombohana aza, alohan'ny hahatongavana amin'ny famonoana. Tsy mahafinaritra, mazava ho azy - toa tsy mitovy ny loharanon-karena, izay tsy mahagaga, satria configure scouted ny safidy hafa kely, fa manana Valgrind aho - aloha hamboariko ity bibikely ity, ary avy eo, raha tsara vintana aho. , hiseho ilay tany am-boalohany. Mitovy amin'izany koa no ataoko eo ambanin'ny Valgrind... Y-y-y, y-y-y, uh-uh, nanomboka izany, nandeha tamin'ny fanombohana ara-dalàna ary nifindra tamin'ny alàlan'ny bug tany am-boalohany tsy nisy fampitandremana iray momba ny fidirana amin'ny fahatsiarovana diso, tsy lazaina intsony ny fianjerana. Ny fiainana, araka ny filazan'izy ireo, dia tsy nanomana ahy ho amin'izany - ny programa fianjerana dia mijanona rehefa natomboka tamin'ny Walgrind. Zava-miafina ny zava-nisy. Ny heveriko dia hoe indray mandeha teo amin'ny manodidina ny fampianarana ankehitriny taorian'ny fianjerana nandritra ny fanombohana, dia nampiseho asa ny gdb memset-a misy tondro manankery mampiasa na mmx, na xmm rejistra, dia mety ho karazana fahadisoana fampifanarahana izany, na dia mbola sarotra inoana aza izany.

Eny, toa tsy manampy eto i Valgrind. Ary eto no nanomboka ny zavatra maharikoriko indrindra - toa manomboka aza ny zava-drehetra, saingy nianjera noho ny antony tsy fantatra noho ny zava-nitranga iray izay mety ho nisy toromarika an-tapitrisany maro lasa izay. Nandritra ny fotoana ela dia tsy nazava ny fomba hanatonana. Tamin'ny farany dia tsy maintsy nipetraka sy nanao debug aho. Nasehon'ny fanontana izay nanoratana indray ny lohapejy fa tsy toy ny isa izy io, fa karazana angon-drakitra mimari-droa. Ary indro ary indro, hita ao amin'ny fichier BIOS io tady binary io - izany hoe, izao dia azo atao ny milaza amin'ny fahatokiana mitombina fa fihoaram-pefy io, ary mazava ho azy fa nosoratana tamin'ity buffer ity. Eny ary, misy zavatra toy izao - ao amin'ny Emscripten, soa ihany fa tsy misy randomization ny habaka adiresy, tsy misy lavaka koa ao, ka afaka manoratra any amin'ny toerana eo afovoan'ny fehezan-dalàna ianao hamoaka data amin'ny alàlan'ny tondro avy amin'ny fandefasana farany, jereo ny angon-drakitra, jereo ny tondro, ary , raha tsy niova izany, mahazo sakafo ho an'ny fisainana. Marina fa mila roa minitra vao mifandray rehefa misy fiovana, nefa inona no azonao atao? Vokatr'izany dia nisy tsipika manokana hita izay nandika ny BIOS avy amin'ny buffer vonjimaika mankany amin'ny fahatsiarovana vahiny - ary, tokoa, tsy ampy ny toerana ao amin'ny buffer. Ny fitadiavana ny loharanon'io adiresy buffer hafahafa io dia niteraka fiasa iray qemu_anon_ram_alloc anaty rakitra oslib-posix.c - Ny lojika teo dia izao: indraindray mety ilaina ny mampifanaraka ny adiresy amin'ny pejy lehibe misy habe 2 MB, izany no hanontaniantsika. mmap aloha kely kokoa, ary avy eo dia hamerina ny tafahoatra miaraka amin'ny fanampiana munmap. Ary raha tsy ilaina ny fampifanarahana toy izany, dia hasehontsika ny valiny fa tsy 2 MB getpagesize() - mmap mbola hanome adiresy mifanitsy izany... Ka ao amin'ny Emscripten mmap miantso fotsiny malloc, fa mazava ho azy fa tsy mifanaraka amin'ny pejy izany. Amin'ny ankapobeny, voahitsy tamin'ny alalan'ny fanovana ny bug izay nahasosotra ahy nandritra ny roa volana двух andalana.

Endri-javatra ny fiantsoana asa

Ary izao ny processeur dia manisa zavatra, Qemu tsy mianjera, fa ny efijery dia tsy mandeha, ary ny processeur dia miditra haingana amin'ny tadivavarana, mitsara ny vokatra. -d exec,in_asm,out_asm. Nipoitra ny petra-kevitra iray: tsy tonga ny fiatoana fameram-potoana (na, amin'ny ankapobeny, ny fahatapahana rehetra). Ary raha ny marina, raha manaisotra ny fanelingelenana avy amin'ny fivoriamben'ny teratany ianao, izay noho ny antony sasany dia niasa, dia mahazo sary mitovy amin'izany ianao. Saingy tsy izany mihitsy no valiny: ny fampitahana ireo soritra navoaka tamin'ny safidy etsy ambony dia nampiseho fa nisaraka aloha ny lalan'ny famonoana. Eto dia tsy maintsy lazaina fa fampitahana ny zavatra voarakitra mampiasa ny launcher emrun Ny famoahana ny famoahana miaraka amin'ny vokatra avy amin'ny fivorian'ny teratany dia tsy dingana mekanika tanteraka. Tsy fantatro tsara ny fomba ifandraisan'ny programa mandeha amin'ny navigateur emrun, fa ny andalana sasany ao amin'ny fivoahana dia mivadika ho amboarina, ka ny fahasamihafana eo amin'ny diff dia tsy mbola antony hiheverana fa nisaraka ny lalana. Amin'ny ankapobeny, dia nanjary nazava fa araka ny toromarika ljmpl misy ny fifindrana mankany amin'ny adiresy samihafa, ary ny bytecode vokarina dia tsy mitovy amin'ny fototra: ny iray dia misy torolàlana hiantsoana asa mpanampy, ny iray tsy. Rehefa avy nijery ny toromarika sy nandinika ny kaody izay mandika ireo torolalana ireo, dia nanjary nazava fa, voalohany, avy hatrany eo amin'ny rejisitra. cr0 Nisy fandraketana natao - tamin'ny fampiasana mpanampy ihany koa - izay nanova ny processeur ho amin'ny fomba voaaro, ary faharoa, fa ny js version dia tsy niova mihitsy tamin'ny fomba voaaro. Saingy ny zava-misy dia ny endri-javatra iray hafa amin'ny Emscripten dia ny fisalasalany handefitra fehezan-dalàna toy ny fampiharana ny torolàlana. call ao amin'ny TCI, izay miteraka karazana karazana long long f(int arg0, .. int arg9) - Ny asa dia tsy maintsy antsoina miaraka amin'ny isan'ny tohan-kevitra marina. Raha voahitsakitsaka io fitsipika io, miankina amin'ny toe-javatra debug, ny programa dia hianjera (izay tsara) na hiantso ny asa diso mihitsy (izay mampalahelo ny debug). Misy ihany koa ny safidy fahatelo - mamela ny taranaka wrappers izay manampy / manala ny tohan-kevitra, fa amin'ny fitambarany ireo wrappers dia maka toerana be dia be, na dia eo aza ny zava-misy fa raha ny marina mila mihoatra ny zato wrapper. Mampalahelo tokoa izany, saingy nisy olana lehibe kokoa: tao amin'ny fehezan-dalàna novokarin'ny fiasa wrapper dia niova fo sy niova ny hevitra, saingy indraindray ny fiasa miaraka amin'ireo hevitra novolavolaina dia tsy nantsoina - tsara, toy ny ao amin'ny ny fampiharana libffi ahy. Izany hoe tsy novonoina fotsiny ny mpanampy sasany.

Soa ihany fa Qemu dia manana lisitry ny mpanampy azo vakiana amin'ny endrika fisie lohapejy toy ny

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

Mampihomehy ihany no ampiasaina: voalohany, ny macro dia nofaritana tamin'ny fomba hafahafa indrindra DEF_HELPER_n, ary mandehana avy eo helper.h. Hatramin'ny nitarina ny macro ho fanombohana rafitra sy faingo, ary avy eo dia faritana ny array, ary ho solon'ny singa - #include <helper.h> Vokatr'izany dia nanana fahafahana nanandrana ny tranomboky tany am-piasana aho pyparsing, ary nosoratana ny script iray izay mamokatra ireo fonosana ireo ho an'ny asa tena ilaina.

Ary noho izany, taorian'izay dia toa niasa ny processeur. Toa satria tsy natomboka mihitsy ny efijery, na dia afaka nandeha tamin'ny fivoriamben'ny teratany aza ny memtest86+. Eto dia ilaina ny manazava fa ny code Qemu block I/O dia voasoratra amin'ny coroutines. Ny Emscripten dia manana ny fampiharana azy manokana, saingy mbola mila tohanana ao amin'ny code Qemu, ary azonao atao ny manala ny processeur izao: Qemu dia manohana safidy -kernel, -initrd, -append, izay ahafahanao manamboatra Linux na, ohatra, memtest86+, tsy mampiasa fitaovana fanakanana mihitsy. Saingy izao no olana: ao amin'ny fivoriambe teratany dia afaka mahita ny famoahana kernel Linux amin'ny console miaraka amin'ny safidy -nographic, ary tsy misy vokatra avy amin'ny navigateur mankany amin'ny terminal izay nanombohana azy emrun, tsy tonga. Izany hoe, tsy mazava: tsy mandeha ny processeur na tsy mandeha ny famoahana sary. Dia tonga tao an-tsaiko ny hiandry kely. Hita fa “tsy matory ny processeur, fa mikitroka moramora fotsiny”, ary rehefa afaka dimy minitra teo ho eo, dia nanipy hafatra marobe teo amin'ny console ny kernel ary nitohy nihantona. Nanjary nazava fa ny processeur, amin'ny ankapobeny, dia miasa, ary mila mandavaka ny fehezan-dalàna amin'ny fiasana amin'ny SDL2 isika. Indrisy anefa fa tsy haiko ny mampiasa an'io tranomboky io, ka tany amin'ny toerana sasany dia tsy maintsy nanao fihetsika kisendrasendra aho. Tamin'ny fotoana iray, ny tsipika parallel0 dia nipoitra teo amin'ny efijery tamin'ny fiaviana manga, izay nanoro hevitra sasantsasany. Tamin'ny farany dia hita fa ny olana dia ny Qemu manokatra varavarankely virtoaly maromaro ao anaty varavarankely iray, izay ahafahanao mifamadika amin'ny fampiasana Ctrl-Alt-n: miasa amin'ny fananganana teratany izy io, fa tsy ao amin'ny Emscripten. Rehefa avy manala ny tsy ilaina varavarankely mampiasa safidy -monitor none -parallel none -serial none ary ny toromarika mba hanesorana indray ny efijery manontolo amin'ny frame tsirairay, dia nandeha tampoka ny zava-drehetra.

Coroutines

Noho izany, ny emulation ao amin'ny navigateur dia miasa, saingy tsy afaka mampandeha zavatra mahaliana tokana ianao ao anatiny, satria tsy misy sakana I / O - mila mampihatra fanohanana ho an'ny coroutine ianao. Efa manana backend coroutine maromaro i Qemu, saingy noho ny toetran'ny JavaScript sy ny mpamorona kaody Emscripten dia tsy afaka manomboka manao juggling stacks ianao. Hoatran'ny hoe “lasa daholo, nesorina ny plaster”, saingy efa nikarakara ny zava-drehetra ireo mpamorona Emscripten. Mampihomehy tokoa no nampiharina: andao hiantso antso toy ity mampiahiahy ity emscripten_sleep sy ny maro hafa mampiasa ny mekanika Asyncify, ary koa ny antso an-tariby sy antso amin'ny asa rehetra izay mety hitranga amin'ny iray amin'ireo tranga roa teo aloha. Ary ankehitriny, alohan'ny fiantsoana mampiahiahy tsirairay, dia hifidy contexte async isika, ary avy hatrany aorian'ny antso dia hojerentsika raha nisy antso asynchronous nitranga, ary raha misy izany, dia hovonjentsika ny variable eo an-toerana rehetra amin'ity context async ity, manondro izay fiasa hamindra ny fanaraha-maso amin'ny fotoana ilantsika hanohizana ny famonoana, ary hiala amin'ny fiasa ankehitriny. Eo no misy sehatra ahafahana mandalina ny vokany nandanilany foana - ho an'ny filàna fanohizana ny famonoana kaody aorian'ny fiverenana avy amin'ny antso asynchronous, ny compiler dia mamorona "stubs" amin'ny asa manomboka aorian'ny antso mampiahiahy - toy izao: raha misy antso mampiahiahy, dia hiitatra any amin'ny n/2 ilay asa. fotoana - mbola izany, raha tsy Tadidinao fa aorian'ny antso tsirairay mety tsy mifanentana dia mila manampy ny fitehirizana ny fari-piadidiana eo an-toerana ianao amin'ny fiasa voalohany. Taorian'izay dia tsy maintsy nanoratra script tsotra amin'ny Python mihitsy aza aho, izay mifototra amin'ny andiana asa be mpampiasa indrindra izay heverina fa "tsy mamela ny asynchrony handalo" (izany hoe, fampiroboroboana stack sy izay rehetra nolazaiko fotsiny dia tsy miasa ao amin'izy ireo), dia manondro antso amin'ny alàlan'ny tondro izay tsy tokony horaharahain'ny mpanangona ny asa mba tsy hoheverina ho asynchronous ireo fiasa ireo. Ary avy eo ny rakitra JS ambanin'ny 60 MB dia mazava ho azy fa be loatra - andao atao hoe 30 farafaharatsiny. Na izany aza, indray mandeha aho dia nanangana script fivoriambe, ary nandroaka tsy nahy ny safidy rohy, anisan'izany ny -O3. Mihazakazaka ny kaody novokarina aho, ary mandany fahatsiarovana sy fianjerana ny Chromium. Dia nojereko tsy nahy izay tadiaviny alaina... Eny ary, inona no azoko lazaina, ho nivaingana koa aho raha nasaina nandalina tamim-pitandremana sy nanatsara ny Javascript 500+ MB.

Indrisy anefa, ny fisavana ao amin'ny kaody famakiam-boky fanohanana Asyncify dia tsy sariaka tanteraka longjmp-s izay ampiasaina amin'ny code processeur virtoaly, fa taorian'ny patch kely izay manafoana ireo fisavana ireo ary mamerina amin'ny laoniny ny toe-javatra toy ny hoe tsara ny zava-drehetra, dia niasa ny code. Ary avy eo dia nisy zavatra hafahafa nanomboka: indraindray ny fisavana ny kaody synchronization dia nipoitra - mitovy amin'ny fandravana ny kaody raha toa ka, araka ny lojikan'ny famonoana, dia tokony ho voasakana - nisy nanandrana naka mutex efa voasambotra. Soa ihany fa tsy olana lojika izany ao amin'ny code serialised - Nampiasa tsotra fotsiny ny fampandehanana mahazatra mahazatra nomen'i Emscripten aho, fa indraindray ny antso asynchronous dia hamaha tanteraka ny stack, ary amin'izay fotoana izay dia tsy hahomby izany. setTimeout avy amin'ny loop lehibe - noho izany, ny code dia niditra tao amin'ny main loop fa tsy nandao ny teo aloha. Avereno soratana amin'ny loop tsy manam-petra ary emscripten_sleep, ary nijanona ny olana tamin'ny mutexes. Ny kaody dia lasa lojika kokoa - na izany aza, raha ny marina, tsy manana kaody aho izay manomana ny sary mihetsika manaraka - ny processeur dia manao kajy fotsiny ary ny efijery dia havaozina tsindraindray. Na izany aza, tsy nijanona teo ny olana: indraindray ny famonoana an'i Qemu dia tapitra mangina fotsiny tsy misy maningana na fahadisoana. Tamin'izay fotoana izay dia nilavo lefona aho, fa, raha mijery ny ho avy, dia hilaza aho fa ny olana dia izao: ny code coroutine, raha ny marina, dia tsy mampiasa. setTimeout (na farafaharatsiny tsy matetika araka izay eritreretinao): asa emscripten_yield mametraka fotsiny ny saina antso asynchronous. Ny hevitra rehetra dia izay emscripten_coroutine_next dia tsy asa asynchronous: ao anatiny izy dia manamarina ny saina, mamerina azy ary mamindra ny fanaraha-maso any amin'izay ilana azy. Izany hoe, mifarana eo ny fampiroboroboana ny stack. Ny olana dia noho ny fampiasana-aorian'ny-maimaim-poana, izay niseho rehefa ny coroutine dobo dia kilemaina noho ny zava-misy fa tsy nandika andalana manan-danja ny code avy amin'ny efa misy coroutine backend, ny asa. qemu_in_coroutine niverina marina raha ny marina dia tokony hiverina diso. Nitarika antso izany emscripten_yield, teo amboniny dia tsy nisy olona teo amin'ny stack emscripten_coroutine_next, nivelatra hatrany amin'ny tampony ny antontam-bato, saingy tsia setTimeout, araka ny efa nolazaiko, dia tsy naseho.

Famoronana code JavaScript

Ary eto, raha ny marina, dia ilay nampanantenaina hoe “hamody ny hena voatoto”. Tsy dia izany loatra. Mazava ho azy, raha mihazakazaka Qemu ao amin'ny navigateur isika, ary ny Node.js ao anatiny, dia mazava ho azy, aorian'ny famoronana kaody ao Qemu dia ho diso JavaScript tanteraka isika. Na izany aza, karazana fanovana mivadika.

Voalohany, kely momba ny fomba fiasan'i Qemu. Mamelà ahy avy hatrany: Tsy mpamorona Qemu matihanina aho ary mety ho diso ny fanatsoahan-kevitro any amin'ny toerana sasany. Araka ny filazan'izy ireo, "ny hevitry ny mpianatra dia tsy voatery hifanaraka amin'ny hevitry ny mpampianatra, ny axiomatika sy ny saina mahazatra an'i Peano." Qemu dia manana maritrano vahiny tohanana maromaro ary ho an'ny tsirairay dia misy lahatahiry toy izany target-i386. Rehefa manorina ianao dia azonao atao ny mamaritra ny fanohanana ho an'ny maritrano vahiny maromaro, fa ny vokatra dia ho binary maromaro. Ny kaody hanohanana ny maritrano vahiny, kosa, dia miteraka hetsika Qemu anatiny, izay efa navadika ho code milina ho an'ny maritrano mpampiantrano ny TCG (Tiny Code Generator). Araka ny voalaza ao amin'ny rakitra readme hita ao amin'ny lahatahiry tcg, ity dia ampahany amin'ny compiler C mahazatra, izay namboarina ho an'ny JIT taty aoriana. Noho izany, ohatra, ny maritrano kendrena amin'ity antontan-taratasy ity dia tsy maritrano vahiny intsony, fa maritrano mpampiantrano. Tamin'ny fotoana iray dia nisy singa iray hafa niseho - Tiny Code Interpreter (TCI), izay tokony hanatanteraka fehezan-dalàna (saika mitovy amin'ny asa anatiny) raha tsy misy mpamorona kaody ho an'ny rafitra mpampiantrano manokana. Raha ny marina, araka ny filazan'ny antontan-taratasiny, ity mpandika teny ity dia mety tsy hanao toy ny mpamorona kaody JIT foana, tsy amin'ny haben'ny hafainganam-pandeha, fa amin'ny kalitao ihany koa. Na dia tsy azoko antoka aza fa mifanaraka tanteraka ny filazany.

Tamin'ny voalohany dia nanandrana nanao backend TCG feno aho, saingy nisavoritaka haingana tao amin'ny kaody loharano sy ny famaritana tsy mazava tsara momba ny toromarika bytecode, ka nanapa-kevitra ny hametaka ny mpandika teny TCI aho. Izany dia nanome tombony maro:

  • Rehefa mampihatra mpamorona fehezan-dalàna ianao dia tsy afaka mijery ny famaritana ny toromarika, fa ny fehezan-dalàna mpandika teny
  • afaka mamorona asa ianao tsy ho an'ny sakana fandikan-teny rehetra, fa, ohatra, aorian'ny famonoana faha-jato
  • raha miova ny code novokarina (ary toa azo atao izany, raha tsaraina amin'ny asa misy anarana misy ny teny patch), dia mila manafoana ny code JS novokarina aho, fa farafaharatsiny dia hanana zavatra hamerenana azy io aho.

Momba ny teboka fahatelo dia tsy azoko antoka fa azo atao ny mametaka rehefa vita ny kaody voalohany, fa ny teboka roa voalohany dia ampy.

Tamin'ny voalohany, ny kaody dia novokarina tamin'ny endrika switch lehibe amin'ny adiresin'ny toromarika bytecode tany am-boalohany, fa avy eo, nahatsiaro ny lahatsoratra momba ny Emscripten, ny fanatsarana ny JS niteraka sy ny relooping, dia nanapa-kevitra ny hamokatra kaody olombelona bebe kokoa, indrindra fa amin'ny empirically izany. dia hita fa ny hany fidirana ao amin'ny sakana fandikan-teny dia ny Fiantombohany. Vao tsy ela akory izay, dia nanana mpamokatra kaody izahay izay namorona kaody miaraka amin'ny ifs (na dia tsy misy tadivavarana aza). Saingy ratsy vintana, nianjera izy io, nanome hafatra fa diso ny halavan'ny toromarika. Ankoatra izany, ny toromarika farany amin'ity ambaratonga recursion ity dia brcond. Eny ary, ampiako fisavana mitovy amin'ny famokarana an'ity torolàlana ity alohan'ny sy aorian'ny antso miverimberina ary ... tsy nisy namono na iray aza, fa taorian'ny fifandimbiasana fanamafisana dia mbola tsy nahomby izy ireo. Tamin'ny farany, rehefa avy nandinika ny kaody novokarina aho dia tsapako fa taorian'ny fifandimbiasana, ny tondro mankany amin'ny torolàlana amin'izao fotoana izao dia averina avy amin'ny stack ary mety hosoloina amin'ny code JavaScript novokarina. Dia toy izany no niseho. Ny fampitomboana ny buffer avy amin'ny megabyte iray ka hatramin'ny folo dia tsy nitarika na inona na inona, ary nanjary nazava fa ny mpamorona code dia mihazakazaka amin'ny faribolana. Tsy maintsy nanamarina izahay fa tsy mihoatra ny fetran'ny TB amin'izao fotoana izao, ary raha nanao izany izahay, dia mamoaka ny adiresin'ny TB manaraka miaraka amin'ny marika minus mba hahafahantsika manohy ny famonoana. Ho fanampin'izany, dia mamaha ny olana "izay novokarina no tokony hofoanana raha toa ka niova ity ampahany amin'ny bytecode ity?" — ny fiasa mifanaraka amin'io sakana fandikan-teny io ihany no tokony hofoanana. Etsy ankilany, na dia nanala ny zava-drehetra tao amin'ny Chromium aza aho (satria mampiasa Firefox aho ary mora kokoa amiko ny mampiasa navigateur mitokana ho an'ny fanandramana), Firefox dia nanampy ahy hanitsy ny tsy mifanaraka amin'ny fenitra asm.js, ary avy eo dia nanomboka niasa haingana kokoa ny code. Chromium.

Ohatra amin'ny kaody novokarina

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

famaranana

Noho izany, mbola tsy vita ny asa, fa reraky ny manafina an-tsokosoko ity fanorenana maharitra ity ho tonga lafatra. Noho izany dia nanapa-kevitra ny hamoaka izay ananako aho amin'izao fotoana izao. Somary mampatahotra ny kaody any amin'ny toerana, satria fanandramana izany, ary tsy mazava aloha izay tokony hatao. Angamba, mendrika ny hamoahana commit atomika mahazatra eo an-tampon'ny dikan-teny maoderina kokoa an'ny Qemu. Mandra-pahatongan'izany, misy kofehy iray ao amin'ny Gita amin'ny endrika bilaogy: isaky ny “ambaratonga” izay nolaniana farafaharatsiny, dia nampiana fanehoan-kevitra amin'ny antsipiriany amin'ny teny Rosiana. Raha ny marina, ity lahatsoratra ity dia mitantara amin'ny ankapobeny ny famaranana git log.

Afaka manandrana azy rehetra ianao eto (tandremo ny fifamoivoizana).

Inona no efa miasa:

  • x86 virtoaly processeur mandeha
  • Misy prototype miasa amin'ny mpamorona kaody JIT avy amin'ny kaody milina mankany amin'ny JavaScript
  • Misy môdely amin'ny fanangonana ireo maritrano vahiny 32-bit hafa: amin'izao fotoana izao dia afaka mankafy Linux ianao noho ny maritrano MIPS mangatsiaka ao amin'ny navigateur amin'ny dingana fametrahana.

Inona koa no azonao atao

  • Manafaingana ny emulation. Na dia amin'ny fomba JIT aza dia toa mandeha miadana kokoa noho ny Virtual x86 (saingy mety misy Qemu iray manontolo miaraka amin'ny fitaovana sy ny maritrano azo alaina)
  • Mba hanaovana interface tsara - tsoriko fa tsy mpamorona tranonkala mahay aho, ka amin'izao fotoana izao dia namerina ny akorandriaka Emscripten mahazatra araka izay azoko atao aho.
  • Andramo ny manangana fiasa Qemu sarotra kokoa - tambajotra, fifindra-monina VM, sns.
  • UPS: mila mandefa ny fivoaranao vitsivitsy sy ny tatitra momba ny bibikely ianao any amin'ny Emscripten upstream, toy ny nataon'ireo mpitatitra an'i Qemu sy ireo tetikasa hafa teo aloha. Misaotra azy ireo noho ny nahafahany nampiasa an-kolaka ny fandraisany anjara tamin'ny Emscripten ho ampahany amin'ny asako.

Source: www.habr.com

Add a comment