JIT සහය ඇති Qemu.js: ඔබට තවමත් mince එක පසුපසට හැරවිය හැක

මීට වසර කිහිපයකට පෙර ෆැබ්රිස් බෙලාර්ඩ් jslinux විසින් ලියන ලදි JavaScript වලින් ලියා ඇති PC emulator වේ. ඊට පස්සේ අඩුම තරමේ තවත් තිබුණා අතථ්‍ය x86. නමුත් ඔවුන් සියල්ලෝම, මා දන්නා පරිදි, පරිවර්තකයන් වූ අතර, Qemu, බොහෝ කලකට පෙර එම Fabrice Bellard විසින් ලියන ලද අතර, බොහෝ විට, ඕනෑම ස්වයං-ගෞරවනීය නවීන ඉමුලේටරය, JIT සම්පාදනය කරන ලද ආගන්තුක කේත ධාරක පද්ධති කේතයට භාවිතා කරයි. බ්‍රව්සර් විසින් විසඳන කාර්යයට සාපේක්ෂව ප්‍රතිවිරුද්ධ කාර්යය ක්‍රියාත්මක කිරීමට කාලය එළඹ ඇති බව මට පෙනුනි: JIT යන්ත්‍ර කේතය JavaScript වෙත සම්පාදනය කිරීම, ඒ සඳහා Qemu වරායට වඩාත්ම තාර්කික බවක් පෙනෙන්නට තිබුණි. එය පෙනේ, ඇයි Qemu, සරල සහ පරිශීලක-හිතකාමී emulators ඇත - එම VirtualBox, උදාහරණයක් ලෙස - ස්ථාපනය කර ක්රියා කරයි. නමුත් Qemu හි රසවත් විශේෂාංග කිහිපයක් තිබේ

  • විවෘත මූලාශ්රය
  • කර්නල් ධාවකයක් නොමැතිව වැඩ කිරීමේ හැකියාව
  • පරිවර්තක මාදිලියේ වැඩ කිරීමේ හැකියාව
  • සත්කාරක සහ ආගන්තුක ගෘහ නිර්මාණ ශිල්පය විශාල සංඛ්‍යාවක් සඳහා සහය දක්වයි

තුන්වන කරුණ සම්බන්ධයෙන්, මට දැන් පැහැදිලි කළ හැක්කේ, ඇත්ත වශයෙන්ම, TCI මාදිලියේදී, අර්ථකථනය කරනු ලබන්නේ ආගන්තුක යන්ත්‍ර උපදෙස් නොව, ඒවායින් ලබාගත් බයිට්කේතය, නමුත් මෙය සාරය වෙනස් නොකරන බවයි - ගොඩනැගීමට සහ ධාවනය කිරීමට. නව ගෘහ නිර්මාණ ශිල්පයක් මත Qemu, ඔබ වාසනාවන්ත නම්, A C සම්පාදකයක් ප්රමාණවත්ය - කේත උත්පාදක යන්ත්රයක් ලිවීම කල් දැමිය හැකිය.

දැන්, මගේ නිදහස් කාලය තුළ Qemu ප්‍රභව කේතය සමඟ විවේකීව සම්බන්ධ වීමෙන් වසර දෙකක කාලයකට පසු, වැඩ කරන මූලාකෘතියක් දර්ශනය විය, එහි ඔබට දැනටමත් ධාවනය කළ හැකිය, උදාහරණයක් ලෙස, Kolibri OS.

Emscripten යනු කුමක්ද?

වර්තමානයේ, බොහෝ සම්පාදකයින් දර්ශනය වී ඇති අතර, එහි අවසාන ප්රතිඵලය JavaScript වේ. ටයිප් ස්ක්‍රිප්ට් වැනි සමහරක් මුලින් අදහස් කළේ වෙබය සඳහා ලිවීමට හොඳම ක්‍රමයයි. ඒ අතරම, Emscripten යනු දැනට පවතින C හෝ C++ කේතය ගෙන එය බ්‍රවුසරයේ කියවිය හැකි ආකෘතියකට සම්පාදනය කිරීමේ ක්‍රමයකි. මත මෙම පිටුව අපි සුප්‍රසිද්ධ වැඩසටහන් වල බොහෝ වරායන් එකතු කර ඇත්තෙමු: මෙහිඋදාහරණයක් ලෙස, ඔබට PyPy දෙස බැලිය හැකිය - මාර්ගය වන විට, ඔවුන් දැනටමත් JIT ඇති බව ප්රකාශ කරති. ඇත්ත වශයෙන්ම, සෑම වැඩසටහනක්ම සරලව සම්පාදනය කර බ්රවුසරයේ ධාවනය කළ නොහැක - අංකයක් තිබේ විශේෂාංග, කෙසේ වෙතත්, ඔබ ඉවසා සිටිය යුතු, කෙසේ වෙතත්, එම පිටුවේම ඇති සෙල්ලිපිය පවසන පරිදි “ඕනෑම දෙයක් පාහේ සම්පාදනය කිරීමට Emscripten භාවිතා කළ හැක අතේ ගෙන යා හැකි C/C++ code to JavaScript". එනම්, සම්මතයට අනුව නිර්වචනය නොකළ හැසිරීම් ගණනාවක් ඇත, නමුත් සාමාන්‍යයෙන් x86 මත ක්‍රියා කරයි - උදාහරණයක් ලෙස, විචල්‍යයන් වෙත නොගැලපෙන ප්‍රවේශය, සාමාන්‍යයෙන් සමහර ගෘහ නිර්මාණ ශිල්පයන්හි තහනම් වේ. සාමාන්‍යයෙන් , Qemu යනු හරස් වේදිකා වැඩසටහනක් වන අතර , මට විශ්වාස කිරීමට අවශ්‍ය වූ අතර, එහි දැනටමත් නිර්වචනය නොකළ හැසිරීම් රාශියක් අඩංගු නොවේ - එය ගෙන සම්පාදනය කරන්න, පසුව JIT සමඟ ටිකක් ටින්කර් කරන්න - ඔබ ඉවරයි! නමුත් එය නොවේ නඩුව...

පළමු උත්සාහය

සාමාන්‍යයෙන් කිවහොත්, Qemu ජාවාස්ක්‍රිප්ට් වෙත ගෙනයාමේ අදහස ඉදිරිපත් කළ පළමු පුද්ගලයා මම නොවේ. Emscripten භාවිතයෙන් මෙය කළ හැකිද යන්න ReactOS සංසදයේ ප්‍රශ්නයක් අසන ලදී. මීට පෙර පවා, ෆැබ්රිස් බෙලාර්ඩ් මෙය පුද්ගලිකව කළ බවට කටකතා පැවතුනි, නමුත් අපි කතා කළේ jslinux ගැන, එය මා දන්නා පරිදි, JS හි ප්‍රමාණවත් කාර්ය සාධනයක් අතින් ලබා ගැනීමේ උත්සාහයක් පමණක් වන අතර මුල සිටම ලියා ඇත. පසුව, අතථ්‍ය x86 ලියා ඇත - ඒ සඳහා නොපැහැදිලි මූලාශ්‍ර පළ කරන ලද අතර, ප්‍රකාශ කළ පරිදි, අනුකරණයේ වැඩි “යථාර්ථවාදය” මඟින් SeaBIOS ස්ථිරාංග ලෙස භාවිතා කිරීමට හැකි විය. ඊට අමතරව, Emscripten භාවිතයෙන් Qemu වරායට ගෙන ඒමට අවම වශයෙන් එක් උත්සාහයක්වත් තිබුණි - මම මෙය කිරීමට උත්සාහ කළෙමි socketpair, නමුත් සංවර්ධනය, මට වැටහෙන පරිදි, කැටි විය.

ඉතින්, පෙනෙන්නේ, මෙන්න මූලාශ්‍ර, මෙන්න එම්ස්ක්‍රිප්ටන් - එය ගෙන සම්පාදනය කරන්න. නමුත් Qemu යැපෙන පුස්තකාල සහ එම පුස්තකාල යැපෙන පුස්තකාල ආදිය ද ඇත, ඒවායින් එකක් වන්නේ libffi, කුමන glib මත රඳා පවතී. එම්ස්ක්‍රිප්ටන් සඳහා පුස්තකාල වරායන් විශාල එකතුවක එකක් ඇති බවට අන්තර්ජාලයේ කටකතා පැවතුනි, නමුත් එය කෙසේ හෝ විශ්වාස කිරීමට අපහසු විය: පළමුව, එය නව සම්පාදකයක් වීමට අදහස් කළේ නැත, දෙවනුව, එය ඉතා පහත් මට්ටමේ විය. පුස්තකාලය ලබා ගැනීමට සහ JS වෙත සම්පාදනය කිරීමට. එය එකලස් කිරීම් ඇතුළු කිරීම් පිළිබඳ කාරණයක් පමණක් නොවේ - බොහෝ විට, ඔබ එය විකෘති කළහොත්, සමහර ඇමතුම් සම්මුතීන් සඳහා ඔබට තොගයේ අවශ්‍ය තර්ක ජනනය කර ඒවා නොමැතිව ශ්‍රිතය ඇමතීමට හැකිය. නමුත් Emscripten යනු උපක්‍රමශීලී දෙයකි: උත්පාදනය කරන ලද කේතය බ්‍රවුසරයේ JS එන්ජින් ප්‍රශස්තකරණයට හුරුපුරුදු කිරීමට, සමහර උපක්‍රම භාවිතා කරනු ලැබේ. විශේෂයෙන්, ඊනියා relooping - සමහර වියුක්ත සංක්‍රාන්ති උපදෙස් සහිත ලැබුණු LLVM IR භාවිතා කරන කේත උත්පාදක යන්ත්‍රයක් පිළිගත හැකි ifs, loops යනාදිය ප්‍රතිනිර්මාණය කිරීමට උත්සාහ කරයි. හොඳයි, කොහොමද ශ්‍රිතයට තර්ක ඉදිරිපත් කරන්නේ? ස්වාභාවිකවම, JS ක්‍රියාකාරිත්වයට තර්ක ලෙස, එනම්, හැකි නම්, තොගය හරහා නොවේ.

මුලදී ලිබ්ෆි වෙනුවට JS සමඟ ආදේශකයක් ලිවීමට සහ සම්මත පරීක්ෂණ ක්‍රියාත්මක කිරීමට අදහසක් තිබුණි, නමුත් අවසානයේ මගේ ශීර්ෂ ලිපිගොනු පවතින කේතය සමඟ ක්‍රියා කරන පරිදි ඒවා සාදා ගන්නේ කෙසේද යන්න ගැන මම ව්‍යාකූලත්වයට පත් විය - මට කුමක් කළ හැකිද, ඔවුන් පවසන පරිදි, "කාර්යයන් එතරම් සංකීර්ණද "අපි එතරම් මෝඩද?" මට වෙනත් ගෘහ නිර්මාණ ශිල්පයකට ලිබ්ෆි පෝට් කිරීමට සිදු විය, ඒ නිසා කතා කිරීමට - වාසනාවකට මෙන්, එම්ක්‍රෝස් ඉන්ලයින් එකලස් කිරීම සඳහා මැක්‍රෝ දෙකම ඇත (ජාවාස්ක්‍රිප්ට් හි, ඔව් - හොඳයි, කුමන ගෘහ නිර්මාණ ශිල්පය වුවත්, එකලස් කරන්නා), සහ පියාසර කිරීමේදී උත්පාදනය වන කේතය ධාවනය කිරීමේ හැකියාව. සාමාන්‍යයෙන්, වේදිකාව මත යැපෙන libffi කොටස් සමඟ ටික වේලාවක් ටින්කර් කිරීමෙන් පසුව, මම සම්පාදනය කළ හැකි කේතයක් ලබා ගත් අතර මට හමු වූ පළමු පරීක්ෂණයේදී එය ධාවනය කළෙමි. මා පුදුමයට පත් කරමින්, පරීක්ෂණය සාර්ථක විය. මගේ දක්ෂතාවයෙන් මවිතයට පත් වී - විහිළුවක් නැත, එය පළමු දියත් කිරීමේ සිට ක්‍රියාත්මක විය - මම, තවමත් මගේ ඇස් විශ්වාස නොකර, ප්‍රතිඵලය වූ කේතය නැවත බැලීමට ගියෙමි, ඊළඟට හාරා ගත යුත්තේ කොතැනදැයි තක්සේරු කිරීමට. මෙන්න මම දෙවෙනි වතාවටත් පිස්සු වැටුණා - මගේ කාර්යය කළේ එකම දෙයයි ffi_call - මෙය සාර්ථක ඇමතුමක් වාර්තා කළේය. කිසිම ඇමතුමක් තිබුණේ නැහැ. එබැවින් මම මගේ පළමු ඇදීමේ ඉල්ලීම යැවූ අතර, එය ඕනෑම ඔලිම්පියාඩ් ශිෂ්‍යයෙකුට පැහැදිලි වන පරීක්ෂණයේ දෝෂයක් නිවැරදි කරන ලදී - සැබෑ සංඛ්‍යා සංසන්දනය නොකළ යුතුය. a == b සහ කෙසේද යන්න පවා a - b < EPS - ඔබ ද මොඩියුලය මතක තබා ගත යුතුය, එසේ නොමැතිනම් 0 1/3 ට බෙහෙවින් සමාන වනු ඇත ... පොදුවේ ගත් කල, මම ලිබ්ෆි හි නිශ්චිත වරායක් ඉදිරිපත් කළෙමි, එය සරලම පරීක්ෂණ සමත් වන අතර එය ග්ලිබ් සමඟ ඇත. සම්පාදනය - මම එය අවශ්ය බව තීරණය කළා, මම එය පසුව එකතු කරන්නම්. ඉදිරිය දෙස බලන විට, මම කියමි, එය සිදු වූ පරිදි, සම්පාදකය අවසන් කේතයට libffi ශ්‍රිතය ඇතුළත් කර නැත.

නමුත්, මම දැනටමත් පවසා ඇති පරිදි, යම් සීමාවන් ඇති අතර, විවිධ නිර්වචනය නොකළ හැසිරීම් වල නිදහස් භාවිතය අතර, වඩාත් අප්රසන්න අංගයක් සැඟවී ඇත - නිර්මාණය මගින් JavaScript හවුල් මතකය සමඟ බහු නූල් කිරීමට සහය නොදක්වයි. ප්‍රතිපත්තිමය වශයෙන්, මෙය සාමාන්‍යයෙන් හොඳ අදහසක් ලෙස පවා හැඳින්විය හැක, නමුත් C නූල් වලට සම්බන්ධ ගෘහනිර්මාණ කේතයක් සඳහා නොවේ. සාමාන්‍යයෙන් කථා කරන විට, ෆයර්ෆොක්ස් හවුල් සේවකයින්ට සහය වීම සම්බන්ධයෙන් අත්හදා බලමින් සිටින අතර, එම්ක්‍රිප්ටෙන් ඔවුන් සඳහා pthread ක්‍රියාත්මක කිරීමක් ඇත, නමුත් මට එය මත යැපීමට අවශ්‍ය නොවීය. මට Qemu කේතයෙන් multithreading ටිකෙන් ටික මුලිනුපුටා දැමීමට සිදු විය - එනම්, නූල් ධාවනය වන ස්ථානය සොයා ගැනීමට, මෙම ත්‍රෙඩ් එකේ ක්‍රියාත්මක වන ලූපයේ ශරීරය වෙනම ශ්‍රිතයකට ගෙන යාමට සහ ප්‍රධාන ලූපයෙන් එවැනි කාර්යයන් එකින් එක ඇමතීමට.

දෙවන උත්සාහය

යම් අවස්ථාවක දී, ගැටලුව තවමත් පවතින බව පැහැදිලි වූ අතර, කේතය වටා අවිනිශ්චිත ලෙස කිහිලිකරු තල්ලු කිරීමෙන් කිසිදු යහපතක් සිදු නොවනු ඇත. නිගමනය: කිහිලිකරු එකතු කිරීමේ ක්‍රියාවලිය අපි කෙසේ හෝ ක්‍රමවත් කළ යුතුය. ඒ නිසා ඒ කාලේ ෆ්‍රෙෂ් වුන 2.4.1 වර්ශන් එක ගත්තේ (2.5.0 නෙවෙයි, මොකද දන්නේ නෑනේ, තවම අහුවෙලා නැති බග්ස් අලුත් වර්ශන් එකේ තියේවි, මට මගේ ඒවා ඇති. දෝෂ), සහ මම කළ පළමු දෙය එය ආරක්ෂිතව නැවත ලිවීමයි thread-posix.c. හොඳයි, එනම්, ආරක්ෂිත ලෙස: අවහිර කිරීමට තුඩු දෙන මෙහෙයුමක් කිරීමට යමෙකු උත්සාහ කළහොත්, එම කාර්යය වහාම කැඳවනු ලැබීය abort() - ඇත්ත වශයෙන්ම, මෙය එකවරම සියලු ගැටලු විසඳුවේ නැත, නමුත් අවම වශයෙන් එය කෙසේ හෝ නොගැලපෙන දත්ත ලබා ගැනීමට වඩා ප්රසන්න විය.

සාමාන්‍යයෙන්, එම්ක්‍රිප්ටන් විකල්පයන් JS වෙත කේතය ගෙනයාමේදී ඉතා ප්‍රයෝජනවත් වේ -s ASSERTIONS=1 -s SAFE_HEAP=1 - ඔවුන් නොගැලපෙන ලිපිනයකට ඇමතුම් වැනි සමහර නිර්වචනය නොකළ හැසිරීම් අල්ලා ගනී (එය ටයිප් කළ අරා සඳහා කේතයට කිසිසේත්ම අනුකූල නොවේ. HEAP32[addr >> 2] = 1) හෝ වැරදි තර්ක සංඛ්‍යාවක් සහිත ශ්‍රිතයක් ඇමතීම.

මාර්ගය වන විට, පෙළගැස්වීමේ දෝෂ වෙනම ගැටළුවකි. මම දැනටමත් පවසා ඇති පරිදි, Qemu හට කේත උත්පාදනය සඳහා TCI (කුඩා කේත පරිවර්තකය) සඳහා “පරිහානියට පත්” අර්ථකථන පසුබිමක් ඇති අතර, නව ගෘහ නිර්මාණ ශිල්පයක් මත Qemu ගොඩනැගීමට සහ ධාවනය කිරීමට, ඔබ වාසනාවන්ත නම්, C සම්පාදකයක් ප්‍රමාණවත් වේ. "ඔබ වාසනාවන්ත නම්". මම අවාසනාවන්ත වූ අතර, TCI එහි බයිට්කේතය විග්‍රහ කිරීමේදී නොගැලපෙන ප්‍රවේශය භාවිතා කරන බව පෙනී ගියේය. එනම්, අවශ්‍යයෙන්ම සමතලා කළ ප්‍රවේශය සහිත සියලු වර්ගවල ARM සහ අනෙකුත් ගෘහ නිර්මාණ ශිල්පය මත, Qemu සම්පාදනය කරන්නේ ඔවුන්ට ස්වදේශීය කේතය ජනනය කරන සාමාන්‍ය TCG පසුබිමක් ඇති නිසා, නමුත් TCI ඒවා මත ක්‍රියා කරයිද යන්න තවත් ප්‍රශ්නයකි. කෙසේ වෙතත්, එය සිදු වූ පරිදි, TCI ලියකියවිලි පැහැදිලිවම සමාන දෙයක් පෙන්නුම් කළේය. එහි ප්‍රතිඵලයක් වශයෙන්, Qemu හි වෙනත් කොටසකින් සොයා ගන්නා ලද කේතයට නොගැලපෙන කියවීම සඳහා ශ්‍රිත ඇමතුම් එකතු කරන ලදී.

ගොඩවල් විනාශය

එහි ප්‍රතිඵලයක් වශයෙන්, TCI වෙත නොගැලපෙන ප්‍රවේශය නිවැරදි කරන ලදී, ප්‍රොසෙසරය, RCU සහ තවත් කුඩා දේවල් ලෙස හැඳින්වෙන ප්‍රධාන ලූපයක් සාදන ලදී. එබැවින් මම විකල්පය සමඟ Qemu දියත් කරමි -d exec,in_asm,out_asm, එයින් අදහස් කරන්නේ කුමන කේත බ්ලොක් ක්‍රියාත්මක කරන්නේ දැයි ඔබ පැවසිය යුතු අතර, විකාශනය වන අවස්ථාවේදී ආගන්තුක කේතය කුමක්ද, ධාරක කේතය වූයේ කුමක්ද (මෙම අවස්ථාවෙහිදී, බයිට්කේතය) ලිවීමට අවශ්‍ය බවයි. එය ආරම්භ වේ, පරිවර්තන වාරණ කිහිපයක් ක්‍රියාත්මක කරයි, RCU දැන් ආරම්භ වන බවට මා තැබූ නිදොස් කිරීමේ පණිවිඩය ලියන්නේ සහ... බිඳ වැටේ abort() කාර්යයක් ඇතුළත free(). කාර්යය සමඟ ටින්කර් කිරීමෙනි free() වෙන් කළ මතකයට පෙර බයිට් අටේ ඇති ගොඩ කුට්ටියේ ශීර්ෂයේ, බ්ලොක් ප්‍රමාණය හෝ ඒ හා සමාන දෙයක් වෙනුවට කුණු ඇති බව සොයා ගැනීමට අපට හැකි විය.

ගොඩේ විනාශය - කෙතරම් හුරුබුහුටිද ... එවැනි අවස්ථාවක, ප්රයෝජනවත් පිළියමක් ඇත - (හැකි නම්) එම මූලාශ්රවලින්, දේශීය ද්විමය එකලස් කර එය Valgrind යටතේ ධාවනය කරන්න. ටික වේලාවකට පසු, ද්විමය සූදානම් විය. මම එය එකම විකල්ප සමඟ දියත් කරමි - එය ක්‍රියාත්මක කිරීමට පෙර ආරම්භයේදී පවා බිඳ වැටේ. එය අප්රසන්නය, ඇත්ත වශයෙන්ම - පෙනෙන විදිහට, මූලාශ්ර හරියටම සමාන නොවීය, එය පුදුමයට කරුණක් නොවේ, මන්ද වින්යාසය තරමක් වෙනස් විකල්ප වලින් බාලදක්ෂ කර ඇත, නමුත් මට Valgrind ඇත - පළමුව මම මෙම දෝෂය නිවැරදි කරමි, පසුව, මම වාසනාවන්ත නම් , මුල් එක දිස් වනු ඇත. මම Valgrind යටතේ එකම දේ ක්‍රියාත්මක කරමි... Y-y-y, y-y-y, uh-uh, එය ආරම්භ විය, සාමාන්‍ය ලෙස ආරම්භ කිරීම හරහා ගොස්, වැරදි මතක ප්‍රවේශය පිළිබඳ එක අනතුරු ඇඟවීමකින් තොරව මුල් දෝෂය පසුකර ගියේය, වැටීම් ගැන සඳහන් නොකරන්න. ජීවිතය, ඔවුන් පවසන පරිදි, මේ සඳහා මාව සූදානම් කළේ නැත - වොල්ග්‍රයින්ඩ් යටතේ දියත් කරන විට කඩා වැටෙන වැඩසටහනක් බිඳ වැටීම නතර කරයි. එය කුමක්ද යන්න අභිරහසක්. මගේ උපකල්පනය නම්, ආරම්භයේදී බිඳවැටීමෙන් පසු වත්මන් උපදෙස් අසලදී, gdb වැඩ පෙන්වූ බවයි. memset-a වලංගු දර්ශකයක් සමඟ එක්කෝ භාවිතා කරන්න mmx, හෝ xmm රෙජිස්ටර් කරයි, සමහර විට එය යම් ආකාරයක පෙළගැස්වීමේ දෝෂයක් විය හැකිය, නමුත් එය තවමත් විශ්වාස කිරීමට අපහසුය.

හරි, Valgrind මෙහි උදව් නොකරන බව පෙනේ. මෙන්න වඩාත්ම පිළිකුල් සහගත දෙය ආරම්භ විය - සෑම දෙයක්ම ආරම්භ වන බව පෙනේ, නමුත් මිලියන ගණනකට පෙර සිදු විය හැකි සිදුවීමක් හේතුවෙන් සම්පූර්ණයෙන්ම නොදන්නා හේතු නිසා බිඳ වැටේ. දිගු කලක්, කෙසේ ළඟා විය යුතුද යන්න පවා පැහැදිලි නැත. අවසානයේදී, මට තවමත් වාඩි වී දෝෂහරණය කිරීමට සිදු විය. ශීර්ෂය නැවත ලියා ඇති දේ මුද්‍රණය කිරීමෙන් පෙන්නුම් කළේ එය අංකයක් මෙන් නොව යම් ආකාරයක ද්විමය දත්ත බවයි. තවද, මෙන්න, මෙම ද්විමය තන්තුව BIOS ගොනුවේ හමු විය - එනම්, දැන් එය බෆර් පිටාර ගැලීමක් බව සාධාරණ විශ්වාසයකින් පැවසිය හැකි අතර එය මෙම බෆරයට ලියා ඇති බව පවා පැහැදිලිය. හොඳයි, එහෙනම් මේ වගේ දෙයක් - Emscripten හි, වාසනාවකට මෙන්, ලිපින අවකාශයේ අහඹුකරණයක් නොමැත, එහි සිදුරු ද නොමැත, එබැවින් ඔබට අවසාන දියත් කිරීමේ සිට දර්ශකය මඟින් දත්ත ප්‍රතිදානය කිරීමට කේතයේ මැද කොතැනක හෝ ලිවිය හැකිය. දත්ත දෙස බලන්න, දර්ශකය දෙස බලන්න, සහ එය වෙනස් වී නොමැති නම්, සිතීමට ආහාර ලබා ගන්න. ඇත්ත, යම් වෙනසක් කිරීමෙන් පසු සම්බන්ධ වීමට මිනිත්තු කිහිපයක් ගත වේ, නමුත් ඔබට කුමක් කළ හැකිද? එහි ප්රතිඵලයක් වශයෙන්, BIOS තාවකාලික බෆරයේ සිට ආගන්තුක මතකය වෙත පිටපත් කරන ලද විශේෂිත රේඛාවක් සොයා ගන්නා ලදී - සහ, ඇත්ත වශයෙන්ම, බෆරයේ ප්රමාණවත් ඉඩක් නොතිබුණි. එම අමුතු බෆර් ලිපිනයේ මූලාශ්‍රය සෙවීමේ ප්‍රතිඵලයක් ලෙස ශ්‍රිතයක් ඇති විය qemu_anon_ram_alloc ගොනුවේ oslib-posix.c - තර්කය වූයේ මෙයයි: සමහර විට ලිපිනය 2 MB ප්‍රමාණයේ විශාල පිටුවකට පෙළගැස්වීම ප්‍රයෝජනවත් විය හැකිය, මේ සඳහා අපි අසන්නෙමු mmap පළමුව තව ටිකක්, පසුව අපි උපකාරයෙන් අතිරික්තය ආපසු දෙන්නෙමු munmap. එවැනි පෙළගැස්මක් අවශ්‍ය නොවේ නම්, අපි 2 MB වෙනුවට ප්‍රති result ලය දක්වන්නෙමු getpagesize() - mmap එය තවමත් පෙළගැස්වූ ලිපිනයක් ලබා දෙනු ඇත... එබැවින් එම්ක්‍රිප්ටෙන් mmap ඇමතුම් පමණි malloc, නමුත් ඇත්ත වශයෙන්ම එය පිටුවෙහි සමපාත නොවේ. පොදුවේ ගත් කල, මාස කිහිපයක් තිස්සේ මා කලකිරීමට පත් වූ දෝෂයක් වෙනස් කිරීමකින් නිවැරදි කරන ලදී දෙකයි රේඛා

ඇමතුම් කාර්යයන් වල විශේෂාංග

දැන් ප්‍රොසෙසරය යමක් ගණන් කරයි, Qemu බිඳ වැටෙන්නේ නැත, නමුත් තිරය ක්‍රියාත්මක නොවේ, සහ ප්‍රොසෙසරය ඉක්මනින් ලූපවලට යයි, ප්‍රතිදානය අනුව විනිශ්චය කරයි -d exec,in_asm,out_asm. උපකල්පනයක් මතු වී ඇත: ටයිමර් බාධා කිරීම් (හෝ, සාමාන්යයෙන්, සියලු බාධා කිරීම්) නොපැමිණේ. ඇත්ත වශයෙන්ම, ඔබ කිසියම් හේතුවක් නිසා ක්‍රියාත්මක වූ ස්වදේශීය එකලස් කිරීමේ බාධා ඉවත් කළහොත්, ඔබට සමාන පින්තූරයක් ලැබේ. නමුත් මෙය කිසිසේත්ම පිළිතුර නොවේ: ඉහත විකල්පය සමඟ නිකුත් කරන ලද හෝඩුවාවන් සංසන්දනය කිරීමෙන් පෙන්නුම් කළේ ක්‍රියාත්මක කිරීමේ පථ ඉතා ඉක්මනින් අපසරනය වී ඇති බවයි. මෙහිදී දියත් කිරීම භාවිතයෙන් පටිගත කළ දේ සංසන්දනය කිරීම පැවසිය යුතුය emrun දේශීය එකලස් කිරීමේ ප්‍රතිදානය සමඟ නිදොස් කිරීම ප්‍රතිදානය සම්පූර්ණයෙන්ම යාන්ත්‍රික ක්‍රියාවලියක් නොවේ. බ්‍රවුසරයක ක්‍රියාත්මක වන වැඩසටහනක් සම්බන්ධ වන්නේ කෙසේදැයි මම හරියටම නොදනිමි emrun, නමුත් ප්‍රතිදානයේ සමහර රේඛා නැවත සකස් වී ඇත, එබැවින් වෙනසෙහි වෙනස තවමත් ගමන් පථ අපසරනය වී ඇතැයි උපකල්පනය කිරීමට හේතුවක් නොවේ. පොදුවේ ගත් කල, උපදෙස් අනුව බව පැහැදිලි විය ljmpl විවිධ ලිපින වෙත සංක්‍රමණයක් ඇති අතර, උත්පාදනය කරන ලද බයිට්කේතය මූලික වශයෙන් වෙනස් වේ: එකක සහායක ශ්‍රිතයක් ඇමතීමට උපදෙස් අඩංගු වේ, අනෙක එසේ නොවේ. උපදෙස් ගූගල් කර මෙම උපදෙස් පරිවර්තනය කරන කේතය අධ්‍යයනය කිරීමෙන් පසු, පළමුව, එය ලේඛනයේ ඇති වහාම බව පැහැදිලි විය. cr0 පටිගත කිරීමක් සිදු කරන ලදී - සහායකයෙකු භාවිතා කරමින් - එය ප්‍රොසෙසරය ආරක්ෂිත ප්‍රකාරයට මාරු කළ අතර, දෙවනුව, js අනුවාදය කිසි විටෙකත් ආරක්ෂිත ප්‍රකාරයට මාරු නොවීය. නමුත් කාරණය නම්, එම්ස්ක්‍රිප්ටන් හි තවත් ලක්ෂණයක් වන්නේ උපදෙස් ක්‍රියාත්මක කිරීම වැනි කේතයන් ඉවසා සිටීමට ඇති අකමැත්තයි. call TCI හි, ඕනෑම ශ්‍රිත දර්ශකයක් ප්‍රතිඵලයක් ලෙස ටයිප් කරයි long long f(int arg0, .. int arg9) - ශ්‍රිතයන් නිවැරදි තර්ක සංඛ්‍යාව සමඟ හැඳින්විය යුතුය. මෙම රීතිය උල්ලංඝනය වී ඇත්නම්, නිදොස් කිරීමේ සිටුවම් මත පදනම්ව, වැඩසටහන බිඳ වැටෙනු ඇත (එය හොඳයි) හෝ වැරදි කාර්යයක් අමතන්න (නිදොස් කිරීම කණගාටුදායක වනු ඇත). තුන්වන විකල්පය ද ඇත - තර්ක එකතු කරන / ඉවත් කරන දවටන උත්පාදනය සක්‍රීය කරන්න, නමුත් ඇත්ත වශයෙන්ම මට අවශ්‍ය වන්නේ දවටන සියයකට වඩා ටිකක් වැඩි වුවද, සමස්තයක් ලෙස මෙම දවටන විශාල ඉඩක් ගනී. මෙය පමණක් ඉතා කණගාටුදායක ය, නමුත් වඩාත් බරපතල ගැටළුවක් ඇති විය: දවටන ශ්‍රිතවල ජනනය කරන ලද කේතයේ, තර්ක පරිවර්තනය කර පරිවර්තනය කරන ලදී, නමුත් සමහර විට උත්පාදනය කරන ලද තර්ක සහිත ශ්‍රිතය හැඳින්වූයේ නැත - හොඳයි, හරියට මගේ libffi ක්රියාත්මක කිරීම. එනම්, සමහර උපකාරකයන් සරලව ක්රියාත්මක නොකළේය.

වාසනාවකට මෙන්, Qemu සතුව ශීර්ෂ ගොනුවක ස්වරූපයෙන් යන්ත්‍රයෙන් කියවිය හැකි උපකාරක ලැයිස්තුවක් ඇත

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

ඒවා ඉතා විහිලු සහගත ලෙස භාවිතා වේ: පළමුව, මැක්‍රෝස් වඩාත් විකාර ආකාරයෙන් නැවත අර්ථ දක්වා ඇත DEF_HELPER_n, පසුව සක්රිය කරයි helper.h. මැක්‍රෝව ව්‍යුහය ආරම්භකයක් සහ කොමාවක් දක්වා ප්‍රසාරණය වන ප්‍රමාණයට, පසුව අරාවක් අර්ථ දක්වනු ලබන අතර, මූලද්‍රව්‍ය වෙනුවට - #include <helper.h> එහි ප්‍රතිඵලයක් වශයෙන්, අවසානයේදී මට පුස්තකාලය වැඩ කිරීමට උත්සාහ කිරීමට අවස්ථාවක් ලැබුණි pyparsing, සහ අවශ්‍ය කාර්යයන් සඳහා හරියටම එම දවටන උත්පාදනය කරන පිටපතක් ලියා ඇත.

ඉතින්, ඊට පසු, ප්‍රොසෙසරය වැඩ කරන බවක් පෙනෙන්නට තිබුණි. memtest86+ ස්වදේශීය එකලස් කිරීමේදී ධාවනය කිරීමට හැකි වුවද, තිරය කිසිදා ආරම්භ නොකළ නිසා බව පෙනේ. මෙහිදී Qemu block I/O කේතය coroutine වලින් ලියා ඇති බව පැහැදිලි කිරීම අවශ්‍ය වේ. එම්ස්ක්‍රිප්ටන්ට එයටම ආවේණික වූ ඉතා උපක්‍රමශීලී ක්‍රියාත්මක කිරීමක් ඇත, නමුත් එයට තවමත් Qemu කේතයේ සහය අවශ්‍ය විය, ඔබට දැන් ප්‍රොසෙසරය නිදොස් කළ හැක: Qemu විකල්ප සඳහා සහය දක්වයි -kernel, -initrd, -append, ඔබට Linux ආරම්භ කළ හැකි හෝ, උදාහරණයක් ලෙස, memtest86+, බ්ලොක් උපාංග භාවිතා නොකර. නමුත් මෙන්න ගැටලුව: ස්වදේශීය එකලස් කිරීමේදී කෙනෙකුට විකල්පය සමඟ කොන්සෝලයට ලිනක්ස් කර්නල් ප්‍රතිදානය දැකිය හැකිය. -nographic, සහ එය දියත් කළ ස්ථානයේ සිට ටර්මිනලය වෙත බ්‍රවුසරයෙන් ප්‍රතිදානයක් නොමැත emrun, ආවේ නැහැ. එනම්, එය පැහැදිලි නැත: ප්රොසෙසරය ක්රියා නොකරයි හෝ චිත්රක ප්රතිදානය ක්රියා නොකරයි. ඊට පස්සේ මට ටිකක් ඉන්න හිතුනා. “ප්‍රොසෙසරය නිදා නොගෙන සෙමින් ඇසිපිය හෙළන” බව පෙනී ගිය අතර මිනිත්තු පහකට පමණ පසු කර්නලය කොන්සෝලය වෙත පණිවිඩ පොකුරක් විසි කර දිගටම එල්ලී ගියේය. ප්‍රොසෙසරය සාමාන්‍යයෙන් ක්‍රියා කරන බව පැහැදිලි වූ අතර SDL2 සමඟ වැඩ කිරීම සඳහා අපි කේතය හාරා ගත යුතුය. අවාසනාවකට, මම මෙම පුස්තකාලය භාවිතා කරන්නේ කෙසේදැයි නොදනිමි, එබැවින් සමහර ස්ථානවල මට අහඹු ලෙස ක්රියා කිරීමට සිදු විය. යම් අවස්ථාවක දී, සමාන්තර 0 රේඛාව නිල් පසුබිමක තිරය මත දැල්වීය, එය සමහර සිතුවිලි යෝජනා කළේය. අවසානයේදී, ගැටළුව වූයේ Qemu එක් භෞතික කවුළුවක අථත්‍ය කවුළු කිහිපයක් විවෘත කිරීමයි, ඒ අතර ඔබට Ctrl-Alt-n භාවිතයෙන් මාරු විය හැකිය: එය ස්වදේශීය ගොඩනැගීමේ ක්‍රියා කරයි, නමුත් එම්ස්ක්‍රිප්ටන් හි නොවේ. විකල්ප භාවිතා කරමින් අනවශ්ය කවුළු ඉවත් කිරීමෙන් පසු -monitor none -parallel none -serial none සහ එක් එක් රාමුව මත මුළු තිරයම බලහත්කාරයෙන් නැවත ඇඳීමට උපදෙස්, සියල්ල හදිසියේම ක්රියාත්මක විය.

කොරූටින්ස්

එබැවින්, බ්‍රවුසරයේ අනුකරණය ක්‍රියාත්මක වේ, නමුත් ඔබට එහි රසවත් තනි-නම්‍ය කිසිවක් ධාවනය කළ නොහැක, මන්ද I/O අවහිරයක් නොමැති නිසා - ඔබ coroutines සඳහා සහය ක්‍රියාත්මක කළ යුතුය. Qemu සතුව දැනටමත් coroutine පසුබිම් කිහිපයක් ඇත, නමුත් JavaScript සහ Emscripten කේත උත්පාදකයේ ස්වභාවය හේතුවෙන්, ඔබට අට්ටි කූරු කිරීම ආරම්භ කළ නොහැක. "සියල්ල පහව ගොස් ඇති බව පෙනේ, ප්ලාස්ටර් ඉවත් කරනු ලැබේ", නමුත් එම්ස්ක්‍රිප්ටන් සංවර්ධකයින් දැනටමත් සියල්ල බලා ගෙන ඇත. මෙය ඉතා හාස්‍යජනක ලෙස ක්‍රියාත්මක කර ඇත: අපි මෙවැනි ක්‍රියාකාරී ඇමතුමක් සැක සහිත යැයි කියමු emscripten_sleep සහ තවත් කිහිපයක් Asyncify යාන්ත්‍රණය භාවිතා කරයි, මෙන්ම පෙර අවස්ථා දෙකෙන් එකක් තොගයට පහළින් සිදු විය හැකි ඕනෑම කාර්යයකට පොයින්ටර් ඇමතුම් සහ ඇමතුම්. දැන්, සෑම සැක සහිත ඇමතුමකට පෙර, අපි අසමමුහුර්ත සන්දර්භයක් තෝරා ගනිමු, සහ ඇමතුමෙන් පසු, අපි අසමමුහුර්ත ඇමතුමක් සිදුවී ඇත්දැයි පරීක්ෂා කරන්නෙමු, එය තිබේ නම්, අපි මෙම අසමමුහුර්ත සන්දර්භය තුළ සියලුම දේශීය විචල්‍යයන් සුරකිමු, කුමන ශ්‍රිතයද යන්න දක්වන්න. අපට ක්‍රියාත්මක කිරීම දිගටම කරගෙන යාමට අවශ්‍ය අවස්ථාවන්ට පාලනය මාරු කිරීමට සහ වත්මන් ශ්‍රිතයෙන් පිටවීමට. මෙහි බලපෑම අධ්‍යයනය කිරීමට ඉඩක් ඇත නාස්ති කරනවා - අසමමුහුර්ත ඇමතුමකින් ආපසු පැමිණීමෙන් පසු අඛණ්ඩ කේත ක්‍රියාත්මක කිරීමේ අවශ්‍යතා සඳහා, සම්පාදකය සැක සහිත ඇමතුමකින් පසුව ආරම්භ වන ශ්‍රිතයේ “ස්ටුබ්” ජනනය කරයි — මේ වගේ: n සැක සහිත ඇමතුම් තිබේ නම්, එවිට ශ්‍රිතය n/2 කොතැනක හෝ පුළුල් වනු ඇත. වාර - මෙය තවමත්, එසේ නොවේ නම්, එක් එක් විභව අසමමුහුර්ත ඇමතුමකට පසුව, මුල් ශ්‍රිතයට දේශීය විචල්‍ය කිහිපයක් සුරැකීම එක් කළ යුතු බව මතක තබා ගන්න. පසුව, මට පයිතන් හි සරල ස්ක්‍රිප්ට් එකක් ලිවීමට පවා සිදු විය, එය, "අසමමුහුර්තකම තමන් හරහා යාමට ඉඩ නොදෙන" (එනම්, ස්ටැක් ප්‍රවර්ධනය සහ මා විස්තර කළ සෑම දෙයක්ම නොකරන" විශේෂයෙන් අධික ලෙස භාවිතා කරන ලද ශ්‍රිත මාලාවක් මත පදනම්ව. ඒවායේ වැඩ), මෙම කාර්යයන් අසමමිතික ලෙස නොසැලකෙන පරිදි සම්පාදකයා විසින් කාර්යයන් නොසලකා හැරිය යුතු පොයින්ටර් හරහා ඇමතුම් දක්වයි. ඉන්පසුව 60 MB ට අඩු JS ගොනු පැහැදිලිවම වැඩියි - අපි අවම වශයෙන් 30 ක් කියමු. නමුත්, වරක් මම එකලස් කිරීමේ ස්ක්‍රිප්ට් එකක් සකසමින් සිටියදී අහම්බෙන් සම්බන්ධක විකල්පයන් ඉවතට විසි කළ අතර, ඒ අතර විය. -O3. මම ජනනය කළ කේතය ධාවනය කරන අතර, Chromium මතකය විනාශ කර බිඳ වැටේ. මම එතකොට අහම්බෙන් බැලුවා මෙයා බාගන්න හදන එක මොකක්ද කියලා... හොඳයි, මම මොනවා කියන්නද, 500+ MB Javascript එකක් කල්පනාකාරීව අධ්‍යයනය කරලා Optimize කරන්න කියලා මටත් කිව්වා නම් මටත් ෆ්‍රෝස් වෙනවා.

අවාසනාවන්ත ලෙස, Asyncify ආධාරක පුස්තකාල කේතයේ චෙක්පත් සම්පූර්ණයෙන්ම මිත්‍රශීලී නොවීය longjmp-s අතථ්‍ය ප්‍රොසෙසර් කේතයේ භාවිතා වේ, නමුත් මෙම චෙක්පත් අක්‍රිය කරන කුඩා පැච් එකකින් පසුව සියල්ල හොඳින් ඇති සේ සන්දර්භ බලහත්කාරයෙන් ප්‍රතිස්ථාපනය කරයි, කේතය ක්‍රියාත්මක විය. ඉන්පසු අමුතු දෙයක් ආරම්භ විය: සමහර විට සමමුහුර්ත කේතයේ චෙක්පත් ක්‍රියාත්මක විය - ක්‍රියාත්මක කිරීමේ තර්කයට අනුව, එය අවහිර කළ යුතු නම්, කේතය බිඳ වැටෙන ඒවාම - යමෙකු දැනටමත් අල්ලා ගත් mutex අල්ලා ගැනීමට උත්සාහ කළේය. වාසනාවකට මෙන්, මෙය අනුක්‍රමික කේතයේ තාර්කික ගැටළුවක් නොවන බව පෙනී ගියේය - මම හුදෙක් එම්ස්ක්‍රිප්ටන් විසින් සපයන ලද සම්මත ප්‍රධාන ලූප ක්‍රියාකාරීත්වය භාවිතා කරමින් සිටියෙමි, නමුත් සමහර විට අසමමුහුර්ත ඇමතුම තොගය සම්පූර්ණයෙන්ම ලිහා දමනු ඇත, එම මොහොතේ එය අසාර්ථක වනු ඇත. setTimeout ප්‍රධාන ලූපයෙන් - මේ අනුව, කේතය පෙර පුනරාවර්තනයෙන් ඉවත් නොවී ප්‍රධාන ලූප පුනරාවර්තනයට ඇතුළු විය. අසීමිත ලූපයක් මත නැවත ලිවීය සහ emscripten_sleep, සහ mutexes සමග ගැටළු නතර විය. කේතය වඩාත් තාර්කික වී ඇත - ඇත්ත වශයෙන්ම, ඊළඟ සජීවිකරණ රාමුව සකස් කරන කේතයක් මා සතුව නොමැත - ප්‍රොසෙසරය යමක් ගණනය කරන අතර තිරය වරින් වර යාවත්කාලීන වේ. කෙසේ වෙතත්, ගැටළු එතැනින් නතර වූයේ නැත: සමහර විට Qemu ක්රියාත්මක කිරීම කිසිදු ව්යතිරේකයක් හෝ දෝෂයක් නොමැතිව නිශ්ශබ්දව අවසන් වේ. ඒ මොහොතේ මම එය අත්හැරියෙමි, නමුත්, ඉදිරිය දෙස බලන විට, ගැටලුව මෙය බව මම කියමි: coroutine කේතය, ඇත්ත වශයෙන්ම, භාවිතා නොවේ setTimeout (හෝ අවම වශයෙන් ඔබ සිතන තරම් බොහෝ විට නොවේ): කාර්යය emscripten_yield අසමමුහුර්ත ඇමතුම් ධජය සරලව සකසයි. සමස්ත කාරණය එයයි emscripten_coroutine_next අසමමුහුර්ත ශ්‍රිතයක් නොවේ: අභ්‍යන්තරව එය ධජය පරීක්ෂා කරයි, එය නැවත සකස් කර පාලනය අවශ්‍ය තැනට මාරු කරයි. එනම්, Stack හි ප්රවර්ධනය එතැනින් අවසන් වේ. ගැටළුව වූයේ, දැනට පවතින coroutine පසුබිමෙන් වැදගත් කේත පේළියක් පිටපත් නොකිරීම නිසා coroutine තටාකය අක්‍රිය වූ විට දර්ශණය වූ භාවිතයෙන් පසු-නිදහස් වීම, ශ්‍රිතය qemu_in_coroutine ඇත්ත වශයෙන්ම එය අසත්‍ය ලෙස ආපසු පැමිණිය යුතු වූ විට සත්‍ය ලෙස ආපසු හැරී ඇත. මෙය ඇමතුමකට හේතු විය emscripten_yield, ඊට උඩින් අට්ටියේ කිසිවෙක් සිටියේ නැත emscripten_coroutine_next, තොගය ඉහළට දිග හැරුණි, නමුත් නැත setTimeout, මම දැනටමත් පවසා ඇති පරිදි, ප්රදර්ශනය කර නැත.

JavaScript කේත උත්පාදනය

මෙන්න, ඇත්ත වශයෙන්ම, පොරොන්දු වූ "අඹරන ලද මස් ආපසු හැරවීම" වේ. ඇත්තෙන්ම නැහැ. ඇත්ත වශයෙන්ම, අපි බ්‍රව්සරයේ Qemu සහ එහි Node.js ධාවනය කරන්නේ නම්, ස්වාභාවිකවම, Qemu හි කේත උත්පාදනය කිරීමෙන් පසුව අපට සම්පූර්ණයෙන්ම වැරදි JavaScript ලැබෙනු ඇත. නමුත් තවමත්, යම් ආකාරයක ප්රතිලෝම පරිවර්තනයක්.

පළමුව, Qemu ක්‍රියා කරන ආකාරය ගැන ටිකක්. කරුණාකර මට වහාම සමාව දෙන්න: මම වෘත්තීය Qemu සංවර්ධකයෙකු නොවන අතර මගේ නිගමන සමහර ස්ථානවල වැරදි විය හැක. ඔවුන් පවසන පරිදි, "ශිෂ්‍යයාගේ මතය ගුරුවරයාගේ මතය, පීනෝගේ අක්ෂීය විද්‍යාව සහ සාමාන්‍ය බුද්ධිය සමඟ සමපාත විය යුතු නැත." Qemu සතුව නිශ්චිත ආගන්තුක ගෘහ නිර්මාණ සංඛ්‍යාවක් සහය දක්වන අතර ඒ සෑම එකක් සඳහාම වැනි නාමාවලියක් ඇත target-i386. ගොඩනඟන විට, ඔබට ආගන්තුක ගෘහනිර්මාණ කිහිපයක් සඳහා සහය දැක්විය හැක, නමුත් ප්රතිඵලය ද්විමය කිහිපයක් පමණක් වනු ඇත. ආගන්තුක ගෘහනිර්මාණ ශිල්පයට සහාය දක්වන කේතය, අනෙක් අතට, සමහර අභ්‍යන්තර Qemu මෙහෙයුම් උත්පාදනය කරයි, TCG (Tiny Code Generator) දැනටමත් සත්කාරක ගෘහ නිර්මාණ ශිල්පය සඳහා යන්ත්‍ර කේතය බවට පත් කරයි. tcg බහලුමේ ඇති readme ගොනුවේ දක්වා ඇති පරිදි, මෙය මුලින් සාමාන්‍ය C සම්පාදකයක කොටසක් වූ අතර පසුව එය JIT සඳහා අනුවර්තනය කරන ලදී. එබැවින්, උදාහරණයක් ලෙස, මෙම ලේඛනය අනුව ඉලක්ක ගෘහ නිර්මාණ ශිල්පය තවදුරටත් ආගන්තුක ගෘහ නිර්මාණ ශිල්පයක් නොව, සත්කාරක ගෘහ නිර්මාණ ශිල්පයකි. යම් අවස්ථාවක දී, තවත් සංරචකයක් දර්ශනය විය - කුඩා කේත පරිවර්තකය (ටීසීඅයි), විශේෂිත ධාරක ගෘහ නිර්මාණ ශිල්පයක් සඳහා කේත උත්පාදක යන්ත්රයක් නොමැති විට කේතය (ආසන්න වශයෙන් එකම අභ්යන්තර මෙහෙයුම්) ක්රියාත්මක කළ යුතුය. ඇත්ත වශයෙන්ම, එහි ප්‍රලේඛනයේ සඳහන් පරිදි, මෙම පරිවර්තකය සෑම විටම JIT කේත උත්පාදක යන්ත්‍රයක් මෙන්ම වේගය අනුව ප්‍රමාණාත්මකව පමණක් නොව ගුණාත්මකව ද ක්‍රියා නොකරයි. ඔහුගේ විස්තරය සම්පූර්ණයෙන්ම අදාළදැයි මට විශ්වාස නැත.

මුලදී මම සම්පූර්ණ TCG පසුබිමක් සෑදීමට උත්සාහ කළ නමුත් මූලාශ්‍ර කේතය සහ බයිට්කේත උපදෙස් පිළිබඳ සම්පූර්ණයෙන්ම පැහැදිලි විස්තරයක් නොමැති නිසා ඉක්මනින් ව්‍යාකූල වූ බැවින් මම TCI පරිවර්තකය එතීමට තීරණය කළෙමි. මෙය වාසි කිහිපයක් ලබා දුන්නේය:

  • කේත උත්පාදක යන්ත්රයක් ක්රියාත්මක කිරීමේදී, ඔබට උපදෙස් විස්තරය දෙස නොව පරිවර්තක කේතය දෙස බැලිය හැකිය
  • ඔබට කාර්යයන් උත්පාදනය කළ හැක්කේ හමු වූ සෑම පරිවර්තන වාරණයක් සඳහාම නොව, උදාහරණයක් ලෙස, සියවන ක්‍රියාත්මක කිරීමෙන් පසුව පමණි
  • උත්පාදනය කරන ලද කේතය වෙනස් වුවහොත් (මෙය කළ හැකි බව පෙනේ, පැච් යන වචනය අඩංගු නම් සහිත කාර්යයන් අනුව විනිශ්චය කිරීම), මට ජනනය කරන ලද JS කේතය අවලංගු කිරීමට අවශ්‍ය වනු ඇත, නමුත් අවම වශයෙන් මට එය නැවත උත්පාදනය කිරීමට යමක් තිබේ.

තුන්වන කරුණ සම්බන්ධයෙන්, කේතය පළමු වරට ක්‍රියාත්මක කිරීමෙන් පසු පැච් කිරීම කළ හැකි බව මට විශ්වාස නැත, නමුත් පළමු කරුණු දෙක ප්‍රමාණවත් වේ.

මුලදී, කේතය මුල් බයිට්කේත උපදෙස් ලිපිනයේ විශාල ස්විචයක් ආකාරයෙන් ජනනය කරන ලදී, නමුත් පසුව, එම්ස්ක්‍රිප්ටන්, ජනනය කරන ලද JS ප්‍රශස්තිකරණය සහ නැවත පණ ගැන්වීම පිළිබඳ ලිපිය සිහිපත් කරමින්, මම තවත් මානව කේතයක් ජනනය කිරීමට තීරණය කළෙමි, විශේෂයෙන් එය ආනුභවිකව එය. පරිවර්තන කොටසට ඇතුල් වන එකම ස්ථානය එහි ආරම්භය බව පෙනී ගියේය. වැඩි කල් යන්නට මත්තෙන්, අපි ටික වේලාවකට පසු (ලූප නොමැතිව වුවද) ifs සමඟ කේතය ජනනය කරන කේත උත්පාදක යන්ත්‍රයක් ලබා ගත්තෙමු. නමුත් අවාසනාවන්ත ලෙස එය කඩා වැටුනේ උපදෙස් යම් දුරකට වැරදි බවට පණිවිඩයක් ලබා දෙමිනි. එපමණක් නොව, මෙම පුනරාවර්තන මට්ටමේ අවසාන උපදෙස් විය brcond. හරි, මම පුනරාවර්තන ඇමතුමට පෙර සහ පසුව මෙම උපදෙස් උත්පාදනයට සමාන චෙක්පතක් එක් කරමි සහ... ඒවායින් එකක්වත් ක්‍රියාත්මක නොකළ නමුත් තහවුරු කිරීමේ ස්විචයෙන් පසුව ඒවා තවමත් අසාර්ථක විය. අවසානයේදී, ජනනය කරන ලද කේතය අධ්‍යයනය කිරීමෙන් පසු, ස්විචයෙන් පසුව, වත්මන් උපදෙස් සඳහා වන පොයින්ටරය තොගයෙන් නැවත පූරණය වන අතර බොහෝ විට ජනනය කරන ලද ජාවාස්ක්‍රිප්ට් කේතයෙන් උඩින් ලියැවී ඇති බව මට වැටහුණි. ඒ නිසා එය සිදු විය. බෆරය මෙගාබයිට් එකක සිට දහය දක්වා වැඩි කිරීම කිසිවකට මඟ පෑදුවේ නැති අතර කේත උත්පාදක යන්ත්‍රය රවුම්වල ක්‍රියාත්මක වන බව පැහැදිලි විය. අපි දැනට පවතින ක්ෂය රෝගයේ සීමාවෙන් ඔබ්බට නොගිය බව පරීක්‍ෂා කළ යුතු අතර, එසේ කළේ නම්, අපට ක්‍රියාත්මක කිරීම දිගටම කරගෙන යාමට හැකි වන පරිදි ඍණ ලකුණක් සමඟ ඊළඟ ක්ෂය රෝගයේ ලිපිනය නිකුත් කරන්න. මීට අමතරව, මෙය "මෙම බයිට්කේත කොටස වෙනස් වී ඇත්නම් කුමන උත්පාදනය කළ ශ්‍රිතයන් අවලංගු කළ යුතුද?" යන ගැටළුව විසඳයි. — මෙම පරිවර්තන කොටසට අනුරූප වන කාර්යය පමණක් අවලංගු කළ යුතුය. මාර්ගය වන විට, මම ක්‍රෝමියම් හි සියල්ල නිදොස් කළද (මම ෆයර්ෆොක්ස් භාවිතා කරන බැවින් සහ අත්හදා බැලීම් සඳහා වෙනම බ්‍රවුසරයක් භාවිතා කිරීම මට පහසු බැවින්), ෆයර්ෆොක්ස් මට asm.js ප්‍රමිතිය සමඟ නොගැලපීම් නිවැරදි කිරීමට උපකාරී විය, ඉන්පසු කේතය වේගයෙන් ක්‍රියා කිරීමට පටන් ගත්තේය. ක්රෝමියම්.

උත්පාදනය කරන ලද කේතයේ උදාහරණය

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

නිගමනය

එබැවින්, වැඩ තවමත් නිම කර නැත, නමුත් මෙම දිගුකාලීන ඉදිකිරීම් රහසේ පරිපූර්ණත්වයට ගෙන ඒමට මම වෙහෙසට පත්ව සිටිමි. ඒ නිසා දැනට මා සතුව ඇති දේ පළ කිරීමට තීරණය කළෙමි. කේතය තැන් වලදී ටිකක් බියජනකයි, මන්ද මෙය අත්හදා බැලීමක් වන අතර, කළ යුතු දේ කල්තියා පැහැදිලි නැත. සමහර විට, Qemu හි තවත් නවීන අනුවාදයක් මත සාමාන්‍ය පරමාණුක බැඳීම් නිකුත් කිරීම වටී. මේ අතරතුර, බ්ලොග් ආකෘතියකින් ගීතා හි නූල් එකක් තිබේ: අවම වශයෙන් කෙසේ හෝ සම්මත කර ඇති සෑම "මට්ටම" සඳහාම රුසියානු භාෂාවෙන් සවිස්තරාත්මක විවරණයක් එකතු කර ඇත. ඇත්ත වශයෙන්ම, මෙම ලිපිය බොහෝ දුරට නිගමනය නැවත කියවීමකි git log.

ඔබට සියල්ල උත්සාහ කළ හැකිය මෙහි (රථවාහනයෙන් පරිස්සම් වන්න).

දැනටමත් වැඩ කරන දේ:

  • x86 අතථ්‍ය ප්‍රොසෙසරය ක්‍රියාත්මක වේ
  • යන්ත්‍ර කේතයේ සිට JavaScript දක්වා JIT කේත උත්පාදක යන්ත්‍රයක ක්‍රියාකාරී මූලාකෘතියක් ඇත
  • වෙනත් 32-බිට් ආගන්තුක ගෘහ නිර්මාණ එකලස් කිරීම සඳහා අච්චුවක් ඇත: දැන් ඔබට පැටවීමේ අදියරේදී බ්‍රව්සරයේ MIPS ගෘහ නිර්මාණ ශිල්පය කැටි කිරීම සඳහා Linux අගය කළ හැකිය.

වෙන මොනවා කරන්නද

  • අනුකරණය වේගවත් කරන්න. JIT ප්‍රකාරයේදී පවා එය අතථ්‍ය x86ට වඩා මන්දගාමීව ක්‍රියාත්මක වන බව පෙනේ (නමුත් අනුකරණය කරන ලද දෘඩාංග සහ ගෘහනිර්මාණ විශාල ප්‍රමාණයක් සහිත සම්පූර්ණ Qemu එකක් තිබිය හැක)
  • සාමාන්‍ය අතුරු මුහුණතක් සෑදීමට - අවංකවම, මම හොඳ වෙබ් සංවර්ධකයෙක් නොවේ, එබැවින් දැනට මම සම්මත එම්ස්ක්‍රිප්ටන් කවචය මට හැකි උපරිමයෙන් ප්‍රතිනිර්මාණය කර ඇත්තෙමි.
  • වඩාත් සංකීර්ණ Qemu කාර්යයන් දියත් කිරීමට උත්සාහ කරන්න - ජාලකරණය, VM සංක්‍රමණය, ආදිය.
  • UPD: Qemu සහ අනෙකුත් ව්‍යාපෘතිවල පෙර පෝටර්වරුන් කළාක් මෙන්, ඔබට ඔබගේ සංවර්ධන කිහිපයක් සහ දෝෂ වාර්තා Emscripten upstream වෙත ඉදිරිපත් කිරීමට අවශ්‍ය වනු ඇත. මගේ කර්තව්‍යයේ කොටසක් ලෙස එම්ක්‍රිප්ටන් වෙත ඔවුන්ගේ දායකත්වය ව්‍යංගයෙන් භාවිතා කිරීමට හැකිවීම ගැන ඔවුන්ට ස්තූතියි.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න