Ruby, Opal and WebAssembly

26e1ba9a02729b2d6013604135221aae?s=47 yhara
September 19, 2017

Ruby, Opal and WebAssembly

RubyKaigi 2017
Presenter notes(Japanese): https://gist.github.com/yhara/ac76db6d2bf0b9ea9701d67db3ac5bd5

26e1ba9a02729b2d6013604135221aae?s=128

yhara

September 19, 2017
Tweet

Transcript

  1. Ruby, Opal and WebAssembly RubyKaigi2017 yhara (Yutaka Hara) RubyKaigi 2017

    (19, Sep) 1
  2. Myself • Yutaka Hara (@yhara) • http://yhara.jp • @ Matsue,

    Shimane RubyKaigi 2017 (19, Sep) 2
  3. RubyKaigi 2017 (19, Sep) 3

  4. Talks from member • Day 1 / Shugo Maeda /

    Handling mails on a text editor • Day 2 / Matz / Keynote • Day 2 / Yutaka Hara / Ruby, Opal and WebAssembly • Day 3 / Kouji Takao / Smalruby : The neat thing to connect Rubyists and Scratchers RubyKaigi 2017 (19, Sep) 4
  5. My Book Available in the bookstore in the sponsors room

    RubyKaigi 2017 (19, Sep) 5
  6. Me on RubyKaigi • 2007: Ruby/SDLͱͦͷपล (with Obayashi-san) • 2009:

    Ruby੡ΞϓϦέʔγϣϯΛ഑෍͢Δnݸͷํ๏ • 2011: RubyϚελʔ΁ͷಓ • 2012: DIY Programming1 • 2015: Let's Make a Functional Language! • 2017: Ruby, Opal and WebAssembly (see http://yhara.jp/Presentations for other events) 1 "The" RubyKaigi was not held in this year RubyKaigi 2017 (19, Sep) 6
  7. Agenda • 1. DXOpal • 2. DXOpal and WebAssembly •

    3. Does WebAssembly change Rubyists' life? RubyKaigi 2017 (19, Sep) 7
  8. 1. DXOpal RubyKaigi 2017 (19, Sep) 8

  9. Opal Ruby to JavaScript compiler http://opalrb.org RubyKaigi 2017 (19, Sep)

    9
  10. Opal Talks in RubyKaigi2017 • Day 1 / dRuby on

    Brower / Yoh Osaki • Day 2 / Yutaka Hara / Ruby, Opal and WebAssembly RubyKaigi 2017 (19, Sep) 10
  11. Why don't you try Opal? • Just didn't know (now

    you know :-) • Lack of library? (compared to tons of JS libs) • Happy with ES6+? (classes, arrow syntax, ...) RubyKaigi 2017 (19, Sep) 11
  12. Why Ruby matters (to me) • I don't hate JavaScript.

    I'm just too fluent in Ruby :-) • "Cached in my brain" 2 • Hash, Enumerable#flat_map, etc. 2 https://www.slideshare.net/mametter/ruby-65182128 (p.69) RubyKaigi 2017 (19, Sep) 12
  13. Why Opal matters JavaScript ↓ Web App Desktop App (Electron)

    Mobile App (Cordova) ... RubyKaigi 2017 (19, Sep) 13
  14. Why Opal matters Ruby→Opal→JavaScript ↓ Web App Desktop App (Electron)

    Mobile App (Cordova) ... RubyKaigi 2017 (19, Sep) 14
  15. Why Opal matters Ruby→Opal→JavaScript ↓ Browser Games Visualizaiton RubyKaigi 2017

    (19, Sep) 15
  16. DXOpal • Opal port of DXRuby • DXRuby: Game Framework

    for Ruby on Windows • http://dxruby.osdn.jp/ • 2009~ • Simple and sufficient API RubyKaigi 2017 (19, Sep) 16
  17. Making Opal Library # Goal Window.draw_circle(100, 100, 200, [0, 255,

    0]) RubyKaigi 2017 (19, Sep) 17
  18. Making Opal Library module DXOpal class Window def self.draw_circle(x, y,

    r, color) # ?? end end end RubyKaigi 2017 (19, Sep) 18
  19. Making Opal Library module DXOpal class Window def self.draw_circle(x, y,

    r, color) %x{ ... ctx.arc(x, y, r, 0, Math.PI*2, false); ... } end end end RubyKaigi 2017 (19, Sep) 19
  20. Compatibility https://github.com/yhara/dxopal/blob/master/TODO.md class DXRuby DXOpal module Input OK Basically (TODO:

    pad support) module Window OK Basically class Font OK Basically class Image OK Basically class Sound OK Basically class SoundEffect OK Basically class Sprite OK Ongoing (TODO: collision detection) class RenderTarget OK N/A class Shader OK N/A class Shader::Core OK N/A RubyKaigi 2017 (19, Sep) 20
  21. DEMO RubyKaigi 2017 (19, Sep) 21

  22. DEMO 2 • Experimental: Physics simulation • powered by Matter.js

    RubyKaigi 2017 (19, Sep) 22
  23. DEMO 3 • You don't need to install Ruby! 1.

    Download and unpack dxoapl-game-x.y.z.zip 2. Edit main.rb 3. Open index.html with Firefox fx fx Chrome is not ok because it raises error when ajax'ing images from file:// RubyKaigi 2017 (19, Sep) 23
  24. How dxopal-game works [index.html] [main.rb] | load ^ v |

    ajax [dxopal.min.js]-------+ RubyKaigi 2017 (19, Sep) 24
  25. How dxopal-game works [index.html] [main.rb] | load ^ v |

    ajax [dxopal/**.rb] --> [dxopal.min.js]-------+ ^ | [opal/**.rb] ----------+ RubyKaigi 2017 (19, Sep) 25
  26. Help wanted • More examples • Tutorial • Beautiful website

    https://github.com/yhara/dxopal/issues RubyKaigi 2017 (19, Sep) 26
  27. opalrb-jp If you need help in Japanese: https://opalrb-jp-slack.herokuapp.com/ RubyKaigi 2017

    (19, Sep) 27
  28. TODOs left for DXOpal v0.4.0 • Collision checking feature is

    unfinished yet • (Mostly because I've been writing this slide :-P) • Let's talk about that RubyKaigi 2017 (19, Sep) 28
  29. 2. DXOpal and WebAssembly RubyKaigi 2017 (19, Sep) 29

  30. DXRuby's Sprite class player = Sprite.new(100, 100, Image[:player]) SpriteʹImageʴCoordinatesʴCollision Checking

    RubyKaigi 2017 (19, Sep) 30
  31. Collision detection is heavy • Each Sprite has a hit-area

    (point/circle/rectangle/triangle) • + scaling, rotation RubyKaigi 2017 (19, Sep) 31
  32. Opal is not so fast (as JavaScript) # Ruby cx

    = (x1 + x2 + x3) / 3 // Compiled JavaScript cx = $rb_divide(($rb_plus($rb_plus(x1, x2), x3)), 3); Because you can "add" Strings or Arrays in Ruby RubyKaigi 2017 (19, Sep) 32
  33. How about using WebAssembly? RubyKaigi 2017 (19, Sep) 33

  34. JavaScript as compile target • Opal (Ruby) • Scala.js (Scala)

    • GopherJS (Go) • ClojureScript (Clojure) • OCamljs (OCaml) • Elm (Haskell-like) • ... RubyKaigi 2017 (19, Sep) 34
  35. Emscripten • 2012~ • Compile C/C++ into JavaScript through LLVM

    IR [.c] | +------|-------+ | v | | [LLVM IR] | Emscripten | | | +------|-------+ v [.js] RubyKaigi 2017 (19, Sep) 35
  36. JavaScript is not so good to be assembly 1. Performance

    predictability 2. Output size RubyKaigi 2017 (19, Sep) 36
  37. 1. Performance predictability • How to write fast JS program

    • is different among browsers (each has different JS engine) RubyKaigi 2017 (19, Sep) 37
  38. What Emscripten needs • Ultra-fast arithmetic operations • A huge

    TypedArray (memory) • No objects • No methods RubyKaigi 2017 (19, Sep) 38
  39. asm.js • Statically typed programming language • No objects •

    No methods RubyKaigi 2017 (19, Sep) 39
  40. asm.js • Small subset of JS (asm.js program is polyglot

    of JS) • Example5e function AddFunctions(){ "use asm"; function add1(value){ value = value | 0; // Declare `value` is int var result = 0; result = (value + 1) | 0; return result; } return { add1: add1 } } 5e https://html5experts.jp/chikoski/18980/ RubyKaigi 2017 (19, Sep) 40
  41. asm.js [ asm.js ] | | Run as JS |

    | Run as asm.js v v [Old Browser] [New Browser] RubyKaigi 2017 (19, Sep) 41
  42. 2. File size problem • Huge .js file • Downloading

    time • Parsing time • Optimizing time RubyKaigi 2017 (19, Sep) 42
  43. Here comes WebAssembly • http://webassembly.org/ • Binary format • Less

    downloading time • Less parsing time • Less optimizing time RubyKaigi 2017 (19, Sep) 43
  44. Summary JS asm.js WebAssembly Performance predictability bad good good Size

    (= load time) bad bad good RubyKaigi 2017 (19, Sep) 44
  45. Browser support http://caniuse.com/#feat=wasm RubyKaigi 2017 (19, Sep) 45

  46. DXOpal + WebAssembly • Use WebAssembly for collision detection •

    Original code (DXRuby) is written in C RubyKaigi 2017 (19, Sep) 46
  47. Compile collision.c into WebAssembly • Cannot port entire C source

    (because of RB_ARRAY etc.) • Extract some functions RubyKaigi 2017 (19, Sep) 47
  48. Compile collision.c into WebAssembly // (...snip...) #define check_line_line( x1, y1,

    x2, y2, x3, y3, x4, y4) \ ( !((((x1 - x2) * (y3 - y1) + (y1 - y2) * (x1 - x3)) * \ ((x1 - x2) * (y4 - y1) + (y1 - y2) * (x1 - x4)) > 0.0) || \ (((x3 - x4) * (y1 - y3) + (y3 - y4) * (x3 - x1)) * \ ((x3 - x4) * (y2 - y3) + (y3 - y4) * (x3 - x2)) > 0.0 ))) int check_triangle_triangle(float ox[3], float oy[3], float dx[3], float dy[3]) { return check_line_line(ox[0], oy[0], ox[1], oy[1], dx[1], dy[1], dx[2], dy[2]) || check_line_line(ox[0], oy[0], ox[1], oy[1], dx[2], dy[2], dx[0], dy[0]) || check_line_line(ox[1], oy[1], ox[2], oy[2], dx[0], dy[0], dx[1], dy[1]) || check_line_line(ox[1], oy[1], ox[2], oy[2], dx[2], dy[2], dx[0], dy[0]) || check_line_line(ox[2], oy[2], ox[0], oy[0], dx[0], dy[0], dx[1], dy[1]) || check_line_line(ox[2], oy[2], ox[0], oy[0], dx[1], dy[1], dx[2], dy[2]) || check_point_triangle(ox[0], oy[0], dx[0], dy[0], dx[1], dy[1], dx[2], dy[2]) || check_point_triangle(dx[0], dy[0], ox[0], oy[0], ox[1], oy[1], ox[2], oy[2]); }; RubyKaigi 2017 (19, Sep) 48
  49. Compile collision.c into WebAssembly 0000000 00 61 73 6d 01

    00 00 00 01 95 80 80 80 00 02 60 0000010 08 7d 7d 7d 7d 7d 7d 7d 7d 01 7f 60 04 7f 7f 7f 0000020 7f 01 7f 03 83 80 80 80 00 02 00 01 04 84 80 80 0000030 80 00 01 70 00 00 05 84 80 80 80 00 01 00 99 01 0000040 07 bb 80 80 80 00 03 06 6d 65 6d 6f 72 79 02 00 0000050 14 63 68 65 63 6b 5f 70 6f 69 6e 74 5f 74 72 69 0000060 61 6e 67 6c 65 00 00 17 63 68 65 63 6b 5f 74 72 0000070 69 61 6e 67 6c 65 5f 74 72 69 61 6e 67 6c 65 00 0000080 01 09 81 80 80 80 00 00 0a b6 8a 80 80 00 02 e4 0000090 81 80 80 00 02 01 7f 04 7d 02 7f 41 00 21 08 02 (...snip...) RubyKaigi 2017 (19, Sep) 49
  50. Demo RubyKaigi 2017 (19, Sep) 50

  51. Important notice ! RubyKaigi 2017 (19, Sep) 51

  52. WebAssembly is not designed to run faster than JavaScript http://2ality.com/2015/06/web-assembly.html

    RubyKaigi 2017 (19, Sep) 52
  53. Demo RubyKaigi 2017 (19, Sep) 53

  54. WebAssembly and run speed • WebAssembly is tree (non-linear) •

    Easier to implement to each browsers? RubyKaigi 2017 (19, Sep) 54
  55. 3. Does WebAssembly change Rubyists' life? RubyKaigi 2017 (19, Sep)

    55
  56. Does WebAssembly change Rubyists' life? • For example, can we

    use Ruby instead of React, etc.? • The official WebAssembly site says: • "including support for languages other than C/C++" hg hg http://webassembly.org/docs/high-level-goals/ 2. RubyKaigi 2017 (19, Sep) 56
  57. What WebAssembly can do • New compile target for the

    web • Better loading time (cf. JS, asm.js) • C/C++/Rust is supported now • Ruby is not supported "yet" RubyKaigi 2017 (19, Sep) 57
  58. How to use WebAssembly with Ruby? • 1: Currently possible

    (C/C++/Rust -> WebAssembly) • 2: Possible in the future (Ruby -> WebAssembly) RubyKaigi 2017 (19, Sep) 58
  59. 1: Currently possible • Opal + WebAssembly (like DXOpal) •

    But DXOpal's case was not so meaningful • Same execution speed, easy to port to JS • Could be meaningful when: • Original C code is too long to port • Original C code is too complex to port (eg. cryptography, WebUSB) • Original C code is changed constantly RubyKaigi 2017 (19, Sep) 59
  60. 2: Possible in the future • Compiling Ruby into WebAssembly

    • It's not easy as it sounds! RubyKaigi 2017 (19, Sep) 60
  61. How to compile Ruby into WebAssembly? • 1: Ruby is

    too dynamic • 2: Ruby is dynamically typed language • 3: Runtime issue • 4: GC issue? RubyKaigi 2017 (19, Sep) 61
  62. How to compile Ruby into WebAssembly? • 1: Ruby is

    very dynamic • Features to evaluate code in runtime (instance_eval, etc.) • a) Embed entire Ruby processor into WebAssembly • b) Restrict some dynamic features RubyKaigi 2017 (19, Sep) 62
  63. How to compile Ruby into WebAssembly? • 2: Ruby is

    dynamically typed language • Hard to "compile" into statically typed language • a) Wrap everything with struct (very slow) • b) Type inference, type annotation • c) Use Ruby-like static language (Crystal) RubyKaigi 2017 (19, Sep) 63
  64. How to compile Ruby into WebAssembly? • 3: Runtime issue

    • Network, etc. cannot be accessed directly from WebAssembly • So some corelib/stdlibs (like Net::HTTP) need porting RubyKaigi 2017 (19, Sep) 64
  65. How to compile Ruby into WebAssembly? • 4: GC issue

    • You cannot walk stack of WebAssembly • Future plan: https://github.com/WebAssembly/design/ issues/1079 • This affects Crystal (GH #829) cr cr Problems 1, 2 are solved by Crystal but 3, 4 remain RubyKaigi 2017 (19, Sep) 65
  66. Do we need to compile Ruby into WebAssembly? • We

    have Opal already! • to run Ruby code on the browser • (One possible difference: WebAssembly-Ruby may run Ruby's C-extensions) RubyKaigi 2017 (19, Sep) 66
  67. If you want to write entire code with Ruby: •

    You can use Opal! • http://opalrb.org/libraries/ • HyperLoop • ClearWater • Inasita • Menilite • Lissio • ... RubyKaigi 2017 (19, Sep) 67
  68. Wrap up • DXOpal: Browser game framework for Ruby •

    WebAssembly is not a silver bullet • Don't wait for the future, use Opal now! RubyKaigi 2017 (19, Sep) 68
  69. Appendix RubyKaigi 2017 (19, Sep) 69

  70. PNaCl (Portable Native Client) • 2013~ • Implemented in Google

    Chrome • "safe, portable, high-performance apps without plugins" • Run native code in browser, securely • Discontinued ch ch https://blog.chromium.org/2017/05/goodbye-pnacl-hello-webassembly.html?m=1 RubyKaigi 2017 (19, Sep) 70
  71. Toolchains [A] Using emcc (Compile through asm.js) .c ---------> .ll

    ----------> asm.js ----------> .wasm Clang Emscripten binaryen (asm2wasm) [B] Using LLVM (Experimental) .c ---------> .ll ----------> .s ----------> .wasm Clang LLVM binaryen (s2wasm) RubyKaigi 2017 (19, Sep) 71
  72. Non-web context • Interesting possible usage of WebAssembly-Ruby: Run on

    Node.js on AWS lambda (which does not support Ruby) [WebAssembly] <- [*.rb] | [Node.js] | [AWS lambda] • But Net::HTTP , etc. must be ported to use aws-sdk gem • eg. By using Node's API RubyKaigi 2017 (19, Sep) 72
  73. Crytal -> WebAssembly? • Crystal -> LLVM IR -> WebAssembly

    • What is needed • WebAssembly's GC support • Port some corelib/stdlib for WebAssembly • Output LLVM IR for WebAssembly? (I'm not sure) • https://github.com/crystal-lang/crystal/issues/829 RubyKaigi 2017 (19, Sep) 73