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

RailsConf 2022 Keynote

RailsConf 2022 Keynote

This is my RailsConf 2022 keynote

Aaron Patterson

June 01, 2022
Tweet

More Decks by Aaron Patterson

Other Decks in Technology

Transcript

  1. AArch64 Example JIT a function that returns 0xF00DCAFE $ gel

    exec ruby test.rb "f00dcafe" Terminal Output require "aarch64" require "jit_buffer" # create a JIT buffer jit_buffer = JITBuffer.new 4096 asm = AArch64::Assembler.new # Make some instructions asm.pretty do asm.movz x0, 0xCAFE asm.movk x0, 0xF00D, lsl(16) asm.ret end # Write the instructions to a JIT buffer jit_buffer.writeable! asm.write_to jit_buffer jit_buffer.executable! # Execute the JIT buffer p jit_buffer.to_function([], -Fiddle::TYPE_INT).call.to_s(16) # => f00dcafe JIT Code
  2. AArch64 Example JIT a function that returns 0xF00DCAFE $ gel

    exec ruby test.rb "f00dcafe" Terminal Output asm = AArch64::Assembler.new # Make some instructions asm.pretty do asm.movz x0, 0xCAFE asm.movk x0, 0xF00D, lsl(16) asm.ret end JIT Code
  3. AArch64 Example JIT a function that returns 0xF00DCAFE $ gel

    exec ruby test.rb "f00dcafe" Terminal Output require "aarch64" require "jit_buffer" # create a JIT buffer jit_buffer = JITBuffer.new 4096 asm = AArch64::Assembler.new # Make some instructions asm.pretty do asm.movz x0, 0xCAFE asm.movk x0, 0xF00D, lsl(16) asm.ret end # Write the instructions to a JIT buffer jit_buffer.writeable! asm.write_to jit_buffer jit_buffer.executable! # Execute the JIT buffer p jit_buffer.to_function([], -Fiddle::TYPE_INT).call.to_s(16) # => f00dcafe JIT Code
  4. AArch64 Example JIT a function that returns 0xF00DCAFE $ gel

    exec ruby test.rb "f00dcafe" Terminal Output require "aarch64" require "jit_buffer" # create a JIT buffer jit_buffer = JITBuffer.new 4096 asm = AArch64::Assembler.new # Make some instructions asm.pretty do asm.movz x0, 0xCAFE asm.movk x0, 0xF00D, lsl(16) asm.ret end # Write the instructions to a JIT buffer jit_buffer.writeable! asm.write_to jit_buffer jit_buffer.executable! # Execute the JIT buffer p jit_buffer.to_function([], -Fiddle::TYPE_INT).call.to_s(16) # => f00dcafe JIT Code JITBuffer.new
  5. Test Code Execution Write some bytes and ensure it can

    execute them # create a JIT buffer jit_buffer = JITBuffer.new 4096 # Write the instructions to a JIT buffer jit_buffer.writeable! jit_buffer.write asm.to_binary jit_buffer.executable! # Execute the JIT buffer p jit_buffer.to_function([], -Fiddle::TYPE_INT).call
  6. Test Code Execution Add a check for the current platform

    # create a JIT buffer jit_buffer = JITBuffer.new 4096 # Write the instructions to a JIT buffer jit_buffer.writeable! if arm64? jit_buffer.write arm64_bytes else jit_buffer.write x86_bytes end jit_buffer.executable!
  7. Test Code Execution Add a check for the current platform

    # create a JIT buffer jit_buffer = JITBuffer.new 4096 # Write the instructions to a JIT buffer jit_buffer.writeable! if arm64? jit_buffer.write arm64_bytes else jit_buffer.write x86_bytes end jit_buffer.executable!
  8. x86 Machine Code Very Cool Code (Intel Syntax) .foo: mov

    rax, 0x2b ret jmp foo Put 0x2b in the "RAX" register Return from the current function Jump to the "foo" label???
  9. x86 Machine Code Bytes Bytes are in base 16 48

    C7 C0 2B 00 00 00 mov rax, 0x2b C3 ret EB F6 jmp foo [0x48, 0xc7, 0xc0, 0x2b, 0x00, 0x00, 0x00, 0xc3, 0xeb, 0xf6]
  10. ARM64 Machine Code Very Very Cool Code movz X11, 0x7b7

    movz X0, 0x2b ret Write 0x7b7 to X11 register because??? Write 0x2b to the X0 register Return from the current function
  11. ARM64 Machine Code Bytes Bytes are in base 16 EB

    F6 80 D2 movz x11, 0x7b7 60 05 80 D2 movz x0, 0x2b C0 03 5F D6 ret
  12. Machine Code for x86 and ARM64 x86_64 Machine Code 48

    C7 C0 2B 00 00 00 mov rax, 0x2b C3 ret EB F6 jmp foo ARM64 Machine Code EB F6 80 D2 movz x11, 0x7b7 60 05 80 D2 movz x0, 0x2b C0 03 5F D6 ret
  13. Machine Code for x86 and ARM64 x86_64 Machine Code 48

    C7 C0 2B 00 00 00 mov rax, 0x2b C3 ret EB F6 jmp foo ARM64 Machine Code EB F6 80 D2 movz x11, 0x7b7 60 05 80 D2 movz x0, 0x2b C0 03 5F D6 ret
  14. Machine Code for x86 and ARM64 48 C7 C0 2B

    00 00 00 mov rax, 0x2b C3 ret EB F6 jmp foo EB F6 80 D2 movz x11, 0x7b7 60 05 80 D2 movz x0, 0x2b C0 03 5F D6 ret
  15. Machine Code for x86 and ARM64 48 C7 C0 2B

    00 00 00 mov rax, 0x2b C3 ret EB F6 jmp foo EB F6 80 D2 60 05 80 D2 movz x0, 0x2b C0 03 5F D6 ret
  16. Machine Code for x86 and ARM64 48 C7 C0 2B

    00 00 00 mov rax, 0x2b C3 ret EB F6 EB F6 80 D2 movz x11, 0x7b7 60 05 80 D2 movz x0, 0x2b C0 03 5F D6 ret
  17. JITBuffer Test Case VCP (Very Cool Program) jit = JITBuffer.new

    4096 bytes = [0x48, 0xc7, 0xc0, 0x2b, 0x00, 0x00, 0x00, # x86_64 mov rax, 0x2b 0xc3, # x86_64 ret 0xeb, 0xf6, # x86 jmp 0x80, 0xd2, # ARM movz X11, 0x7b7 0x60, 0x05, 0x80, 0xd2, # ARM movz X0, #0x2b 0xc0, 0x03, 0x5f, 0xd6] # ARM ret jit.writeable! jit.write bytes.pack("C*") jit.executable! func = Fiddle::Function.new(jit.to_i + 8, [], Fiddle::TYPE_INT) assert_equal 0x2b, func.call Start at offset 8 Offset 8 Alw ays 0x2b!!
  18. Tenderlove Talk Timeline Teardown Jokes about local businesses Pictures of

    Cats W eird code not related to the topic M ain topic Abrupt ending after running out of tim e
  19. Talk Timeline Breakdown Jokes about local businesses Pictures of Cats

    W eird code not related to the topic M ain topic Abrupt ending after running out of tim e
  20. New Features in Rails 7 Cool! • Import maps •

    Hotwire Default • Turbo 7 Default • Stimulus 3 Default • JS Bundling • CSS Bundling
  21. New application.html.erb javascript_importmap_tags <!DOCTYPE html> <html> <head> <title>Myapp</title> <meta name="viewport"

    content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> </head> <body> <%= yield %> </body> </html>
  22. Define importmaps con fi g/importmap.rb # Pin npm packages by

    running ./bin/importmap pin "application", preload: true pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true pin_all_from "app/javascript/controllers", under: "controllers"
  23. Rendered Application Layout Import map automatically generated <script type="importmap" data-turbo-track="reload">{

    "imports": { "application": "/assets/application-123.js", "@hotwired/turbo-rails": "/assets/turbo.min-123.js", "@hotwired/stimulus": "/assets/stimulus.min-123.js", "@hotwired/stimulus-loading": "/assets/stimulus-loading-123.js", "controllers/application": "/assets/controllers/application-123.js", "controllers/hello_controller": "/assets/controllers/hello_controller-123.js", "controllers": "/assets/controllers/index-123.js" } }</script>
  24. Put a pin in it! Add stu ff to the

    import map $ bin/importmap pin [email protected]/startCase.js Pinning "lodash-es/startCase.js" to https://ga.jspm.io/npm:[email protected]/startCase.js es: Español
  25. New config/importmap.rb With lodash-es # Pin npm packages by running

    ./bin/importmap pin "application", preload: true pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true pin_all_from "app/javascript/controllers", under: "controllers" pin "lodash-es/startCase.js", to: "https://ga.jspm.io/npm:[email protected]/startCase.js"
  26. New config/importmap.rb With lodash-es # Pin npm packages by running

    ./bin/importmap pin "application", preload: true pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true pin_all_from "app/javascript/controllers", under: "controllers" pin "lodash-es/startCase.js", to: "https://ga.jspm.io/npm:[email protected]/startCase.js"
  27. New config/importmap.rb With lodash-es # Pin npm packages by running

    ./bin/importmap pin "application", preload: true pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true pin_all_from "app/javascript/controllers", under: "controllers" pin "@lodash/startCase", to: "https://ga.jspm.io/npm:[email protected]/startCase.js"
  28. New Sourcemap Has Lowdash! <script type="importmap" data-turbo-track="reload">{ "imports": { "application":

    "/assets/application-123.js", "@hotwired/turbo-rails": "/assets/turbo.min-123.js", "@hotwired/stimulus": "/assets/stimulus.min-123.js", "@hotwired/stimulus-loading": "/assets/stimulus-loading-123.js", "@lodash/startCase": "https://ga.jspm.io/npm:[email protected]/startCase.js", "controllers/application": "/assets/controllers/application-123.js", "controllers/hello_controller": "/assets/controllers/hello_controller-123.js", "controllers": "/assets/controllers/index-123.js" } }</script>
  29. New Sourcemap Has Lowdash! <script type="importmap" data-turbo-track="reload">{ "imports": { "application":

    "/assets/application-123.js", "@hotwired/turbo-rails": "/assets/turbo.min-123.js", "@hotwired/stimulus": "/assets/stimulus.min-123.js", "@hotwired/stimulus-loading": "/assets/stimulus-loading-123.js", "@lodash/startCase": "https://ga.jspm.io/npm:[email protected]/startCase.js", "controllers/application": "/assets/controllers/application-123.js", "controllers/hello_controller": "/assets/controllers/hello_controller-123.js", "controllers": "/assets/controllers/index-123.js" } }</script>
  30. Use the new module! <script type="module"> import startCase from '@lodash/startCase';

    const el = document.createElement('h1'); const words = "hello, mom!" const text = document.createTextNode(startCase(words)); el.appendChild(text); document.body.appendChild(el); </script>
  31. Indirect Names Use names rather than fi les <script type="importmap"

    data-turbo-track="reload">{ "imports": { "application": "/assets/application-123.js", "@hotwired/turbo-rails": "/assets/turbo.min-123.js", "@hotwired/stimulus": "/assets/stimulus.min-123.js", "@hotwired/stimulus-loading": "/assets/stimulus-loading-123.js", "controllers/application": "/assets/controllers/application-123.js", "controllers/hello_controller": "/assets/controllers/hello_controller-123.js", "controllers": "/assets/controllers/index-123.js" } }</script>
  32. Indirect Names Use names rather than fi les <script type="importmap"

    data-turbo-track="reload">{ "imports": { "application": "/assets/application-123.js", "@hotwired/turbo-rails": "/assets/turbo.min-123.js", "@hotwired/stimulus": "/assets/stimulus.min-123.js", "@hotwired/stimulus-loading": "/assets/stimulus-loading-123.js", "controllers/application": "/assets/controllers/application-123.js", "controllers/hello_controller": "/assets/controllers/hello_controller-123.js", "controllers": "/assets/controllers/index-123.js" } }</script>
  33. Rack Interface rack_app = lambda do |env| [200, {}, ["neat"]]

    end def webserver(app) status, headers, body = app.call({}) $socket.puts status $socket.puts headers body.each do |chunk| $socket.puts chunk end end webserver(rack_app) Rack App Webserver Request Data Response Data
  34. HTTP Timeline + First Commit of Rack Starting with HTTP/0.9

    1990 1998 2006 2014 2022 Websockets 2011 HTTP/3 2020 HTTP/2 2015 Rack 2007 HTTP/1.1 1997 HTTP/1.0 1996 HTTP/0.9 1991
  35. HTTP 0.9 Request / Response Connections were closed Client New

    TCP Connection Server HTTP Request HTTP Response perl ... ENV rack_app = lambda do |env| [200, {}, ["neat"]] end
  36. HTTP/1.0 RFC 1945 1990 1998 2006 2014 2022 Websockets 2011

    HTTP/3 2020 HTTP/2 2015 Rack 2007 HTTP/1.1 1997 HTTP/1.0 1996 HTTP/0.9 1991
  37. Fetch assets in parallel? <!DOCTYPE html> <html> <body> <img src="wow.gif"

    /> <h1>HELLO!</h1> <p>Happy Friday!!!</p> </body> </html>
  38. HTTP/1.1 RFC 2068 1990 1998 2006 2014 2022 Websockets 2011

    HTTP/3 2020 HTTP/2 2015 Rack 2007 HTTP/1.1 1997 HTTP/1.0 1996 HTTP/0.9 1991
  39. HTTP 1.1 Request / Response Connections are kept open Client

    New TCP Connection Server HTTP Request HTTP Response ruby ... ruby ... HTTP Request HTTP Response
  40. HTTP 1.1 Multiple Connections Thanks buddy! New TCP Connection Server

    HTTP Request HTTP Response ruby ... ruby ... HTTP Request HTTP Response Client New TCP Connection Server HTTP Request HTTP Response ruby ... ruby ... HTTP Request HTTP Response
  41. Rack is released! Version 0.1 1990 1998 2006 2014 2022

    Websockets 2011 HTTP/3 2020 HTTP/2 2015 Rack 2007 HTTP/1.1 1997 HTTP/1.0 1996 HTTP/0.9 1991
  42. Full Rack Application Example rack_app = lambda do |env| [200,

    # Status Code { "X-Cool-Header" => "Neat" }, # Headers ["Response Body"]] # Response Body end
  43. Websockets Sockets, but for the web! 1990 1998 2006 2014

    2022 Websockets 2011 HTTP/3 2020 HTTP/2 2015 Rack 2007 HTTP/1.1 1997 HTTP/1.0 1996 HTTP/0.9 1991
  44. Hijacking: Slap a proc in there! Get access to the

    socket rack_app = lambda do |env| io = env["rack.hijack"].call io.write "neat" io.close # socket is closed # Return stuff? [200, {}, []] end
  45. HTTP/2 It's 0.9 better than HTTP 1.1 1990 1998 2006

    2014 2022 Websockets 2011 HTTP/3 2020 HTTP/2 2015 Rack 2007 HTTP/1.1 1997 HTTP/1.0 1996 HTTP/0.9 1991
  46. Request / Response Multiplexing Concurrent requests on the same socket

    Client New SSL TCP Connection Server H2 Request 1 H2 Response 2 ruby ... ruby ... H2 Request 2 H2 Response 1
  47. HTTP 2 Proxy Server Proxy translates to HTTP 1.1 H2O

    Unicorn Rails HTTP 1.1 Rack HTTP 2
  48. Sending Server Push with H2 Proxy HTTP 1.1 server sends

    103, proxy converts to PUSH HTTP/1.1 103 Early Hints Link: </style.css>; rel=preload; as=style Link: </script.js>; rel=preload; as=script HTTP/1.1 200 OK Date: Fri, 26 May 2022 10:02:11 GMT Content-Length: 1234 Content-Type: text/html; charset=utf-8 Link: </style.css>; rel=preload; as=style Link: </script.js>; rel=preload; as=script HTTP 1.1 Response
  49. Sending Server Push with H2 Proxy HTTP 1.1 server sends

    103, proxy converts to PUSH HTTP/1.1 103 Early Hints Link: </style.css>; rel=preload; as=style Link: </script.js>; rel=preload; as=script HTTP 103 Response H2O Unicorn HTTP 1.1 HTTP 2 PUSH /style.css PUSH /script.js
  50. Slap another lambda in the env hash! Great! class Server

    def call env env['rack.early_hints'].call([ { link: "/style.css", as: "style" }, # push /style.css { link: "/script.js" }]) # push /script.js [200, { "X-Hello" => "World" }, ["Hello world!"]] end end