2007-12-30
Ruby 1.9.0のバイトコードをいじり倒す(その6)
|いろいろなところで、Ruby 1.8.xと1.9.0の非互換性が話題になっていますが、バイトコードをいじくってちょっと乗り越えてみようという*冗談*です。
今回まな板にあげる非互換性は、ブロックローカル変数です。
たとえば、
a = 12 0.upto(1) do |n| a = a + 20 end p a
といったプログラムは、ruby 1.8.6と1.9.0でこのように異なりますが、
d:\work\ruby>c:/cygwin/usr/local/bin/ruby -v c:/cygwin/usr/local/bin/ruby -v ruby 1.9.0 (2007-12-28 revision 0) [i386-cygwin] d:\work\ruby>c:/cygwin/usr/local/bin/ruby sample.rb c:/cygwin/usr/local/bin/ruby sample.rb 12 d:\work\ruby>ruby -v ruby -v ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-cygwin] d:\work\ruby>ruby sample.rb ruby sample.rb 21
local.rbを咬ませて、バイトコードにパッチを当てると、1.8.6と同じ挙動を示します。
d:\work\ruby>c:/cygwin/usr/local/bin/ruby local.rb sample.rb c:/cygwin/usr/local/bin/ruby local.rb sample.rb 21
種を明かすと、こんな感じのコードのパッチを当てています。
- ブロックの終わりに$__ブロック変数名というグローバル変数にブロック変数の値を代入する
- そのブロックを呼び出したsendの後に、1で代入したグローバル変数を再び、同名のブロック変数かローカル変数に代入しなおす
こんな感じで、非互換性が解決できるんじゃないでしょうか・・・、なんて嘘です。そんなに甘くないですね。
とりあえず、このプログラムはこの場合は動きます。
local.rbです。
require 'instruction' require 'pp' include VMLib iseq = VM::InstructionSequence.compile_file(ARGV[0]) iseqt = InstSeqTree.new(nil, iseq) iseqt.add_code_all_before_return {|fname, info, no, code| lambda {|level| res = [] if code.header['type'] == :block then code.header['locals'].each_with_index do |nm, i| res.push [:getdynamic, i + 1, 0] res.push [:setglobal, ":$___#{nm}".intern] end end res } } iseqt.add_code_all_around_send {|fname, info, no, code| lambda {|mname, sendno, inst| bl = code.blockes[sendno] res = [inst] if bl then cv = code.header['locals'] if code.header['type'] == :block then bl.header['locals'].each do |lv| if cv.include?(lv) then res.push [:getglobal, ":$___#{lv}".intern] res.push [:setdynamic, cv.index(lv) + 1, 0] end end else bl.header['locals'].each do |lv| if cv.include?(lv) then res.push [:getglobal, ":$___#{lv}".intern] res.push [:setlocal, cv.index(lv) + 2] end end end end res } } VM::InstructionSequence.load(iseqt.to_a).eval
instruction.rbはこの前載せたものよりずいぶんでっかくなっています(340行くらい)。ちょっと載せるのに躊躇してますので、もし試してみたいという奇特な人がいたらコメントください。
- 5 http://d.hatena.ne.jp/keyworddiary/Scheme
- 2 http://d.hatena.ne.jp/keyworddiary/Ruby
- 2 http://reader.livedoor.com/reader/
- 1 http://d.hatena.ne.jp/keyword/最適化
- 1 http://d.hatena.ne.jp/keyword/Ruby
- 1 http://d.hatena.ne.jp/keyword/Scheme
- 1 http://d.hatena.ne.jp/keyword/YARV
- 1 http://d.hatena.ne.jp/negation/edit?date=20071231
- 1 http://d.hatena.ne.jp/shimobayashi/20071230
- 1 http://i-know.jp/deriwosk/