Ruby 1.9.0のバイトコードをいじり倒す(その3)

では、このVMLib::InstSeqTreeを使って、トレースを実現したいと思います。各ブロックの始まりと終わりにprintメソッドの呼び出しを追加して、ファイル名と行番号を入れるようにします。

require 'instruction'
require 'pp'

include VMLib
iseq = VM::InstructionSequence.compile_file(ARGV[0])
iseqt = InstSeqTree.new(iseq)

iseqt.add_code_before_block {|fname, info, no|
  [
    [:putnil], 
    [:putobject, "enter #{fname}:#{no}\n"], 
    [:send, :print, 1, nil, 8, nil], 
    [:pop]
  ]
}

iseqt.add_code_after_block {|fname, info, no|
  [
    [:putnil], 
    [:putobject, "leave #{fname}:#{no}\n"], 
    [:send, :print, 1, nil, 8, nil], 
    [:pop]
  ]
}

VM::InstructionSequence.load(iseqt.to_a).eval

これに、こんな感じの階乗を求めるプログラムを食わせると

def fact(n)
  p n
  if n == 0 then
    1
  else
    n * fact(n - 1)
  end
end

print fact(5)

こんな感じの出力になります。

c:\cygwin\usr\local\bin\ruby trace2.rb fact.rb
enter fact.rb:1
enter fact.rb:2
5
enter fact.rb:2
4
enter fact.rb:2
3
enter fact.rb:2
2
enter fact.rb:2
1
enter fact.rb:2
0
leave fact.rb:6
leave fact.rb:6
leave fact.rb:6
leave fact.rb:6
leave fact.rb:6
leave fact.rb:6
120leave fact.rb:10

つづく