bytecode of YARV, Rubinius and JRuby
這應該是目前三大 Ruby VM 吧,其他勉強能提的大概是 IronRuby,
不過完成度好像還低於其他三者不少,先略過不提。要搞 mono 也比較麻煩。
暫時沒找到 JRuby 比較輕便的 compile 法,好像是 JRuby.compile 會產生
JRuby::CompiledScript, 一個完整可以執行的 script, 而 YARV 只是單純
產生 RubyVM::InstructionSequence, 而 Rubinius 則是 CompiledMethod,
介於 JRuby 與 YARV 之間吧。
短評:
YARV:
1. 用 instruction sequence 來 compile 有一點奇怪
2. 閱讀起來滿清楚的
Rubinius:
1. 用法最有彈性,可取得的資訊最多
2. 有點失望 constants 不是放在 Rubinius 下,如 JRuby 或 YARV
JRuby:
1. 用起來最清楚的一個,命名乾淨,沒試幾次就有結果了
2. bytecode 也未免 verbose 過頭了些......
接下來就是希望可以 decompile, 像是 Ruby2Ruby 的 to_ruby 那樣。
不過這個就不抱太大的期望了,畢竟如果能簡單的轉換,那 compile 就失去意義了。
godfat ~> irb1.9 -r pp
irb(main):001:0> pp RubyVM::InstructionSequence.compile('1 + 2').to_a
["YARVInstructionSequence/SimpleDataFormat",
1,
1,
1,
{:arg_size=>0, :local_size=>1, :stack_max=>2},
"",
"",
:top,
[],
0,
[],
[1, [:trace, 1], [:putobject, 1], [:putobject, 2], [:opt_plus], [:leave]]]
或是:
irb(main):002:0> puts RubyVM::InstructionSequence.compile('1 + 2').disassemble
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace 1 ( 1)
0002 putobject 1
0004 putobject 2
0006 opt_plus
0007 leave
Rubinius:
godfat ~/p/g/rubinius> bin/rbx
irb(main):001:0> Compiler.compile_string('1 + 2', binding.context).iseq.decode
=> [[:meta_push_1], [:meta_push_2], [:meta_send_op_plus], [:ret]]
或是:
irb(main):002:0> Compiler.compile_string('1 + 2', binding.context).iseq.opcodes
=> #<Tuple: 72, 73, 74, 12>
或是:
irb(main):003:0> require 'pp'
=> true
irb(main):004:0> pp Compiler.compile_string('1 + 2', binding.context).decode
[#<CompiledMethod::Instruction:0x110 @ip=0 @args=[] @stack_consumed=[0, true] @op=#<InstructionSet::OpCode:0xc2 @opcode_info={:opcode=>:meta_push_1, :bytecode=>72, :args=>[], :stack=>[0, 1]}> @line=1 @stack_produced=[1, true] @comment=nil>,
#<CompiledMethod::Instruction:0x118 @ip=1 @args=[] @stack_consumed=[0, true] @op=#<InstructionSet::OpCode:0xd2 @opcode_info={:opcode=>:meta_push_2, :bytecode=>73, :args=>[], :stack=>[0, 1]}> @line=1 @stack_produced=[1, true] @comment=nil>,
#<CompiledMethod::Instruction:0x120 @ip=2 @args=[] @stack_consumed=[2, true] @op=#<InstructionSet::OpCode:0xe2 @opcode_info={:opcode=>:meta_send_op_plus, :vm_flags=>[:check_interrupts], :bytecode=>74, :flow=>:send, :args=>[], :stack=>[2, 1]}> @line=1 @stack_produced=[1, true] @comment=nil>,
#<CompiledMethod::Instruction:0x128 @ip=3 @args=[] @stack_consumed=[0, true] @op=#<InstructionSet::OpCode:0xf4 @opcode_info={:opcode=>:ret, :vm_flags=>[:terminator], :bytecode=>12, :flow=>:return, :args=>[], :stack=>[0, 0]}> @line=1 @stack_produced=[0, true] @comment=nil>]
JRuby:
godfat ~> jirb
irb(main):001:0> puts JRuby.compile('1 + 2').inspect_bytecode
// class version 49.0 (49)
// access flags 33
public class _dash_ extends org/jruby/ast/executable/AbstractScript {
// access flags 18
private final Ljava/lang/Class; $class
// access flags 1
public()V
ALOAD 0
INVOKESPECIAL org/jruby/ast/executable/AbstractScript.()V
ALOAD 0
LDC "_dash_"
INVOKESTATIC java/lang/Class.forName (Ljava/lang/String;)Ljava/lang/Class;
PUTFIELD _dash_.$class : Ljava/lang/Class;
ALOAD 0
LDC "+"
INVOKESTATIC org/jruby/runtime/MethodIndex.getCallSite (Ljava/lang/String;)Lorg/jruby/runtime/CallSite;
PUTFIELD _dash_.site0 : Lorg/jruby/runtime/CallSite;
RETURN
MAXSTACK = 2
MAXLOCALS = 1
// access flags 9
public static()V
RETURN
MAXSTACK = 0
MAXLOCALS = 0
// access flags 1
public __file__(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject;
ALOAD 1
INVOKEVIRTUAL org/jruby/runtime/ThreadContext.getRuntime ()Lorg/jruby/Ruby;
DUP
ASTORE 5
INVOKEVIRTUAL org/jruby/Ruby.getNil ()Lorg/jruby/runtime/builtin/IRubyObject;
ASTORE 7
NOP
ALOAD 1
ICONST_0
INVOKESTATIC _dash_.setPosition (Lorg/jruby/runtime/ThreadContext;I)V
ALOAD 0
GETFIELD _dash_.site0 : Lorg/jruby/runtime/CallSite;
ALOAD 1
ALOAD 0
ALOAD 5
LDC 1
INVOKEVIRTUAL _dash_.getFixnum0 (Lorg/jruby/Ruby;J)Lorg/jruby/RubyFixnum;
ALOAD 0
ALOAD 5
LDC 2
INVOKEVIRTUAL _dash_.getFixnum1 (Lorg/jruby/Ruby;J)Lorg/jruby/RubyFixnum;
INVOKEVIRTUAL org/jruby/runtime/CallSite.call (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;
ARETURN
MAXSTACK = 7
MAXLOCALS = 8
// access flags 1
public __file__(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject;
ALOAD 1
INVOKEVIRTUAL org/jruby/runtime/ThreadContext.getRuntime ()Lorg/jruby/Ruby;
ALOAD 3
ICONST_0
ICONST_0
INVOKESTATIC org/jruby/runtime/Arity.checkArgumentCount (Lorg/jruby/Ruby;[Lorg/jruby/runtime/builtin/IRubyObject;II)I
POP
ALOAD 0
ALOAD 1
ALOAD 2
ALOAD 4
INVOKEVIRTUAL _dash_.__file__ (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject;
ARETURN
MAXSTACK = 4
MAXLOCALS = 5
// access flags 1
public load(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject;
TRYCATCHBLOCK L0 L1 L1 null
L0
FRAME FULL [] []
ALOAD 1
ICONST_0
ANEWARRAY java/lang/String
INVOKESTATIC org/jruby/javasupport/util/RuntimeHelpers.preLoad (Lorg/jruby/runtime/ThreadContext;[Ljava/lang/String;)V
ALOAD 0
ALOAD 1
ALOAD 2
ALOAD 3
ALOAD 4
INVOKEVIRTUAL _dash_.__file__ (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject;
ALOAD 1
INVOKESTATIC org/jruby/javasupport/util/RuntimeHelpers.postLoad (Lorg/jruby/runtime/ThreadContext;)V
ARETURN
L1
FRAME FULL [_dash_ org/jruby/runtime/ThreadContext org/jruby/runtime/builtin/IRubyObject [Lorg/jruby/runtime/builtin/IRubyObject; org/jruby/runtime/Block] [java/lang/Throwable]
ALOAD 1
INVOKESTATIC org/jruby/javasupport/util/RuntimeHelpers.postLoad (Lorg/jruby/runtime/ThreadContext;)V
ATHROW
MAXSTACK = 5
MAXLOCALS = 5
// access flags 9
public static main([Ljava/lang/String;)V
NEW _dash_
DUP
INVOKESPECIAL _dash_.()V
NEW org/jruby/RubyInstanceConfig
DUP
INVOKESPECIAL org/jruby/RubyInstanceConfig.()V
DUP
ALOAD 0
INVOKEVIRTUAL org/jruby/RubyInstanceConfig.setArgv ([Ljava/lang/String;)V
INVOKESTATIC org/jruby/Ruby.newInstance (Lorg/jruby/RubyInstanceConfig;)Lorg/jruby/Ruby;
DUP
INVOKEVIRTUAL org/jruby/Ruby.getCurrentContext ()Lorg/jruby/runtime/ThreadContext;
SWAP
INVOKEVIRTUAL org/jruby/Ruby.getTopSelf ()Lorg/jruby/runtime/builtin/IRubyObject;
GETSTATIC org/jruby/runtime/builtin/IRubyObject.NULL_ARRAY : [Lorg/jruby/runtime/builtin/IRubyObject;
GETSTATIC org/jruby/runtime/Block.NULL_BLOCK : Lorg/jruby/runtime/Block;
INVOKEVIRTUAL _dash_.load (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject;
RETURN
MAXSTACK = 5
MAXLOCALS = 1
// access flags 4106
private static setPosition(Lorg/jruby/runtime/ThreadContext;I)V
ALOAD 0
LDC "-"
ILOAD 1
INVOKEVIRTUAL org/jruby/runtime/ThreadContext.setFileAndLine (Ljava/lang/String;I)V
RETURN
MAXSTACK = 3
MAXLOCALS = 2
}
0 retries:
Post a Comment
Note: Only a member of this blog may post a comment.