ひとり勉強会

ひとり楽しく勉強会

YARVソースコード勉強会 (14)

お久しぶりです。週一の勉強会だったはずなのにお久しぶりです。

[YARV] insnhelper.h


insns.defYARVVMVM insnhelper.h 
#define REG_CFP (reg_cfp)
#define REG_PC  (REG_CFP->pc)
#define REG_SP  (REG_CFP->sp)
#define REG_LFP (REG_CFP->lfp)
#define REG_DFP (REG_CFP->dfp)


#define GET_SP()   (USAGE_ANALYSIS_REGISTER_HELPER(1, 0, REG_SP))
#define SET_SP(x)  (REG_SP  = (USAGE_ANALYSIS_REGISTER_HELPER(1, 1, (x))))

#define GET_LFP()  (USAGE_ANALYSIS_REGISTER_HELPER(3, 0, REG_LFP))
#define SET_LFP(x) (REG_LFP = (USAGE_ANALYSIS_REGISTER_HELPER(3, 1, (x))))

#define GET_DFP()  (USAGE_ANALYSIS_REGISTER_HELPER(4, 0, REG_DFP))
#define SET_DFP(x) (REG_DFP = (USAGE_ANALYSIS_REGISTER_HELPER(4, 1, (x))))

setter/getterUSAGE_ANALYSIS_REGISTER_HELPERYARV使3
#define GET_PC()           (USAGE_ANALYSIS_REGISTER_HELPER(0, 0, REG_PC))
#define SET_PC(x)          (REG_PC = (USAGE_ANALYSIS_REGISTER_HELPER(0, 1, x)))

#define JUMP(dst)          (REG_PC += (dst))

PC

insns.def


insns.def


 (getlocal, ...)

 (putnil, ...)

 (pop, dup, ...)

 (definemethod, alias, ...)

/ (defineclass, ...)

/ (send, invokeblock, ...)

 (throw, ...)

 (jump, branchif, ...)

 (opt_plus, opt_mult, ...)



11

おまけ: Scheme on YARV


YARV

 


 Scheme 
 


yasm.rb

記事で紹介されているyasmモジュールがRubyのtrunkに見つからなかったので、旧YARVのレポジトリ

から拾ってきて適当に修正して使っています。変えたのは、YARV仮想マシンオブジェクトを表すクラス名と

- module YARVCore
+ class VM

- YARVCore::
+ VM::

メソッド名としてSymbolを渡すと怒られるみたいだったのでStringにしたところと

      def initialize type, name, filename, args, vars, lopt, parent
        @type = type
-       @name = name
+       @name = name.to_s
        @filename = filename

関数形式のメソッド呼び出しを表すフラグが1<<2から1<<3になっているようなのでその反映

      def call id, argc, block = nil
-       @body << [:send, id, argc, block, 0x04, nil]
+       @body << [:send, id, argc, block, 0x08, nil]
      end

の3カ所です。

目標


SchemeLispYARV
p scheme("(+ (* 2 3) 4)")   # ==>10



require 'yasm'

def scheme(text)
  # とっても手抜きなS式パーザ
  # "(+ (* 2 3) 4)"  ==>  [:+, [:*, 2, 3], 4]
  s = eval text.gsub( /(\()|(\))|(\d+)|([^()\s]+)/ ) {
    case
      when $1 then "["
      when $2 then $'[/\S/] ? "]," : "]"
      when $3 then "#$3,"
      else         ":#$4,"
    end
  }

  # コンパイル
  iseq = YASM.toplevel {
    scm_compile s
    leave
  }

  # 実行
  iseq.eval
end

SchemeSymbolscm_compileYARVscm_compile

scm_compile : 四則演算


YASM::SimpleDataBuilder
class YASM::SimpleDataBuilder
  def scm_compile(s)
    caseswhen Array
        op,*arg = s
        caseopwhen :+
            scm_compile arg[0]
            arg[1..-1].each{|a| scm_compile a; send :+,1}
          when :-
            scm_compile arg[0]
            arg[1..-1].each{|a| scm_compile a; send :-,1}
          when :*
            scm_compile arg[0]
            arg[1..-1].each{|a| scm_compile a; send :*,1}
          when :/
            scm_compile arg[0]
            arg[1..-1].each{|a| scm_compile a; send :/,1}
        end
      else
        putobject s
    end
  end
end

s (+ 1 2 3 4) S
putobject 1
putobject 2
send :+, 1
putobject 3
send :+, 1
putobject 4
send :+, 1

sputobject
p scheme("(+ (* 2 3) 4)")   # ==>10


scm_compile : 関数定義



(define (norm x y)
   (+ (* x x) (* y y)))

normYARVdefinemethod
          when :define
            mname, *mparam = arg[0]
            putnil
            definemethod mname, YASM.method(mname, mparam) {
              scm_compile arg[1]
              leave
            }
            putnil

putnilputnildefinenilnil
S
    caseswhen Array
        ...
      when Symbol
        getlocal s
      else
        ...
    end

Ruby
scheme <<EOS
  (define (norm x y)
     (+ (* x x) (* y y)))
EOS

p norm(3,4)  # ==> 25

scm_compile : 関数呼び出し


Scheme
          when :+
            ...
          when :-
            ...
          when :*
            ...
          when :/
            ...
          when :define
            ...
          else
            putnil
            arg.each{|a| scm_compile a}
            call op, arg.size

selfnilyasmcall
p scheme("(/ (norm 5 12) 13)")  # ==>13


def cube(x)
  x * x * x
end

p scheme("(cube 11)")   # ==> 1331

RubyScheme

scm_compile: 条件分岐

(if 条件 then部 else部)

ifRubyif
          when :if
            scm_compile arg[0]
            branchunless :else_part
            scm_compile arg[1]
            jump :end
          _ :else_part
            scm_compile arg[2]
          _ :end


          when :==
            scm_compile arg[0]; scm_compile arg[1]; send :==, 1
          when :<
            scm_compile arg[0]; scm_compile arg[1]; send :<, 1
          when :>
            scm_compile arg[0]; scm_compile arg[1]; send :>, 1
          when :<=
            scm_compile arg[0]; scm_compile arg[1]; send :<=, 1
          when :>=
            scm_compile arg[0]; scm_compile arg[1]; send :>=, 1


scheme <<EOS
  (define (fib x)
     (if (<= x 1)
1
         (+ (fib (- x 2)) (fib (- x 1)))))
EOS

p scheme("(fib 10)")    # ==>89


scheme <<EOS
  (define (facs x)
     (if (== x 0) 1 (* x (facr (- x 1)))))
EOS
def facr(x)
  if x == 0 then 1 else x * facs(x-1) end
end

p facs(10), facr(10)   # 3628800 \n 3628800

RubyScheme

scm_compile: 速度比較


Ruby
def fibr(x)
  if x <= 1
    1
  else
    fibr(x-2) + fibr(x-1)
  end
end

require 'benchmark'
3.times {
  print "Scheme:", Benchmark.measure { fib(36)  }
  print "Ruby:  ", Benchmark.measure { fibr(36) }
}


Scheme:  8.942000   0.000000   8.942000 (  8.973000)
Ruby:    8.853000   0.000000   8.853000 (  8.863000)
Scheme:  8.863000   0.000000   8.863000 (  8.863000)
Ruby:    8.873000   0.000000   8.873000 (  8.872000)
Scheme:  8.852000   0.000000   8.852000 (  8.853000)
Ruby:    8.863000   0.000000   8.863000 (  8.863000)

Ruby

まとめ


YARV





yasm.rb (yasmdata.rb  YARV  =~ s/module YARVCore/class VM/)

scheme.rb




11/17 http://d.hatena.ne.jp/shinichiro_h/20071113#1194884481 shinichiro.h

10/23 orz

3/23 12:53