LoginSignup
5
5

More than 5 years have passed since last update.

Ruby スクリプトの内部表現をチラ見する(書きかけ)

Last updated at Posted at 2015-11-15

前説

この記事は

Ruby スクリプトが CRuby(MRI) でどう変換されてどう実行されるのか、興味があって見てみたいと思って調べた結果についての記事、になるはずだったものです。
書きかけで投げ出してしまっているので、そういうのが嫌な人にはおすすめしません。

要するに

--dump に感動したのでみんな使おうぜ、あと使っててわかったことがあったら共有しようぜ、という、それだけです。あと、わかりにくい出力が一部あったので、そこについて説明しています。

CRuby のオプション --dump=XXX

とは

CRuby には、--dump=XXX というとても素敵なオプションを渡すことができます。
これを指定すると、Ruby スクリプトは実行されず、そのコードが ruby の内部でどのような形で表現されるのかを知ることができます。

XXX に入るもの

XXX の部分は本当に XXX と書くわけではなく、以下の 2 つのいずれかを渡すことができます。

  • insns
    • ruby の VM (YARV とか呼ばれている(いた?)あいつです) の命令列を見ることができます
  • parsetree
    • 上の VM 命令列にコンパイルされるより前の段階の、「ノード」と言われる中間表現をみることができます

動作例

スクリプトの用意

動作を確認するために、スクリプトを用意します。
とりあえず簡単に、a,b = nil でいってみたいと思います。
(なぜ a = nil でないかというと、多重代入の動きが見たかったからです)

まずはプレーン

最初に、--dump なしで動かしてみました。

$ ruby -e 'a, b = nil'
$

pputs もしていないので何も出力されずに少し寂しいですが、想定通りです。

insns

次に、VM の命令列 insns です。

$ ruby --dump=insns -e 'a, b = nil'
== disasm: <RubyVM::InstructionSequence:<main>@-e>======================
local table (size: 3, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 3] a          [ 2] b          
0000 trace            1                                               (   1)
0002 putnil           
0003 dup              
0004 expandarray      2, 0
0007 setlocal_OP__WC__0 3
0009 setlocal_OP__WC__0 2
0011 leave            
$

なんだかいっぱい出ています。

ab の 2 つのローカル変数が定義されていて、内部的には a を 3 番、b を 2 番と呼んでる、っぽいような、そんなことが 3 行目から読み取れる、ような気がします。

へー、タイプ 1 で trace するんだー、スタックに nil をおいて dup してから expandarray したものでそれぞれ setlocal するんだー 3 番(ローカル変数 a)と 2 番(ローカル変数 b)にねー、ふーん、などと読んでいきます。

何言っているかわからないと思います。書いてる本人もわかりません。

補足

とりあえずここでは大まかなイメージだけわかればいいと思います。
これより深いところは VM の動作の領域であって今回の「内部表現をチラ見する」という趣旨とは外れるので割愛します。

本当は

わかってないので説明できないだけです。すみません。
詳しい人の詳しい話を見たり聞いたりしてください。

parsetree

次に、ノード表現 parsetree です。

$ ruby --dump=parsetree -e 'a, b = nil'
###########################################################
## Do NOT use this node dump for any purpose other than  ##
## debug and research.  Compatibility is not guaranteed. ##
###########################################################

# @ NODE_SCOPE (line: 1)
# +- nd_tbl: :a,:b
# +- nd_args:
# |   (null node)
# +- nd_body:
#     @ NODE_MASGN (line: 1)
#     +- nd_value:
#     |   @ NODE_NIL (line: 1)
#     +- nd_head:
#     |   @ NODE_ARRAY (line: 1)
#     |   +- nd_alen: 2
#     |   +- nd_head:
#     |   |   @ NODE_DASGN_CURR (line: 1)
#     |   |   +- nd_vid: :a
#     |   |   +- nd_value:
#     |   |       (null node)
#     |   +- nd_next:
#     |       @ NODE_ARRAY (line: 1)
#     |       +- nd_alen: 140562125983720
#     |       +- nd_head:
#     |       |   @ NODE_DASGN_CURR (line: 1)
#     |       |   +- nd_vid: :b
#     |       |   +- nd_value:
#     |       |       (null node)
#     |       +- nd_next:
#     |           (null node)
#     +- nd_args:
#         (null node)
$

はじめに注意書きが出力されます。互換性とか保証されないからデバッグと調査にしか使うなよーとのこと。

やはり最初に、ab の 2 つのローカル変数があるということを言っている、ような気がします。

ははあ MASGN というのは multi assign、多重代入のことかな、nd_value には 右辺が、nd_head には左辺が入っているっぽいな、などと読んでいきます。

不審な数字

下の方の行に、nd_alen: 140562125983720 という、なんだかよくわからないものが出力されています。なんでしょうか。

といったところで

実はこの値は nd_alen じゃなくて nd_end なんだよー同じ NODE_ARRAY でも u2 の使い方が二通りあるんだよーという話を、どう書くのがいいかわからなくなってきました。ぶっちゃけ面倒になってきて投げ出しました。

ただ、別にバグではないんだよということと、--dump が便利だということは言いたかったので、もうこの状態で公開してしまいます。

詳しく知りたい人はソース読んだり詳しい人に聞いてみてください。
詳しい人はどこかで解説してくれたりすると嬉しいです。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5