Share
Embed
Vim compiled to WebAssembly
- Emscripten & WebAssembly night !! #8
- 30min
- Demo: https://rhysd.github.io/vim.wasm/
- Repo: https://github.com/rhysd/vim.wasm
- Event: https://emsn.connpass.com/event/136346/
Linda_pp
July 24, 2019
Transcript
33 slides
-
• ݴޠॲཧܥίʔυΤσΟλͳͲͷϓϩ άϥϛϯάπʔϧ͕͖ • 70+ Vim plugins • NyaoVim, vim.wasm
ͳͲͷ Vim/Neovim ΤσΟλͷ Web ϑϩϯτΤϯυ • LLVM Λͬͨݴޠࣗ࡞ (Dachs, gocaml) @Linda_pp @rhysd -
Vim ΤσΟλͱ • vi Ϋϩʔϯͱͯͭ͘͠ΒΕɼ͘༻͞Ε͍ͯΔςΩετΤσΟλɽ 28ܦͬͨࠓਐԽ͠ଓ͚͍ͯΔ • CUI ൛ͱ GUI
൛ͷ྆ํ͕͋Γɼଟ͘ͷ OS ʹҠ২͞Ε͍ͯΔʢ࣮ C99ʣ • Vim script ͱ͍͏ಠࣗݴޠͰϋΠϥΠτɾϓϥάΠϯͳͲ֦ுͰ͖Δ > wc -l vim/src/**/*.{c,h} | grep total 465419 total > wc -l vim/runtime/**/*.vim | grep total 217978 total -
vim.wasm ͱ Vim ΤσΟλΛ fork ͯ͠ WebAssembly ʹί ϯύΠϧͰ͖ΔΑ͏ʹ͠ɼϒϥβ͔Β͑ ΔΑ͏ʹ͢ΔϓϩδΣΫτ
https://github.com/rhysd/vim.wasm -
Ԡ༻ྫ • ֎෦ϓϥάΠϯΛࢼ͢ • vim-buffer: https://tinyurl.com/y48abmbn • https://github.com/rhysd/react-vim-wasm • vim.wasm
ͷ React ίϯϙʔωϯτ • https://github.com/rhysd/vimwasm-try-plugin • vim.wasm Ͱ֎෦ϓϥάΠϯΛࢼͨ͢Ίͷ URL ੜ • https://github.com/nat-chan/vim.wasm.ipynb • Jupyter Notebook ͷΤσΟλͰ Vim Λ ͏ -
vim.wasm ͷػೳ • ΄΅શͯͷ Vim ͷػೳʢߏจϋΠϥΠτϓϥάΠϯͳ Ͳʣ͕ϒϥβͰಈ͘ • navigator.clipboard ΛͬͨΫϦοϓϘʔυͷαϙʔτ
ɼϑΝΠϧͷΓͱΓʢD&DɼVim ͰฤूதͷϑΝΠ ϧͷμϯϩʔυʣ • Indexed DB Λͬͯ .vimrc ΛӬଓԽ • ϦϞʔτͷϑΝΠϧΛ -
vim.wasm ͷϞνϕʔγϣϯ • Vim ͘ΘΕ͍ͯΔ͕ɼ·ͩΣϒͰΘΕ ͍ͯͳ͍ • Wasm ʹطଘͷΤσΟλΛϙʔτͯ͠ಈ͔͢ํࣜͷ Web
ίʔυΤσΟλʢ୳ͨ͠ݶΓͰʣͳ͔ͬͨ ͷͰɼͲΕ͘Β͍͏·͘ಈ͔͘ڵຯ͕͋ͬͨ • WebAssembly, Web Worker, ES Modules ͳͲͷ࠷ ৽༷Λ࣮ફతʹͬͯΈ͍ͨ -
ͳͥ Vim Λϙʔτ͢Δͷ͔ʁ • ଟ͘ͷڥʹҠ২͞Ε͍ͯΔͨΊɼ͔ͳΓϙʔλϒϧ ͳ C Ͱॻ͔Ε͍ͯΔ • feature
ͱ͍͏֓೦͕͋Γɼtiny, small, normal, big, huge ͷ5ஈ֊ͷػೳηοτΛఏڙ͍ͯ͠Δʢhuge ͕ શ෦ೖΓʣɽ࠷খηοτͷ tiny ͔ΒҠ২Λ࢝ΊΒΕ Δ • Vim ͖ -
npm ύοέʔδ vim-wasm https://www.npmjs.com/package/vim-wasm ES ModuleɼWeb Worker εΫϦϓτɼwasm ό ΠφϦΛ1ͭͷ
npm ύοέʔδʹɽ؆୯ʹ vim.wasm ΛϖʔδʹΈࠐΊΔ -
npm ύοέʔδ vim-wasm <!doctype html> <html lang="en-us"> <title>hello vim.wasm</title> <body>
<div id="vim-editor"> <canvas id="vim-screen"></canvas> <input id="vim-input" autocomplete="off" autofocus /> </div> <script type="module" src="/path/to/vim-wasm/vimwasm.js"></script> <script type="module" src="index.js"></script> </body> </html> import { VimWasm } from '/path/to/vim-wasm/vimwasm.js'; const vim = new VimWasm({ workerScriptPath: '/path/to/vim-wasm/vim.js', canvas: document.getElementById('vim-screen'), input: document.getElementById('vim-input'), }); vim.start(); JOEFYIUNM JOEFYKT -
vim.wasm ͷߏ WJNXBTNKT ΤϯτϦʔϙΠϯτɽ8FC8PSLFSͷϥΠϑαΠΫϧΛཧ͢Δɽ %0.ʹΞΫηεͰ͖Δɽ8FC8PSLFS͔ΒඳըใΛड͚औΓɼ DBOWBTͷඳըΛߦͬͨΓɼ,FZCPBSE&WFOUΛड͚ͨΓ͢Δɽ WJNKT 8FC8PSLFSͰ ΔεΫϦϓτɽ 8BTNϑΝΠϧΛ
ಡΈࠐΈɼ7JNͱ ΓऔΓ͢Δ WJNXBTN 7JNͷ$ίʔυ͔ΒίϯύΠϧ ͨ͠8BTNόΠφϦɽ ΤσΟλͷίΞϩδοΫʢςΩε τόοϑΝͷཧೖྗͷॲཧɼ εΫϦʔϯͷඳըܭࢉͳͲʣ new Worker("vim.js"); wasm_main(); postMessage(); Atomics.notify(); gui_wasm_*(); vimwasm_*(); ϝΠϯεϨου ϫʔΧʔεϨου -
$BMDVMBUF *OQVU 4FRVFODF ,FZEPXO &WFOU *OQVUUP #V⒎FS &WFOU -PPQ 6TFS
,FZ*OQVU %SBX5FYU %SBX3FDU 4DSPMM3FHJPO ʜ %SBX&WFOU 5ZQF4DSJQU 7JN 8BTN %JTQMBZ $BMDVMBUF 3FOEFSJOH $PSF &EJUPS -PHJD 5ZQF4DSJQU $BMDVMBUF DBOWBT SFOEFSJOH 3FOEFSUP DBOWBT POBOJNBUJPOGSBNF 4IBSFE#V⒎FS ,FZ%BUB LFZOBNF DIBSDPEF NPEJpFST 8BJU-PBE 1PTU .FTTBHF .BJO5ISFBE 8PSLFS5ISFBE WJNXBTNKT WJNKT WJNXBTN 4UPSF -
ϝΠϯεϨου • ී௨ͷ JavaScript ϥΠϒϥϦʢES Moduleʣ • Worker ͷىಈͱऴྃ •
ϫʔΧʔεϨουͱͷΓऔΓ • ඳըΠϕϯτΛ animation frame Ͱ <canvas/> ʹඳըʢcustom drawer Λ࣮͢Δ͜ͱ Ͱ͖Δʣ • Ωʔೖྗ • ΟϯυͷϦαΠζ • ... • ϫʔΧʔεϨου͔Βͷ௨ onmessage Ͱड͚ɼϫʔΧʔεϨουͷ௨ SharedMemoryBuffer ͱ Atomics API Λ͏ import { VimWasm } from '/path/to/vim-wasm/vimwasm.js'; const vim = new VimWasm({ ... }); vim.start(); IUUQTHJUIVCDPNSIZTEWJNXBTNCMPCXBTNXBTNWJNXBTNUT -
ϫʔΧʔεϨου • emcc -o vim.js ͰϏϧυͨ͠ Vim • ϝΠϯεϨουͱͷΓऔΓ --js-library
ͰΈࠐΜͩ JavaScript Ͱߦ͏ • Vim (vim.wasm) ͱ JS ϥϯλΠϜ (runtime.ts) ͱؔݺͼ ग़͠ͰΓऔΓɽemscripten ͕ͭͳ͍Ͱ͘ΕΔ • Atomics API Λ͍ɼϝΠϯεϨου͔Βͷ௨Λ SharedArrayBuffer Ͱಉظతʹड͚औΔ IUUQTHJUIVCDPNSIZTEWJNXBTNCMPCXBTNXBTNSVOUJNFUT -
ϫʔΧʔεΫϦϓτͷϏϧυ $MBOH NBJOD HVJD UFSND PT@VOJYD HVJ@XBTN ɾ ɾ ɾ
NBJOP HVJP UFSNP PT@VOJYP HVJ@XBTNP ɾ ɾ ɾ $4PVSDFT --7. CJUDPEF WJNCD --7. CJUDPEF QSFUT NBJOUT WJNXBTN WJNEBUB 5ZQF4DSJQU 3VOUJNF SVOUJNFUT FYFDVUBCMF MMWNMJOL #JOBSZFO NBJOKT WJNKT JOEFYIUNM TUZMFDTT VTSMPDBMTIBSFWJN WJNUVUPS -
Vim ͷ C ଆͷ࣮ Vim Makefile ͰϦϯΫ͢ΔϑΝΠϧΛΓସ ͑Δ͜ͱͰɼGUI ࣮ΛΓସ͑Δ͜ͱ͕Ͱ͖Δ
→ ৽͍͠ GUI ࣮ͱͯ͠ gui_wasm ΛՃ͠ɼ ͦͷதͰ JavaScript ଆͷؔΛݺͿ ΤσΟλͷίΞ෦ʹखΛೖΕͳͯ͘ྑ͍ -
Vim ͷ C ଆͷ࣮ SVOUJNFKT ϝΠϯεϨου͔Βೖ ྗΛड͚औΔ HVJ@XBTND (6*ॲཧʹԠͯ͡ɼదٓ +BWB4DSJQUଆʹॲཧΛ͛
Δ (6*࣮ؔΛݺͼ ग़ͯ͠(6*ॲཧ 7JNͷίΞϩδοΫ ೖྗΛॲཧͯ͠ΤσΟλͷঢ় ଶΛΞοϓσʔτ ʢςΩετόοϑΝɼεΫϦʔ ϯඳըͳͲʣ $ͷؔݺ ͼग़͠ HVJ@XBTN@ SVOUJNFKT w ඳըΠϕϯτΛϝΠϯ εϨουʹ͛Δ w "UPNJDTͰಉظXBJU +4ͷؔݺ ͼग़͠ WJNXBTN@ -
Vim ͷϝΠϯϧʔϓ ΤσΟλͷίΞϩδοΫ w ςΩετόοϑΝͷߋ৽ w εΫϦʔϯඳը w 7JNTDSJQUͷධՁ w
(6*ॲཧ w ը໘ඳը w Ϣʔβͷೖྗͪ w Ωʔೖྗ w ը໘ͷϦαΠζ w ಉظతͳೖྗ͕ͪඞཁ -
ಉظతͳೖྗ͕ͪඞཁ • Vim GUI ࣮Λ௨ͯ͠ϢʔβͷೖྗΛಉظతʹͭɽ ଟ͘ͷ GUI ϑϨʔϜϫʔΫ࣮Ͱ… •
ϑϨʔϜϫʔΫ͕࣋ͭϝΠϯϧʔϓ͕ཧ • ୯ʹ sleep() Ͱ polling ͯͭ͠ • WebAssembly JavaScript ϒϩοΩϯάૢ࡞ʹ͔ ͳΓݫ͘͠ɼجຊతʹඇಉظॲཧ͔͠Ͱ͖ͣϒϩοΫͰ ͖ͳ͍ -
ಉظతͳೖྗ͕ͪඞཁ • vim.wasm Ͱ࠷ॳ Emterpreter Λ͍ɼ emscripten_sleep Λ͍ͬͯͨ • ࣮ߦ͕͍
• όΠφϦαΠζ͕ΕΔ • Emterpreter ͰΒͤΔؔͷڊେͳϦετΛखͰཧ͢Δඞཁ͕͋Δ • ࣮͕ buggy • https://speakerdeck.com/rhysd/vim-ported-to-webassembly-vimconf-2018 • Web Worker Ͱ JS ͷ Atomics API Λͬͯಉظ తʹͭ -
Atomics API • JavaScript ͰεϨουؒͷ ಉظॲཧΛߦ͏ͨΊͷϨ ϕϧ API • εϨουؒͷڞ༗ϝϞϦͱ
ͯ͠ݻఆͷ int32 ྻͷ SharedArrayBuffer Λ͏ • Web Worker ݶఆͰɼόο ϑΝ্ͷ͕มΘΔͷΛ Atomics.wait Ͱಉظతʹ ͯΔ (futex(7)) const worker = new Worker('worker.js'); const buffer = new Int32Array( new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 1) ); new Worker('worker.js').postMessage(buffer); setTimeout(() => { // ࠷ॳͷཁૉΛ 0 ! 1 ʹॻ͖͑Δ Atomics.store(buffer, 0, 1); // ཁૉ͕ॻ͖Θͬͨ͜ͱΛ௨ͯ͠ϫʔΧʔΛى͜͢ Atomics.notify(buffer, 0, 1); }, 1000); onmessage = e => { const buffer = e.data; // 1ཁૉΛ0ΫϦΞ Atomics.store(buffer, 0, 0); // ͜͜Ͱ buffer ͕ॻ͖ΘΔ·Ͱ࣮ߦ͕ࢭ·Δ Atomics.wait(buffer, 0, 0); }; ϝΠϯεϨου ϫʔΧʔεϨου -
Atomics API • όοϑΝݻఆͳͷͰɼϝΠϯɾϫʔΧʔؒͷՄมσʔλ ʢe.g. ςΩετʣผ్όοϑΝΛ༻ҙͯ͠Δඞཁ͕͋Δ ϝΠϯεϨου ϫʔΧʔεϨου BCDEFΛૹΓ͍ͨ CZUFTόοϑΝ΄͍͠
ੜ ڞ༗όοϑΝ όοϑΝͷࢀরΛ͢ ॻ͖ࠐΈ όοϑΝʹॻ͍ͨΑ ($ ಡΈऔΓ BCDEFΛड͚औͬͨ -
Atomics API Λ͏ܽ • Spectre ੬ऑੑͷͨΊɼݱঢ়Ͱ΄΅ Chromeʢͱ Chromium ϕʔεϒϥβʣݶఆ •
Ϣʔβ͔ΒͷೖྗΛಉظతʹͭͨΊɼίʔϧόοΫ͕ൃՐ͢Δ λΠϛϯά͕ͳ͘ͳΔ • requestAnimationFrame() ൃՐ͠ͳ͍ • onmessage ίʔϧόοΫൃՐ͠ͳ͍ • ՄมσʔλͷΓऔΓ͕ࡶ • ϒϥβͷόάΛ౿Ή • @nhiroki_ ͞Μʹ৭ʑରԠ͍͖ͯͨͩ͠·ͨ͠ -
ࠓޙ • emscripten LLVM όοΫΤϯυʹΓ͑ • ৽͍͠ Asyncify • ύϑΥʔϚϯεվળʢC
ଆͷ tracing ΛͲ͏͢ Δ͔͕՝ʣ • Web Components ͷΧελϜཁૉԽ -
emscripten LLVM Wasm όοΫ Τϯυ • https://v8.dev/blog/emscripten-llvm-wasm • Ҏલ LLVM
bitcode ͔ΒҰ୴ asm.js Λܦ༝ͯ͠ Wasm ʹม͍ͯͨ͠ʢfastcompʣ͕ɼ Wasm ʹมͰ͖ΔΑ͏ʹͳΔ • Կ͠ͳͯ͘όΠφϦαΠζͱϦϯΫ͕࣌ؒվળɽ ඌݺͼग़͠࠷దԽͳͲͷ Wasm ͷ৽ػೳ͕͙͢ ͑Δ -
• Ϗϧυ࣌ؒ • όΠφϦαΠζ emscripten LLVM Wasm όοΫ Τϯυ
NBLFDQVTUPUBM FNDDDQVTUPUBM NBLFDQVTUPUBM FNDDDQVTUPUBM ˠ,J# ˠ,J# -
৽͍͠ Asyncify • چ Asyncify, Emterpreter ʹΘΔɼC ͰඇಉظॲཧΛ࣮͢Δͨ ΊͷΈɽίϧʔνϯͷΑ͏ʹॲཧΛதஅɾ࠶։Ͱ͖Δ •
https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html • େنͳมΛڬ·ͳ͍ͷͰɼ࣮ߦͷΦʔόʔϔου͕͔ͳΓখ ͍͞ • Wasm ʹΤΫεϙʔτ͞Εͨ intrinsic ؔͰ rewind/unwind ͢Δ • Binaryen ͷ࠷దԽύεͰ rewind/unwind ͞ΕΔ͔͠Εͳ͍ؔ ͷ caller&callee ͰελοΫΛอଘ͢ΔॲཧΛίʔυʹࠩ͠ࠐΉ -
৽͍͠ Asyncify • vim.wasm Ͱ Atomics ʹΑΔಉظతͳ wait ͷΘΓʹ ಋೖΛݕ౼த
• requestAnimationFrame ͕͑ΔΑ͏ʹͳΔͷͰɼ OffscreenCanvas ʹΑΔը໘ඳը͕ߦ͑ΔΑ͏ʹͳΔ • Atomics API ΛΘͳ͍ͷͰɼChrome Ҏ֎ͷϒϥ βͰಈ͘Α͏ʹͳΔ • όΠφϦαΠζ͕݁ߏେ͖͘ͳΓͦ͏ʁʢཁௐࠪʣ