Share
Embed
What you can do with Ruby on WebAssembly
EuRuKo 2024 https://2024.euruko.org/speakers/yuta_saito
Yuta Saito
September 12, 2024
Transcript
37 slides
-
What you can do with Ruby on WebAssembly Yuta Saito
(@kateinoigakukun) EuRuKo 2024 1 -
About me • Yuta Saito / @kateinoigakukun • Master's student
from Tokyo, Japan • Committer of CRuby and Swift • Creator of ruby/ruby.wasm 2 -
Overview 1. Introduction to WebAssembly 2. Introduction to ruby.wasm 3.
Showcases 4. Technical details 5. Future vision 3 -
1. Introduction: WebAssembly A binary instruction format for a stack-based
machine Designed to be • Portable • Size- and Load-time efficient • Secure by Sandbox 4 -
Out side of the web • Many independent runtime implementations
outside of browsers: • Wasmtime, WAMR, WasmKit, etc. • Easy to embed in applications • Useful for software that accepts untrusted programs from users • Examples: Plugin systems, serverless environments, etc. 5 -
Both languages and platforms benefit from Wasm • For language
developers: • If it compiles to Wasm, it can run in various environments • For platform developers: • With a Wasm runtime, it can support multiple languages Good for program distribution formats. 6 -
2. Introduction: ruby.wasm • Introduced in RubyKaigi 2022 • Enables
running Ruby on everywhere by WebAssembly • This project consists of: 1. CRuby interpreter compiled to WebAssembly 2. Packaging system for interpreter + .rb files 3. JS interop library ( require 'js') 8 -
<html> <script src="https://cdn.jsdelivr.net/.../dist/browser.script.iife.js"></script> <script type="text/ruby" data-eval="async"> require "js" button =
JS.global[:document].createElement("button") button[:textContent] = "Click me!" button.addEventListener("click") do puts "Hello~" end response = JS.global.fetch("https://example.com/data.json").await puts response.json.await </script> </html> 9 -
3. Community showcase • play-ruby ruby.github.io/play-ruby • RunRuby.dev runruby.dev •
ruby-next playground: ruby-next.github.io4 • Tints 'N Shades gem: hansschnedlitz.com/tints-n-shades5 5 https://www.hansschnedlitz.com/2024/03/25/porting-a-ruby-gem-to-the-browser-with-ruby-wasm.html 4 https://evilmartians.com/chronicles/first-steps-with-ruby-wasm-or-building-ruby-next-playground 15 -
4. Technical details 1. Porting CRuby to WebAssembly 2. Package
Gems 3. Cross-compile C-Extensions 4. Pre-link C-Extension shared libraries 17 -
4.1. Porting CRuby to WebAssembly Me: OK, we already have
C to WebAssembly compiler, so it’s easier than Swift. ! Exceptions, Fiber, GC: NO 18 -
4.1. Porting CRuby to WebAssembly • Asyncify instrumentation: • Enables
conservative GC, exceptions, and Fiber with minimal platform-specific hacks • Trade off performance and code size for portability • It greatly works for the initial stage, but we need to improve it by using recent WebAssembly features. See RubyKaigi 2022 keynote for more details https://rubykaigi.org/2022/presentations/kateinoigakukun.html 19 -
4.2. Package Gems Package gem source files into the WebAssembly
binary by VFS # WARNING: Still Experimental $ bundle add ruby_wasm --group=development $ bundle add rainbow $ bundle exec rbwasm build -o ruby.wasm (snip) INFO: Packaging gem: rainbow-3.1.1 INFO: Size: 51.17 MB 20 -
4.3. Cross-compile C-Extensions Cross-compilation support in mkmf • mkmf is
the core of the C-extension build system in Ruby • 3 major mkmf users (extconf.rb consumers in other words): • CRuby build system • rake-compiler • RubyGems 22 -
4.3. Cross-compile C-Extensions Cross-compilation support without trick ✅ Feature #20345:
Add --target-rbconfig option to mkmf2 https://bugs.ruby-lang.org/issues/20345 $ ruby extconf.rb --target-rbconfig=path/to/rbconfig.rb creating Makefile $ make $ file nokogiri.so nokogiri.so: WebAssembly (wasm) binary module version 0x1 (MVP) 2 Will be available in Ruby 3.4 and later 23 -
4.3. Cross-compile C-Extensions Cross-compilation support in RubyGems ✅ PR #7628:
Add --target-rbconfig option to gem install https://github.com/rubygems/rubygems/pull/7628 $ gem install nokogiri --target-rbconfig=path/to/rbconfig.rb $ bundle install --target-rbconfig=path/to/rbconfig.rb 24 -
4.4. Pre-link C-Extension shared libraries Why not static linking? •
We already support statically-linked C-extensions • But, the build model is not suitable for the RubyGems ecosystem • Take a long linking time (especially due to Asyncify) • Need to tightly integrate with the CRuby build system 26 -
4.4. Pre-link C-Extension shared libraries Why not dynamic linking so
far? • WebAssembly does not have a standard dynamic linking ABI • If we do our bespoke dynamic linking3, the binary will be incompatible with standard WebAssembly runtimes 3 Emscripten does dynamic linking by its own loader 28 -
4.4. Pre-link C-Extension shared libraries Breakthrough: Component Model • A
new layer of WebAssembly standard • Consists of: • WIT (WebAssembly Interface Types) IDL • Module linking • ... and more 29 -
4.4. Pre-link C-Extension shared libraries Dynamic Linking upon Component Model
• Each module has its metadata for dynamic linking • "AOT" linker encapsulates "how to link modules" into Component 31 -
4.4. Pre-link C-Extension shared libraries AOT dynamic linking A new
concept of dynamic linking in WebAssembly • Done at the build time • The final binary is a Component • The linker is originally developed by Joel Dice in wit-component • Adjusted for Ruby use case 32 -
4.5. Pre-link C-Extension shared libraries Difference from the traditional dynamic
linking • The final binary, a Component, contains all the dependencies • No file-based shared library search at runtime • dlopen is available only for libraries known at build-time 33 -
Summary • Ruby is going to be more WebAssembly-friendly •
RubyGems support is partially available • Ruby is leveraging the state-of-the-art WebAssembly technology including the Component Model 37