1 / 13

第 12 回 RHG の逆襲

第 12 回 RHG の逆襲. 2009/3/14 澤田 淳二. 今日のテーマ. ブロック周りの実装 メソッドへのブロックの渡し方 yield 時の処理 変数アクセス next, redo, break. サンプルソース. (1) C でのブロック呼び出し. (2) Ruby でのブロック呼び出し. def foo yield(1) yield(2) yield(3) yield(4) yield(5) end x = 1 foo {|i| next if i == 2 break if i == 3

Download Presentation

第 12 回 RHG の逆襲

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第12回 RHGの逆襲 2009/3/14 澤田 淳二

  2. 今日のテーマ • ブロック周りの実装 • メソッドへのブロックの渡し方 • yield時の処理 • 変数アクセス • next, redo, break

  3. サンプルソース (1) Cでのブロック呼び出し (2) Rubyでのブロック呼び出し def foo yield(1) yield(2) yield(3) yield(4) yield(5) end x = 1 foo {|i| next if i == 2 break if i == 3 redo if i == 6 p [x, i] } x = 1 (1..5).each do |i| (1..5).each do |j| next if i == 2 break if i == 3 redo if i == 6 p [x, i, j] end end ローカル変数 外のブロック変数 自分のブロック変数

  4. YARVコードへの変換結果 でYARVコードが出力されます ruby --dump=insn スクリプト

  5. rubyのトレース実行 • Emacsの場合 • makeするとき最適化フラグは切っておくとよい • M-x gdbでgdb起動 • set argsでコマンドライン • breakでブレークポイント(ファイル:行数 or 関数) • runで実行開始 • stepで1行実行(関数に入る) • nextでも1行実行(関数には入らない) • finishで関数抜けだし • btでバックトレース

  6. メソッドへのブロックの渡し方(1) • コンパイル時 • iseq_compile_each()のNODE_ITERおよびNODE_CALL参照 • NODE_ITER • ブロックのNODEツリーをコンパイルし compile_data->current_blockに設定 • NODE_CALL • send命令の引数としてcurrent_blockを設定

  7. メソッドへのブロックの渡し方(2) • 実行時 • ブロックの準備:caller_setup_args() • ブロックのrb_iseq_tをセットした rb_block_tを準備 • cfpの一部をrb_block_t用の領域として使用 • メソッドの呼び出し:vm_push_frame() • rb_block_tをspecvalに設定

  8. 図解 スタックは の向きに伸びる VALUEスタック rb_control_frame_t rb_block_t lfp specval ブロックの rb_iseq_t iseq 実行中のcfp 1つ前のcfp cfpスタック

  9. yield時の処理 • specvalからrb_block_t取り出し • cfpをpush • 1つ前のcfpのlfp(rb_block_t.lfp)をlfpに設定 • 1つ前のcfpのdfpをspecvalに設定

  10. 図解 サンプルソース(1)で中のブロック実行時のスタック状態 スタックは の向きに伸びる dfp specval(1つ前のdfp) j specval(rv_block_t) specval(1つ前のdfp) dfp i specval(rb_block_t) lfp 中のブロックのcfp specval lfp x 中のeachのcfp 外のブロックのcfp lfp, dfp 外のeachのcfp <main>のcfp

  11. 変数アクセス • dfpを利用して変数の位置を特定 • 自ブロックの外にある変数もdfpをたどることでアクセス可能(たどるレベルはコンパイル時にわかる)

  12. next, redo • next • 処理:次のループに進む • コンパイル結果:leave • redo • 処理:ブロック実行をやり直す • コンパイル結果:jump 0 ちなみに、retryは使えなくなりました

  13. break • 処理:ループ(yieldしたメソッド)を終了する • コンパイル結果:throw 2 • break時の1つ前のdfpとマッチするcfp(メソッドを呼び出したcfp)を検索 • マッチしたcfpのpcから実行を再開 • ブロック呼び出しがC関数の場合、JUMP_TAGを利用してCのコールスタックを巻き戻し

More Related