C言語でCurrying2

http://d.hatena.ne.jp/shinichiro_h/20060119の手法は引数を積みなおして関数ポインタを呼ぶというもの(だと思う)。

call cを呼んだ直後のスタック …… 100 ret(c)
call addを呼んだ直後のスタック …… 100 ret(c) 100 10 ret(add)

という感じで。これをtail callに出来たら面白いかも。

calleeがスタックを解放する場合

簡単すぎて省略。

callerがスタックを解放する場合

call cを呼んだ直後のスタック …… 100 ret(c)
call addを呼んだ直後のスタック …… 100 10 ret(add)
call cから帰った直後のスタック …… x

となるように手を加えればよい。

細工付きトランポリン
call cを呼んだ直後のスタック …… 100 ret(c)
call addを呼んだ直後のスタック …… 100 10 ret(add)
call addから帰った直後のスタック …… 100 10
call cから帰る直前のスタック …… 100 ret(c)
call cから帰った直後のスタック …… 100

トランポリン関数部分で細工を頑張る。でも、スタック消費がわずかに減っただけで処理自体は元のものよりも重くなっている。

bp, spに細工
call cを呼んだ直後のスタック …… 100 ret(c)
call addを呼んだ直後のスタック …… 100 ret(c) 100 10 ret(c)
call addから帰った直後のスタック …… 100

call addを呼ぶ直前のebp, espをcall cを呼ぶ直前の値にし、一回のretで二つの関数呼び出しの分を返してしまうという。処理の流れはtail call、スタック消費は非tail callになっている。

〆。

C言語の呼び出し規約は良くも悪くも難しい。