Hatena::ブログ(Diary)

miura1729の日記 このページをアンテナに追加 RSSフィード

2008-11-22

llvmrubyでRubyを拡張する

23:09 |  llvmrubyでRubyを拡張するを含むブックマーク  llvmrubyでRubyを拡張するのブックマークコメント

yarv2llvmはコンパイルするプログラム文字列で与えています。これは、Rubyバイトコード列を得るAPIがRubyVM::InstructionSequence.compileとcompile_fileしかなくどちらもRubyプログラム文字列で与えるためです。コンパイルするプログラム文字列で与えるという仕様は、かなり煩雑です。Emacsでエディットしてもインデントも手動になるし、色も付きません。既存のRubyのメソッドのバイトコード列が得られれば、普通にメソッドを定義しておいて、jit_compile(:foo)とかやってコンパイルさせるって感じのスマートなインターフェースが実現できます。

既存のメソッドのバイトコード列を得るには拡張ライブラリを使う必要がありました。拡張ライブラリを使うと、インストールスクリプトを書くのが面倒になるので避けていました。ところが、今日llvmrubyを使うと、Rubyだけで実現できるんじゃないかなと思い試してみたら、何とかできました。

バイトコード列を得るプログラムを作っていてllvmrubyの可能性を思い知りました。llvmはC以上のことができるので手間さえ掛ければRubyをすべてllvmrubyで置き換えることが可能です。そこまで行かなくてもRubyに関するあらゆる拡張がRuby自身でできることになります。ちょうどLispマシンの中ではすべてのことがLispでできるということと似ているなと思いました。ただ、Lispマシン場合に比べてプログラミングがあまりにも煩雑ですが。

もっとllvmrubyのプログラミングが楽になるようなライブラリの整備が必要だなとも思いました。

#
# dynamic_iseq.rb - Get iseq of method dynamically with LLVM
#
require 'llvm'

module VMLib
  class DynamicInstSeq
    include LLVM
    include RubyInternals

    NODE = Type.struct([Type::Int32Ty, P_CHAR, VALUE, VALUE, VALUE])
    P_NODE = Type.pointer(NODE)
    
    def initialize
      @module = LLVM::Module.new('dynamic_iseq')
      ExecutionEngine.get(@module)

      # Using Ruby API
      ftype = Type.function(P_NODE, [VALUE])
      mbody = @module.external_function('rb_method_body', ftype)

      # entry point
      ftype = Type.function(VALUE, [VALUE])
      @iseq_of = @module.get_or_insert_function('iseq_of', ftype)
      
      # method body
      b = @iseq_of.create_block.builder
      mt = @iseq_of.arguments[0]
      node = b.call(mbody, mt)
      body0 = b.struct_gep(node, 3)
      body1 = b.bit_cast(body0, Type.pointer(P_NODE))
      body = b.load(body1)
      b.return(body)
    end

    def iseq_of(met)
      ExecutionEngine.run_function(@iseq_of, met)
    end
  end
end


if __FILE__ == $0 then
  def fact(x)
    if x == 1 then
      1
    else
      fact(x - 1) * x
    end
  end
  
  a = VMLib::DynamicInstSeq.new
  p a.iseq_of(method(:fact)).to_a
end

ささだささだ 2008/11/23 12:41 ISeq#to_a じゃダメでしょうか.

miura1729miura1729 2008/11/23 15:27 ISeqはRubyVM::InstructionSequenceのことでしょうか?
色々調べてみたのですが、Rubyのレベルで既存のメソッドのiseqオブジェクトを得る方法がわかりませんでした。

ささだささだ 2008/11/24 03:02 ああ,そういうことか.なるほど.確かに,今は無いかも.もう feature freeze してしまったので,1.9.2 以降で対応するかもしれません.

miura1729miura1729 2008/11/24 06:53 おお!、ぜひお願いします。

トラックバック - http://d.hatena.ne.jp/miura1729/20081122/1227362968