今日は家人はお出かけ
なので CALL のレビューに集中できるな、と言ってたんですが
家人から申しつかった用事を済ませていたらスデに 1500 過ぎ。とりあえず豚角煮を作りつつ CALL なソレを読みはじめるもいきなり
argc = SP - ARGP;
が引数の個数をナニ、という部分でもう駄目。ええと確かドキュメントがあったぞ、と言いつつググッて以下を発見。
とりあえず目を通す。
痛い
SP も ARGP もポインタなんだよな。それにしても現状の処理を見るに上記文書にある PUSH_ENV_HDR というマクロが出てこない。例えば
gosh> (disasm (lambda (x) (x 1 2 3) 0)) main_code (name=#f, code=0x80f8f28, size=9, const=0, stack=12): args: #f 0 PRE-CALL(3) 7 2 CONSTI-PUSH(1) 3 CONSTI-PUSH(2) 4 CONSTI-PUSH(3) 5 LREF0 ; x 6 CALL(3) ; (x 1 2 3) 7 CONSTI(0) 8 RET #<undef> gosh>
みたいなナニを例にソースを見てみるに PRE-CALL で確かに次の命令 (上の例だと 0 を戻す CONSTI(0) になると思われます) を継続フレームたるナニに push して引数を順にスタックに push しています。
上記ドキュメントによれば、次の命令を継続フレームに push した直後に_引数フレームの頭を積む_とあるんですが、そうなってはいないな。
あら?
ワケワカんなくなってきた。_次の命令_って何だよ。
と言いつつ
まごまごしててココを発見。灯台の真下は暗かった。とは言えまだよく分からんのが PRE_CALL で出てくる procedure_id なるソレ。このドキュメントでも結論出てなさげだったんですが、確認のために以下を試してみた。
gosh> (disasm (lambda (x y) (x 1 (y 2) 3) 0)) main_code (name=#f, code=0x8149f88, size=14, const=0, stack=18): args: #f 0 PRE-CALL(3) 12 2 CONSTI-PUSH(1) 3 PRE-CALL(1) 8 5 CONSTI-PUSH(2) 6 LREF0 ; y 7 CALL(1) ; (y 2) 8 PUSH 9 CONSTI-PUSH(3) 10 LREF1 ; x 11 CALL(3) ; (x 1 (y 2) 3) 12 CONSTI(0) 13 RET #<undef> gosh> (disasm (lambda (x y) (x 1 (y 1 2 3) 4) 0)) main_code (name=#f, code=0x813ef40, size=16, const=0, stack=20): args: #f 0 PRE-CALL(3) 14 2 CONSTI-PUSH(1) 3 PRE-CALL(3) 10 5 CONSTI-PUSH(1) 6 CONSTI-PUSH(2) 7 CONSTI-PUSH(3) 8 LREF0 ; y 9 CALL(3) ; (y 1 2 3) 10 PUSH 11 CONSTI-PUSH(4) 12 LREF1 ; x 13 CALL(3) ; (x 1 (y 1 2 3) 4) 14 CONSTI(0) 15 RET #<undef> gosh>
うーん。引数の数??
てーか disasm の出力見ててなんとなく PC の並びが以下になってるのではないかと推測。
PRE-CALL(3) CONSTI(0) CONSTI-PUSH(1) PRE-CALL(3) PUSH CONSTI-PUSH(1) CONSTI-PUSH(2) CONSTI-PUSH(3) LREF0 CALL(3) PUSH 以下略
ええと先頭あたりを追いかけてみるに
- dispatch に戻って PRE-CALL が取り出されて PC++ される
- PC は CONSTI(0) を指している
- CONSTI(0) が取り出されて継続フレームに push される
- PC++ されて PC は次の CONSTI-PUSH(1) を指す
- NEXT で次
disasm した時のナニが微妙にきちんと並んでないのはそれでだったのか、と。でもこれって compile.scm 解析して初めて根拠になるソレなんだなぁ。類推の域を越えないあたりが微妙っちゃ微妙。でもなんかスッキリしますた。(何
夢中で
おっかけてて、豚角煮をコガしかけました。とほほほ。でも今回はタマゴも一緒に煮ちゃってええカンジ。(を
続き
で、何だっけ。以降はざっくりブロック毎に分けちゃえ、ってか CALL でもそうしてますな。
- VAL0 が手続きオブジェクトでない (!SCM_PROCEDUREP(VAL0)) 場合
- VAL0 の手続きタイプ (SCM_PROCEFURE_TYPE(VAL0) が SCM_PROC_SUBR (C で定義された手続き)の場合
- VAL0 の手続きタイプ (SCM_PROCEFURE_TYPE(VAL0) が SCM_PROC_CLOSURE の場合
- VAL0 の手続きタイプ (SCM_PROCEFURE_TYPE(VAL0) が SCM_PROC_GENERIC の場合
- VAL0 の手続きタイプ (SCM_PROCEFURE_TYPE(VAL0) が SCM_PROC_NEXT_METHOD の場合
- この時点で proctype が SCM_PROC_GENERIC の場合
- 後処理
- SCM_METHOD(VAL0)->func が NULL じゃない (C で定義された method) 場合
- SCM_METHOD(VAL0)->func が NULL (scheme で定義された method) の場合
というカンジでしょうか。
VAL0 が手続きオブジェクトでない場合
どこまでイケるか。そろそろ家人も戻ってくるはず。レビューになってるのかどうかも疑問だったりしますが、一応ドキュメントを照らしつつ見てますので。(何
ここでは SP をぐじゃぐじゃ弄くりマワしてますが、ARGP とか SP にフォーカス当てると以下なカンジになってると見て良いのでしょうか。
| | SP>| | +--------+ | arg[2] | | arg[1] | ARGP>| arg[0] | +--------+
これを順ぐりにずらしていって
| | | | | | | | SP>| arg[2] | SP>| arg[2] | SP>| arg[2] | SP>| arg[2] | +--------+ +--------+ +--------+ +--------+ | arg[2] | | arg[1] | | arg[1] | | arg[1] | | arg[1] | | arg[1] | | arg[0] | | arg[0] | ARGP>| arg[0] |ARGP>| arg[0] |ARGP>| arg[0] |ARGP>| val0 | +--------+ +--------+ +--------+ +--------+
みたいにした後に SP とか argc とかをナニ。
一体これは何だ、と言いつつ Scm_GenericObjectApply を確認した所、以下なドキュメントへのポインタが。
具体的な例が挙げられて説明されてます。
このケイス (VAL0 が手続きオブジェクトでない (!SCM_PROCEDUREP(VAL0)) 場合) ではスタック弄って val0 とか proctype とか nm をセットした後に generic というラベルに goto しております。
VAL0 の手続きタイプが SCM_PROC_SUBR の場合
ADJUST_ARGUMENT_FRAME というマクロがやたらに長い。横着してひらで掘った後を確認。
ここでは_引数フレーム_な名前が付いてますな。確かに中身を見たら引数の個数のチェックとオプション引数のリストのたたみ込みを行なっております。
家人が
戻ってまいりましたので、一旦ストップ。
続
なんとなく文脈的に理解はできるんですが微妙なのが以下。
VAL0 = SCM_SUBR(VAL0)->func(ARGP, argc, SCM_SUBR(VAL0)->data);
抽象化され杉でナニ。
ええと、ScmSubr なソレのコンストラクタは proc.c にて定義されてる Scm_MakeSubr 手続きで OK なのかな。でもまだ func と data という属性が何なのか、が微妙。
で、ReadingGauche を探してみたら Scm_MakeSubr なドキュメントはあったんですが data 属性にセットされるのが何なのかは不明。