Perl XS でちょっと複雑なことをしようと思うと、CODE または PPCODE セクションに C レベルのコードを記述する必要がありますが、この CODE と PPCODE セクションの違いはなんだろうということで調べてみました。詳細は perlxs の "The PPCODE: Keyword" や "The RETVAL Variable" を参照のこと。
CODE セクションと PPCODE セクションは両立できないことを前提としていますが、CODE セクションを用いると Perl のスタックポインタ (SP) が裏で自動的に設定されるようです。
In CODE: sections SP preserves the value which was on entry to the XSUB: SP is on the function pointer (which follows the last parameter).
おそらくスタックは以下のような形になっている。
- XSUB のエントリーポイント <= SP
- XSUB への n 番目の引数
- XSUB への n-1 番目の引数
- XSUB への n-2 番目の引数
・・・
- XSUB への最初の引数
XSUB から制御が戻ると、普通は「XSUB への最初の引数」の領域にある値が戻り値として返ります。実際に CODE セクションを使う限りは SP を特に意識する必要はなく、"「XSUB への最初の引数」の領域" は RETVAL が自動的に使う形になっているようです。
CODE セクションとは逆に、PPCODE セクションを用いた場合は SP を強く意識しないといけません。
In PPCODE: sections SP is moved backward to the beginning of the parameter list, which allows ""PUSH*()"" macros to place output values in the place Perl expects them to be when the XSUB returns back to Perl.
PPCODE セクションを用いた場合は、SP が XSUB への最初の引数が置かれたコールスタック上の領域を指すことになります。
- XSUB のエントリーポイント
- XSUB への n 番目の引数
- XSUB への n-1 番目の引数
- XSUB への n-2 番目の引数
・・・
- XSUB への最初の引数 <= SP
XPUSH* などを明示的に呼ぶというような SP の面倒な操作が必要な代わりに、複数の戻り値を XSUB から返せるようになります。