CALL なインストラクション (2)
昨晩に引き続き。
ひげぽんさんのレビューコメント
_SCM_PROC_SUBR は一部のものを除いて PC を更新することはない_という部分、なんだろって思ってたんですが確かに
PC = PC_TO_RETURN; SCM_PROF_COUNT_CALL(vm, VAL0); VAL0 = SCM_SUBR(VAL0)->func(ARGP, argc, SCM_SUBR(VAL0)->data); /* the subr may substituted pc, so we need to check if we can pop the continuation immediately. */ if (TAIL_POS()) RETURN_OP();
最初で RET を PC に置いといて subr を評価した後に RET のままだったら書き変わってない認定、という事だろうか。や、違うな RET の事が多いのでこん中でやっちゃえ、ってのが意図?
ではなくって PC 書き換えの発生が少ないので事前に RET 入れといて書き変わってなかったらこん中で、とゆー事か。ちょっとまだオチてないんですが、成程。
クロージャの場合
ええと、微妙なのが argc の値で分岐している部分なんですがマクロを手動展開してみてやれ。
if (argc) { do { ScmEnvFrame *e__ = (ScmEnvFrame*)SP; e__->up = SCM_CLOSURE(VAL0)->env; e__->info = SCM_PROCEDURE_INFO(VAL0); e__->size = SP - ARGP; SP += ENV_HDR_SIZE; ARGP = SP; ENV = e__; } while (0) } else { ENV = SCM_CLOSURE(VAL0)->env; ARGP = SP; }
これ、CALL に入ってきた時点でのスタックの様子が分からんと駄目か。
でも ここを見るに引数が積まれてるケイスって then ブロックなソレにほぼ合致しているはず。
って何か違うな。を、FINISH_ENV の記述が参考になるか。
引数がある場合は_環境ヘッダ_が push されてます。
うーん
ちょっとこのあたり、きっちりイメージできん。もう少し修行が必要。
何が微妙か
ちょっとだけ控え。
- クロージャが持っている環境
- 具体的に言えば上記の SCM_CLOSURE(VAL0)->env ですね
- 環境フレームの属性 (特に up) が何を指しているか
- 直前の環境?
ええと、vm.h に以下なコメントあり。
/* * Environment frame * * : : * +--------+ * | size=N | * | info | * |...up...|<--- ScmEnvFrame* envp * |arg[N-1]| * |arg[N-2]| * : : * | arg[0] | * +--------+ * : : */
あ、分かった。もしかして ここのソレから逆な持ち方に変わったのかな??
なるほど。この持ち方だと envp と size で arg が手繰れる。これは x86 なスタックフレームのナニを踏襲しとるんかな。
てーコトは引数が無いクロージャのソレは環境 push する必要が無い、というのが else ブロックの意図でしょうか。なかなか凄いな。