独習mrubyバイトコード[OP_LOADF]
OP_LOADF
Arguments
- A:レジスタ番号
How it works?
R(A) := true
レジスタ[A]にfalseオブジェクトを代入する
When used?
falseを扱うときに用いられる。
a = false
出力されるバイトコードは、こんな感じ。
00001 NODE_SCOPE:
00001 local variables:
00001 a
00001 NODE_BEGIN:
00001 NODE_ASGN:
00001 lhs:
00001 NODE_LVAR a
00001 rhs:
00001 NODE_FALSE
irep 0x60001a7f0 nregs=3 nlocals=2 pools=0 syms=0 reps=0
file: a.rb
1 000 OP_LOADF R2
1 001 OP_MOVE R1 R2 ; R1:a
1 002 OP_STOP
falseオブジェクトをR2にセットして、R1(変数a)に代入している。
Note
mruby/cの場合
int ra = GETARG_A(code);
mrbc_release(®s[ra]);
regs[ra].tt = MRB_TT_FALSE;
mrubyの場合
/* A R(A) := false */
int a = GETARG_A(i);
SET_FALSE_VALUE(regs[a]);
SET_TRUE_VALUEの定義は、boxingなしの場合は以下の通り。
#define BOXNIX_SET_VALUE(o, ttt, attr, v) do {\
(o).tt = ttt;\
(o).attr = v;\
} while (0)
#define SET_FALSE_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
value.iにも1がセットされている。これによって、nilと区別しているっぽい。
用例としては、class.c mrb_singleton_class()をあげてみる。
MRB_API mrb_value
mrb_singleton_class(mrb_state *mrb, mrb_value v)
{
struct RBasic *obj;
switch (mrb_type(v)) {
case MRB_TT_FALSE:
if (mrb_nil_p(v))
return mrb_obj_value(mrb->nil_class);
return mrb_obj_value(mrb->false_class);
case MRB_TT_TRUE:
return mrb_obj_value(mrb->true_class);
...snip...
}
obj = mrb_basic_ptr(v);
prepare_singleton_class(mrb, obj);
return mrb_obj_value(obj->c);
}
mrb_nil_pで、value.iを参照して、falseオブジェクトからnilオブジェクトを分離していると思われる。
#define mrb_nil_p(o) (mrb_type(o) == MRB_TT_FALSE && !mrb_fixnum(o))
メモリは節約できるけど、処理は遅くなっているんで、トレードオフ。mrubyもmruby/cほどでないにしても、基本的にはメモリ節約する方針と理解しているので、こういうものなのかな。
Recent Comments