is_a?
vm.c の SCM_VM_IS_A の項をニラむ。やはり
if (!SCM_FALSEP(Scm_ClassOf(obj)->redefined)) {
な場合以外は平易。
何が
微妙なのかなぁ、と言いつつ何度が昼間に現実トウヒ。とりあえず
if (!SCM_FALSEP(Scm_ClassOf(obj)->redefined)) { CHECK_STACK(CONT_FRAME_SIZE); PUSH_CONT(PC); PC = PC_TO_RETURN;
な前処理は
- PC を継続フレームに push
- PC に RET をセット
- という事は 継続フレームから pop する、という事??
と見てあとは
VAL0 = Scm_VMIsA(obj, c);
が何か、という部分ですな。ちなみに obj は POP_ARG したナニで、c は VAL0 レジスタを ScmClass * でキャストしたソレ。受け手は以下。
/* * (is-a? obj class) * - if obj's class is redefined, first updates obj. */ ScmObj is_a_cc(ScmObj result, void **data) { return Scm_VMIsA(SCM_OBJ(data[0]), SCM_CLASS(data[1])); } ScmObj Scm_VMIsA(ScmObj obj, ScmClass *klass) { ScmClass *k = Scm_ClassOf(obj); if (!SCM_FALSEP(k->redefined)) { void *data[2]; data[0] = obj; data[1] = klass; Scm_VMPushCC(is_a_cc, data, 2); return instance_class_redefinition(obj, k); } return SCM_MAKE_BOOL(Scm_TypeP(obj, klass)); }
最初難しく考えていたみたいでクラスの階層みたいのを遡ってくのかな、と思ってたりしたのですがそうでもないみたい。とりあえず
gosh> change-class #<generic change-class (1)> gosh>
ジェネリック関数って何ッスか?
とりあえず
generic はスルーで。Scm_VMIsA() 限定で見てみると
- k->redefined が #f でない場合
- 下準備して Scm_VMPushCC で今の呼び出しを継続フレームにナニして stack に push
- instance_class_redefinition() の戻りを return
で、この instance_class_redefinition() ですが、前処理の
(void)SCM_INTERNAL_MUTEX_LOCK(old->mutex); while (!SCM_ISA(old->redefined, SCM_CLASS_CLASS)) { (void)SCM_INTERNAL_COND_WAIT(old->cv, old->mutex); } newc = old->redefined; (void)SCM_INTERNAL_MUTEX_UNLOCK(old->mutex);
はスルーします。ロックを確保して何かしてロックを解放してるのは、ぱっと見理解できるんですが、SCM_ISA() の評価の間に再定義されるのを防いでる、と見てよいのでしょうか。なんか違うな。
で、核心が以下。
if (SCM_CLASSP(newc)) { return Scm_VMApply2(SCM_OBJ(&Scm_GenericChangeClass), obj, newc); } else { return SCM_OBJ(old); }
ええと、ここで newc が ScmClass なオブジェクトなら change-class して RET するんですな。で、再び RET で出てくる Scm_VMIsA() に制御が渡るはず。
ざっくりな
理解なんですが、ぎりぎりセイフと見てレビュのコメント投入に着手。