compile/disassemble

なんとなくコードの compile と disassemble についてメモ。
Python では compile と dis module を使えば良い。

>>> code = compile("print 1+2", "<string>", "exec")
>>> eval(code)
3
>>> import dis
>>> dis.dis(code)
  1           0 LOAD_CONST               3 (3)
              3 PRINT_ITEM
              4 PRINT_NEWLINE
              5 LOAD_CONST               2 (None)
              8 RETURN_VALUE

compile されたコードだけでなく、method や module も disassemble してくれる。
Ruby 1.9 の場合は VM::InstructionSequence.compile_を使って compile する。compile 結果のオブジェクトに eval メソッドや disasm メソッドがある。

irb(main):001:0> code = VM::InstructionSequence.compile("puts 1+2")
=> <ISeq:<compiled>@<compiled>>
irb(main):002:0> code.eval
3
=> nil
irb(main):003:0> puts code.disasm
== disasm: <ISeq:<compiled>@<compiled>>=================================
0000 putnil                                                           (   1)
0001 putobject        1
0003 putobject        2
0005 opt_plus
0006 send             :puts, 1, nil, 8, <ic>
0012 leave
=> nil

ちなみに VM::InstructionSequence.compile_option= でデフォルトのコンパイルオプションが変更できる。

irb(main):001:0> puts VM::InstructionSequence.compile("def f; f; end").disasm
== disasm: <ISeq:<compiled>@<compiled>>=================================
0000 putnil                                                           (   1)
0001 definemethod     :f, f, 0
0005 putnil
0006 leave
== disasm: <ISeq:f@<compiled>>==========================================
0000 putnil                                                           (   1)
0001 send             :f, 0, nil, 24, <ic>
0007 leave
=> nil
irb(main):002:0> VM::InstructionSequence.compile_option = { :tailcall_optimization => true }
=> {:tailcall_optimization=>true}
irb(main):003:0> puts VM::InstructionSequence.compile("def f; f; end").disasm
== disasm: <ISeq:<compiled>@<compiled>>=================================
0000 putnil                                                           (   1)
0001 definemethod     :f, f, 0
0005 putnil
0006 leave
== disasm: <ISeq:f@<compiled>>==========================================
0000 putnil                                                           (   1)
0001 send             :f, 0, nil, 56, <ic>
0007 leave
=> nil

VM::InstructionSequence.compile の第4引数に最適化オプションを指定することもできる(第2引数はファイル名、第3引数は開始行番号)。

irb(main):002:0> puts VM::InstructionSequence.compile("def f; f; end", "<compiled>", 1, { :tailcall_optimization => true }).disasm
== disasm: <ISeq:<compiled>@<compiled>>=================================
0000 putnil                                                           (   1)
0001 definemethod     :f, f, 0
0005 putnil
0006 leave
== disasm: <ISeq:f@<compiled>>==========================================
0000 putnil                                                           (   1)
0001 send             :f, 0, nil, 56, <ic>
0007 leave
=> nil

現在してできるコンパイルオプションは以下。

  • inline_const_cache
  • peephole_optimization
  • tailcall_optimization
  • specialized_instruction
  • operands_unification
  • instructions_unification
  • stack_caching
  • trace_instruction

まぁ、VM::InstructionSequence は1.9.1で消えるという話なんだけどな。まぁ、今日時点でまだ trunk に残っているけど。