独習mrubyバイトコード[OP_LOADNIL]
OP_LOADNIL
Arguments
- A:レジスタ番号
How it works?
R(A) := nil
レジスタ[A]にnilオブジェクトを代入する
When used?
nilをレジスタ引数にとる命令に使われたりしている。
class TestClass
end
t = TestClass.new
出力されるバイトコードは、こんな感じ。
00001 NODE_SCOPE:
00004 local variables:
00004 t
00001 NODE_BEGIN:
00001 NODE_CLASS:
00002 :TestClass
00002 body:
00001 NODE_BEGIN:
00004 NODE_ASGN:
00004 lhs:
00004 NODE_LVAR t
00004 rhs:
00004 NODE_CALL(.):
00004 NODE_CONST TestClass
00004 method='new' (15)
irep 0x60001a810 nregs=4 nlocals=2 pools=0 syms=2 reps=1
file: a.rb
1 000 OP_LOADNIL R2
1 001 OP_LOADNIL R3
1 002 OP_CLASS R2 :TestClass
1 003 OP_EXEC R2 I(+1)
4 004 OP_GETCONST R2 :TestClass
4 005 OP_SEND R2 :new 0
4 006 OP_MOVE R1 R2 ; R1:t
4 007 OP_STOP
irep 0x600087580 nregs=2 nlocals=1 pools=0 syms=0 reps=0
file: a.rb
1 000 OP_LOADNIL R1
1 001 OP_RETURN R0 normal
OP_CLASSの引数のAがR2、R3には、Super Classが入る。ここでは継承ないので、nilが入っている。
R2には、定義したクラスが入ることになる。どうせ上書きされるのなら、R2のLOADNILは不要?処理が失敗したときのためにnilにしている?
Note
nilとは
nullではなく、nilである由来は、Smalltalk、Lispらしい。1
いろいろな言語の影響を受けてRubyは作られている。2
mruby/cの場合
オブジェクトの種別に”MRB_TT_NIL”を設定している。
int ra = GETARG_A(code);
mrbc_release(®s[ra]);
regs[ra].tt = MRB_TT_NIL;
mrubyの場合
/* A R(A) := nil */
int a = GETARG_A(i);
SET_NIL_VALUE(regs[a]);
SET_***_VALUEは、NaN boxingを適用するか否かで参照するヘッダファイルが異なる。適用しない場合は、
#define BOXNIX_SET_VALUE(o, ttt, attr, v) do {\
(o).tt = ttt;\
(o).attr = v;\
} while (0)
#define SET_NIL_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_FALSE, value.i, 0)
#define SET_FALSE_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
ttがオブジェクトの種別だけど、MRB_TT_NILではなくて、MRB_TT_FALSEとして扱われている。MRB_TT_FALSEとの違いを見ると、value.iの値が1か0かで区別して、種別の数が増えないように節約しているように見える。
詳しくは、Nilを扱っているコードも読んでみないといけない。
Reference
“Why does Ruby use nil to name the null object?” https://stackoverflow.com/questions/22108397/why-does-ruby-use-nil-to-name-the-null-object
松江Ruby会議09の松本さんの講演
Recent Comments