O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

YARV INTRODUCTION

at 2015-12-20 yochiyochirb

  • Entre para ver os comentários

YARV INTRODUCTION

  1. 1. YARVINTRODUCTION WAKASUGI HIROFUMI DECEMBER 20, 2015
  2. 2. Rubyプログラムが動く仕組みの中で、 中心的な役割の1つを占めるYARVを 簡単に紹介します。 YARVINTRODUCTION
  3. 3. YARV (Yet Another Ruby VM) • 現在のMRI (CRuby) の処理系 • Rubyコードを実行するための仮想マシン (VM) • Ruby 1.9でMRIに取り込まれた • 開発者は笹田耕一氏 YARVINTRODUCTION
  4. 4. 仮想マシンとは? YARVINTRODUCTION
  5. 5. ソフトウェアが動作する構造 ハードウェア OS ソフトウェア コンピューターでは、 ソフトウェアは左記の ようなレイヤー構造で 動く仕組みとなってい る YARVINTRODUCTION
  6. 6. ソフトウェアが動作する構造 ハードウェア OS ソフトウェア ソフトウェアはOSのAPIを利用 OSのカーネルがハードウェアを制御 ソフトウェアはOSによって「仮想化」されたハードウェア資源を活用する。 このように、間に仮想化機構を挟むことでギャップを埋め扱いやすくなる。 YARVINTRODUCTION
  7. 7. 一般的に「仮想マシン」と聞いて思い浮かぶもの ハードウェア OS (※) OS あるOSの上に仮想化されたマシンを構築 し、別のOSなどを動かせるもの ただ、YARVのような、プログラミング言 語における仮想マシンを考えるときには、 この仮想マシンのイメージに捉われすぎ ない方がいいかも ※実際にはほとんどオリジナルのOSはスルーして直接ハード ウェアを操作できることが多い 仮想マシン (VirtualBoxなど) ソフトウェア YARVINTRODUCTION
  8. 8. プログラミング言語処理系としての 「仮想マシン」 ハードウェア OS プログラミング言語 プログラミング言語は仮想マシン が解釈できる命令に変換され、仮 想マシンがその命令をOSなどより 低い層に伝える さっきのソフトウェアが動作する ための仮想化機構と考え方は同じ 仮想マシン YARVINTRODUCTION
  9. 9. VM VM VM プログラミング言語処理系としての 「仮想マシン」 OS プログラミング言語 VM YARVINTRODUCTION OS OS OS HW HW HW HW このように、プログラミング言語自体を マルチ環境に対応できるよう設計するの は非常に難しいが、仮想マシンを間に挟 むことで対応や最適化が容易になる 言語は仮想マシンが解釈できる命令を吐ければOK 仮想マシンのマルチ環境対応は比較的容易
  10. 10. 仮想マシンが解釈するもの => バイトコード YARVINTRODUCTION プログラミング言語 バイトコード 仮想マシンが解釈 できる命令列 コンパイル 仮想マシン 命令 プログラム実行…
  11. 11. 代表的な仮想マシン YARVINTRODUCTION Java JVM • おなじみ「Write Once, Run Anywhere」 • Javaはもちろん、Scala、Clojureなど多数がこの処理系で動作する .NET Framework • MS製だがOSSとして公開されており、本来プラットフォームは問わない • VB.NET、C#、F#などの言語がこの処理系で動作する
  12. 12. 代表的な仮想マシン YARVINTRODUCTION Java • おなじみ「Write Once, Run Anywhere • Javaはもちろん、Scala、Clojure .NET Framework • MS製だがOSS • VB.NET、C#、F# LLVMもLLVM IRという中間表現を利用す るなど仮想マシンに近いところはあるが、 厳密にはコンパイラ基盤なので ちょっとジャンルが違う
  13. 13. 仮想マシンのメリットまとめ YARVINTRODUCTION • マルチ環境への対応が容易になる • 各環境への最適化がしやすく高速化が期待できる • 別のプログラミング言語の開発もしやすい 仮想マシンという仲介役を用意し、プログラミング言語を 仮想マシンへの命令列にコンパイルする仕組みによって、
  14. 14. YARVINTRODUCTION YARV
  15. 15. Overview YARVINTRODUCTION OS Rubyコード YARV OS OS OS HW HW HW HW YARV YARV YARV C C C C ① RubyコードはYARV命令列のバイトコードにコ ンパイルされる ② 各環境に対応したYARVが、共通のYARV命令 列を解釈しCプログラムを生成して実行 •MRIはC言語実装なので、YARVを介してCの プログラムとして実行される •ネイティブコードに変換されるJVMなどとは この点で異なるが、仮想化の構造的には同じ
  16. 16. YARV命令列とは? YARVINTRODUCTION
  17. 17. def hello(name) "Hello " + name end puts hello("Tom") YARVINTRODUCTION このRubyコードをコンパイルすると…?
  18. 18. YARVINTRODUCTION == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>=============== 0000 trace 1 ( 1) 0002 putspecialobject 1 0004 putspecialobject 2 0006 putobject :hello 0008 putiseq hello 0010 opt_send_without_block <callinfo!mid:core#define_method, argc:3, ARGS_SIMPLE> 0012 pop 0013 trace 1 ( 5) 0015 putself 0016 putself 0017 putstring "Tom" 0019 opt_send_without_block <callinfo!mid:hello, argc:1, FCALL|ARGS_SIMPLE> 0021 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE> 0023 leave == disasm: <RubyVM::InstructionSequence:hello@<compiled>>=============== local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) [ 2] name<Arg> 0000 trace 8 ( 1) 0002 trace 1 ( 2) 0004 putstring "Hello " 0006 getlocal_OP__WC__0 2 0008 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE> 0010 trace 16 ( 3) 0012 leave ( 2) こんなYARV命令列になる
  19. 19. == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>=============== 0000 trace 1 ( 1) 0002 putspecialobject 1 0004 putspecialobject 2 0006 putobject :hello 0008 putiseq hello 0010 opt_send_without_block <callinfo!mid:core#define_method, argc:3, ARGS_SIMPLE> 0012 pop 0013 trace 1 ( 5) 0015 putself 0016 putself 0017 putstring "Tom" 0019 opt_send_without_block <callinfo!mid:hello, argc:1, FCALL|ARGS_SIMPLE> 0021 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE> 0023 leave == disasm: <RubyVM::InstructionSequence:hello@<compiled>>=============== local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) [ 2] name<Arg> 0000 trace 8 ( 1) 0002 trace 1 ( 2) 0004 putstring "Hello " 0006 getlocal_OP__WC__0 2 0008 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE> 0010 trace 16 ( 3) 0012 leave ( 2) ? YARVINTRODUCTION
  20. 20. YARVINTRODUCTION puts 2 + 3 字句解析 構文解析 The Long and Winding Road to YARV Instructions Rubyコード コンパイル YARV命令列
  21. 21. YARVINTRODUCTION 字句解析 Rubyコードを1文字ずつ読み込み解析する 10.times do |n| puts n end
  22. 22. YARVINTRODUCTION 字句解析 Rubyコードを1文字ずつ読み込み解析する 1 0 . t i m e s d o ¦ n ¦ 10.times do |n| puts n end
  23. 23. YARVINTRODUCTION 字句解析 Rubyコードを1文字ずつ読み込み解析する 1 0 . t i m e s d o ¦ n ¦ 10.times do |n| puts n end tINTEGER 10 . tIDENTIFIER times keyword_do ¦ tIDENTIFIER n ¦
  24. 24. YARVINTRODUCTION 字句解析 Rubyコードを1文字ずつ読み込み解析する 1 0 . t i m e s d o ¦ n ¦ 10.times do |n| puts n end tINTEGER 10 . tIDENTIFIER times keyword_do ¦ tIDENTIFIER n ¦ トークン列
  25. 25. YARVINTRODUCTION puts 2 + 3 字句解析 構文解析 The Long and Winding Road to YARV Instructions Rubyコード コンパイル YARV命令列 コードをトークン列に分解
  26. 26. YARVINTRODUCTION 構文解析 tINTEGER 10 . tIDENTIFIER times keyword_do ¦ tIDENTIFIER n ¦ method_call: ... | primary_value '.' operation2 | ... 文法規則にマッチ パーサが文法規則に基づいてトークン列の解析を行う
  27. 27. 省略… YARVINTRODUCTION 構文解析 program method
 add block call integer 10 period identifier times do block 構文解析によってAST (抽象構文木) が生成される
  28. 28. YARVINTRODUCTION 構文解析 Ripperを使うと実際にASTを確認できる require 'ripper' require 'pp' code = <<EOS 10.times do |n| puts n end EOS pp Ripper.sexp(code) [:program, [[:method_add_block, [:call, [:@int, "10", [1, 0]], :".", [:@ident, "times", [1, 3]]], [:do_block, [:block_var, [:params, [[:@ident, "n", [1, 13]]], nil, nil, nil, nil, nil, nil], false], [[:command, [:@ident, "puts", [2, 2]], [:args_add_block, [[:var_ref, [:@ident, "n", [2, 7]]]], false]]]]]]] S式!
  29. 29. YARVINTRODUCTION puts 2 + 3 字句解析 構文解析 The Long and Winding Road to YARV Instructions Rubyコード コンパイル YARV命令列 コードをトークン列に分解 トークン列からASTを生成
  30. 30. YARVINTRODUCTION YARV命令列へのコンパイル より単純なRubyコードを元に説明 puts 2 + 3 Rubyコード NODE_SCOPE NODE_FCALL method_id: puts NODE_CALL method_id: + NODE_LIT 2 NODE_LIT 3 レシーバ 引数 ASTノード
  31. 31. putself putobject 2 putobject 3 send <callinfo!mid:+, argc:1, … send <callinfo!mid:puts, argc:1, ... YARVINTRODUCTION YARV命令列へのコンパイル AST構造を りながら YARV命令列スタックにプッシュしていく NODE_FCALL method_id: puts NODE_CALL method_id: + YARV命令列 NODE_LIT 2 NODE_LIT 3
  32. 32. putself putobject 2 putobject 3 opt_plus opt_send_simple <callinfo!mid:puts, argc:1, ... YARVINTRODUCTION YARV命令列へのコンパイル YARV命令列は最適化される NODE_FCALL method_id: puts NODE_CALL method_id: + YARV命令列 NODE_LIT 2 NODE_LIT 3 更に最適化を行い、 最適化した命令に置き換える
  33. 33. YARVINTRODUCTION puts 2 + 3 字句解析 構文解析 The Long and Winding Road to YARV Instructions Rubyコード コンパイル YARV命令列 コードをトークン列に分解 トークン列からASTを生成 ASTから最適化された YARV命令列 (バイトコード) を生成
  34. 34. YARVINTRODUCTION YARVが命令に従いCプログラムを実行 このようにしてRubyプログラムは実行される $ cat example.rb puts 2 + 3 $ ruby example.rb 5 字句解析、 構文解析、 YARV命令列へのコンパイル、 Cプログラムの実行
  35. 35. YARVINTRODUCTION まとめ Rubyのしくみを知ると RubyKaigiをもっと楽しめる!
  36. 36. YARVINTRODUCTION 参考 ★ YARV Maniacs • http://magazine.rubyist.net/?0006-YarvManiacs ★ Rubyのしくみ Ruby Under a Microscope • https://estore.ohmsha.co.jp/titles/978427405065P 以下の記事や書籍を思いっきり参考にしました
  37. 37. よちよち.rb 回オメデトウ

×