Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby, Opal and WebAssembly

yhara
September 19, 2017

Ruby, Opal and WebAssembly

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

yhara

September 19, 2017
Tweet

More Decks by yhara

Other Decks in Programming

Transcript

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

    View full-size slide

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

    View full-size slide

  3. RubyKaigi 2017 (19, Sep) 3

    View full-size slide

  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

    View full-size slide

  5. My Book
    Available in the bookstore in the sponsors
    room
    RubyKaigi 2017 (19, Sep) 5

    View full-size slide

  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

    View full-size slide

  7. Agenda
    • 1. DXOpal
    • 2. DXOpal and WebAssembly
    • 3. Does WebAssembly change Rubyists' life?
    RubyKaigi 2017 (19, Sep) 7

    View full-size slide

  8. 1. DXOpal
    RubyKaigi 2017 (19, Sep) 8

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  13. Why Opal matters
    JavaScript

    Web App
    Desktop App (Electron)
    Mobile App (Cordova)
    ...
    RubyKaigi 2017 (19, Sep) 13

    View full-size slide

  14. Why Opal matters
    Ruby→Opal→JavaScript

    Web App
    Desktop App (Electron)
    Mobile App (Cordova)
    ...
    RubyKaigi 2017 (19, Sep) 14

    View full-size slide

  15. Why Opal matters
    Ruby→Opal→JavaScript

    Browser Games
    Visualizaiton
    RubyKaigi 2017 (19, Sep) 15

    View full-size slide

  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

    View full-size slide

  17. Making Opal Library
    # Goal
    Window.draw_circle(100, 100, 200, [0, 255, 0])
    RubyKaigi 2017 (19, Sep) 17

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  21. DEMO
    RubyKaigi 2017 (19, Sep) 21

    View full-size slide

  22. DEMO 2
    • Experimental: Physics simulation
    • powered by Matter.js
    RubyKaigi 2017 (19, Sep) 22

    View full-size slide

  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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  26. Help wanted
    • More examples
    • Tutorial
    • Beautiful website
    https://github.com/yhara/dxopal/issues
    RubyKaigi 2017 (19, Sep) 26

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

  29. 2. DXOpal and WebAssembly
    RubyKaigi 2017 (19, Sep) 29

    View full-size slide

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

    View full-size slide

  31. Collision detection is heavy
    • Each Sprite has a hit-area
    (point/circle/rectangle/triangle)
    • + scaling, rotation
    RubyKaigi 2017 (19, Sep) 31

    View full-size slide

  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

    View full-size slide

  33. How about using WebAssembly?
    RubyKaigi 2017 (19, Sep) 33

    View full-size slide

  34. JavaScript as compile target
    • Opal (Ruby)
    • Scala.js (Scala)
    • GopherJS (Go)
    • ClojureScript (Clojure)
    • OCamljs (OCaml)
    • Elm (Haskell-like)
    • ...
    RubyKaigi 2017 (19, Sep) 34

    View full-size slide

  35. Emscripten
    • 2012~
    • Compile C/C++ into JavaScript through LLVM IR
    [.c]
    |
    +------|-------+
    | v |
    | [LLVM IR] | Emscripten
    | | |
    +------|-------+
    v
    [.js]
    RubyKaigi 2017 (19, Sep) 35

    View full-size slide

  36. JavaScript is not so good to be assembly
    1. Performance predictability
    2. Output size
    RubyKaigi 2017 (19, Sep) 36

    View full-size slide

  37. 1. Performance predictability
    • How to write fast JS program
    • is different among browsers
    (each has different JS engine)
    RubyKaigi 2017 (19, Sep) 37

    View full-size slide

  38. What Emscripten needs
    • Ultra-fast arithmetic operations
    • A huge TypedArray (memory)
    • No objects
    • No methods
    RubyKaigi 2017 (19, Sep) 38

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

  41. asm.js
    [ asm.js ]
    | |
    Run as JS | | Run as asm.js
    v v
    [Old Browser] [New Browser]
    RubyKaigi 2017 (19, Sep) 41

    View full-size slide

  42. 2. File size problem
    • Huge .js file
    • Downloading time
    • Parsing time
    • Optimizing time
    RubyKaigi 2017 (19, Sep) 42

    View full-size slide

  43. Here comes WebAssembly
    • http://webassembly.org/
    • Binary format
    • Less downloading time
    • Less parsing time
    • Less optimizing time
    RubyKaigi 2017 (19, Sep) 43

    View full-size slide

  44. Summary
    JS asm.js WebAssembly
    Performance
    predictability
    bad good good
    Size
    (= load time)
    bad bad good
    RubyKaigi 2017 (19, Sep) 44

    View full-size slide

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

    View full-size slide

  46. DXOpal + WebAssembly
    • Use WebAssembly for collision detection
    • Original code (DXRuby) is written in C
    RubyKaigi 2017 (19, Sep) 46

    View full-size slide

  47. Compile collision.c into WebAssembly
    • Cannot port entire C source
    (because of RB_ARRAY etc.)
    • Extract some functions
    RubyKaigi 2017 (19, Sep) 47

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  50. Demo
    RubyKaigi 2017 (19, Sep) 50

    View full-size slide

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

    View full-size slide

  52. WebAssembly is not designed to run faster than JavaScript
    http://2ality.com/2015/06/web-assembly.html
    RubyKaigi 2017 (19, Sep) 52

    View full-size slide

  53. Demo
    RubyKaigi 2017 (19, Sep) 53

    View full-size slide

  54. WebAssembly and run speed
    • WebAssembly is tree (non-linear)
    • Easier to implement to each browsers?
    RubyKaigi 2017 (19, Sep) 54

    View full-size slide

  55. 3. Does WebAssembly change Rubyists' life?
    RubyKaigi 2017 (19, Sep) 55

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  60. 2: Possible in the future
    • Compiling Ruby into WebAssembly
    • It's not easy as it sounds!
    RubyKaigi 2017 (19, Sep) 60

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  69. Appendix
    RubyKaigi 2017 (19, Sep) 69

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide