Slide 1

Slide 1 text

What you can do with Ruby on WebAssembly Yuta Saito (@kateinoigakukun) EuRuKo 2024 1

Slide 2

Slide 2 text

About me • Yuta Saito / @kateinoigakukun • Master's student from Tokyo, Japan • Committer of CRuby and Swift • Creator of ruby/ruby.wasm 2

Slide 3

Slide 3 text

Overview 1. Introduction to WebAssembly 2. Introduction to ruby.wasm 3. Showcases 4. Technical details 5. Future vision 3

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

WebAssembly as a program distribution format 7

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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 9

Slide 10

Slide 10 text

$ curl -LO https://github.com/ruby/ruby.wasm/releases/latest/download/ruby.wasm $ wasmtime run ruby.wasm hello.rb Hello, world! 10

Slide 11

Slide 11 text

3. Showcase 11

Slide 12

Slide 12 text

12

Slide 13

Slide 13 text

13

Slide 14

Slide 14 text

3. Showcase - Mastodon in the browser 14

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

4. Technical details 16

Slide 17

Slide 17 text

4. Technical details 1. Porting CRuby to WebAssembly 2. Package Gems 3. Cross-compile C-Extensions 4. Pre-link C-Extension shared libraries 17

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

4.2. Package Gems 21

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

4.4. Pre-link C-Extension shared libraries 25

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Static linking Dynamic linking 27

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

4.4. Pre-link C-Extension shared libraries Module Linking 30

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

5. Future vision 34

Slide 35

Slide 35 text

Roadmap 35

Slide 36

Slide 36 text

Interpreter size 36

Slide 37

Slide 37 text

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