独習mrubyバイトコード[OP_LOADSELF]
OP_LOADSELF
Arguments
- A:レジスタ番号
How it works?
R(A) := self
レジスタ[A]にselfオブジェクトを代入する
When used?
selfに対して、何か処理をするときにあちこちで使われる。
例えば、
puts "test"
出力されるバイトコードは、こんな感じ。
00001 NODE_SCOPE:
00001 NODE_BEGIN:
00001 NODE_FCALL:
00001 NODE_SELF
00001 method='puts' (227)
00001 args:
00001 NODE_STR "test" len 4
irep 0x60001a790 nregs=4 nlocals=1 pools=1 syms=1 reps=0
file: a.rb
1 000 OP_LOADSELF R1
1 001 OP_STRING R2 L(0) ; "test"
1 002 OP_SEND R1 :puts 1
1 003 OP_STOP
スクリプト実行時のトップレベルのself、すなわちmainオブジェクトをR1にセットして、R1に対して、putsメソッドをsendして処理を実行している。
Note
レジスタの0番にはselfが格納されている。
mruby/cの場合
int ra = GETARG_A(code);
mrbc_release(®s[ra]);
mrbc_dup(®s[0]); // TODO: Need?
regs[ra] = regs[0];
0番レジスタの値をA番のレジスタにコピーしている。
mrubyの場合
int a = GETARG_A(i);
regs[a] = regs[0];
参照カウントが無いぶん、よりシンプル。
@miura1729さんのコメントに、
MOVE Rm, R0じゃ駄目なのか?と思わないでもないが、何か理由があるのだろう。私は知らないが。あ、mrubyのVMでは常にR0にselfが入っているんだよ。Rubyレベルでは何の役にも立たない知識でした。
LOADSELFはMOVEより少し早い可能性があるって言う利点はありそう。早いと言ってもほんの少しだけど、LOADSELFはいっぱい出てくるので効果が出てくるかもしれない。
とあるので、MOVEと比較してみる。
/* A B R(A) := R(B) */
int a = GETARG_A(i);
int b = GETARG_B(i);
regs[a] = regs[b];
確かに、コピー元のレジスタが固定されていぶん、アドレスの参照回数が少なくて済む、というメリットはありそう。
Recent Comments