北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

XS Nite (Shibuya.pm Tech Talk #9)

id:TAKESAKOさんの好意で出させてもらったので、適当にロギングします。

はじめてのXS / id:hirose31さん

  • XSってなに? PerlとCをつなぐための言語&インタフェース
    • Foo.xs → xsubpp → Foo.c → Cコンパイラ → Foo.so
    • Perlからは、XSLoaderやDynaLoaderでFoo.soを読み込む
  • なぜXSを使う?
    • Cのライブラリを使いたい
    • パフォーマンス向上(Cache::Memcached::Fast 等)
    • Perlの内部をいじくり倒す(autobox*1 等)
  • XSを書いた動機 → forkしまくりたくなかった
  • ドキュメント
    • perlxstut, perlxs, perlguts, perlapi
  • h2xs or module-starter (Module::Starter::XSimple) で始める
  • 外部のsay_hello()関数を呼ぶxsの例
    • 動的の場合は LIBS に指定、静的の場合は MYEXTLIB
  • 参考
    • CPANのXSモジュール
    • Google Code Search で、API名 + *.xsで調査
  • Perlの"代わりに"XSを書いてはいけない
    • Perlの方が簡単
  • メモリリークの問題 → XS内で作った値が、スコープはずれても解放されない
    • New〜したものはSafefree()
    • newSV〜したものはsv_free
    • DESTROY()でやるべし
  • プロファイリング
    • valgrind --tool=callgrind と kcachegrind
  • 互換性
    • NewxzってのはPerl5.8.4では使えないらしい
    • → ppport.hで吸収、Devel::PPPort
  • まとめ
    • XSは簡単
    • XSでPerlの内部構造に詳しくなる
  • 質疑応答
    • Q. PTR2INT??とかって何してるの?
    • A. 次のセッションで

Perl 5 Internalsの世界にようこそ / 牧さん

  • PerlはCで書かれている
  • XS、XSUB → Glue。マクロやツール類
  • Perlは、規模・歴史の割にはよくメンテされている
  • 構造体
    • SV: スカラ
    • AV: 配列
    • HV: ハッシュ
    • GV: グロブ
  • SV構造体
    • Perlのスカラ、リファレンス、リテラル
    • SVの種類: IV, UV, NV, PV(文字列), RV
    • ポインタ+REFCNT+フラグ、で構成される
    • 文字列: SVのポインタの先にPVが格納され、フラグにSVf_PVがセットされる
      • PVには、charの先頭ポインタとか文字列長、バッファ長等
    • 整数: PVIVへのポインタを持っている。PVIVには整数値を含む(文字列値はNULL)
  • AV構造体
    • AVの先にXPVAVがある
  • HVとかGVは略
  • Structural Equivalence
    • 構造体内のバイトオフセットを揃えることにより、SVとかAVが互いにキャスト可能になる
  • SVのAPI → newSV~、Sv〜OK等
  • REFCNT
    • メモリ管理用のリファレンスカウント
    • 誕生のときはREFCNT = 1、参照が増えると加算する
    • REFCNT == 0 になると、解放
    • 値そのものではなく、リファレンスを参照するとカウントが増える
  • SvREFCNT_inc() と SvREFCNT_dec() : カウントの加算と減算
    • sv_freeよりもこっちが好き
  • SVに魔法をかける
    • 例: tie → SvPVMGにSVがアップグレードされる(MAGIC)を持ってる
  • MAGICの種類: extがユーザ定義
  • 構造体を持ち歩くには?
    • SvIVにポインターを入れる(PTR2INT)
    • ただし、この方法だとPerlから値(整数値)が見えてしまう
  • 構造体をMAGICに入れる
    • sv_magicして、中に入れる
    • Perlからは、構造体が見えない
    • 整数ではなくハッシュとして使えるので、PurePerlで拡張できる
    • Memcached::libmemcached等を参照
  • XSはPerlとCをつなげるもの
    • SV操作をいくらCでやっても、意味はない(5%くらいは速いらしい)
    • Cで書かれてる物のみXSで使う(Perl - XS - C Library)
  • XS関数の定義
  • XS関数→xsubpp(ExtUtils::Xsubpp)→C→コンパイル
  • XSセクション
    • PREINIT, CODE / PPCODE, OUTPUT, BOOT
  • Typemap
    • Cの世界とPerlの世界の型を、毎回XS関数で展開するのはやだ
    • Typemapで自動変換する
    • 自前のTypemapを作れば、カスタムコードを差し込める
    • Typemapにより、XSをほとんど消せる → XSのほとんどは型変換なので
    • Text::MeCabなどを参照
  • さらに研究するには、.xsファイルと.cファイルを見比べるとよい
  • Devel::Peek
    • SVの構造体を覗ける
  • REFCNTによるGC
    • やり玉に挙げられるが・・・?
    • DESTROYが呼ばれるタイミングが保証されるのはよい
    • ハマりどころ
      • hv_storeするときは、SvREFCNT_inc()忘れない
      • コンテナがGCされたときはノータッチじゃなければならない
  • トリビア
    • PVIVにはPVスロットがある
    • 整数を作った段階ではIVには100が入り、文字列評価されるとPVXには"100\0"が入る
    • 文字列分のメモリを使いたくない場合は、print "$x\n" より print $x, "\n"
  • 質疑応答
    • Q. コンテナがGCされたときはノータッチじゃなければならないのは、自動で中身のREFCNT減らされるから?
    • A. はいそうです。アレイの場合も一緒です。
    • Q. ウィークリファレンスはSVレベルではどうなっているの??
    • A. わかりません。宿題。

Inside Ruby.pm 藤さん

  • CライブラリとしてのRuby (ライトニングトーク)
    • Ruby.pmとは? → PerlからRubyの共有ライブラリを呼び出す
  • Rubyのソースの基礎
    • VALUE : SV*
    • Qnil : PL_sv_undef
    • Qtrue, Qfalse : 真偽値
    • ID : 文字列に対する一意の整数値
  • xsubppを通した後の物を参考に、直接Cで書いている
    • XS厨のころに書いたからw
  • rubyのメソッドの呼び出し
    • ruby_self: VALUEになっているかをチェックして、VALUEになってなければPerlオブジェクトをRubyオブジェクトにラップして返す。文字列でRubyのクラスっぽければRubyのクラスを返す
    • Funcall: Rubyの例外の仕組みに対応が必要。(do_funcall_protect)
      • 最後の引数には、ブロック付きメソッドの対応
    • do_funcall_protect
      • rb_protect(evalでくくって呼び出すAPI)を利用。ただし、引数は一つしかとれない
      • 引数を一つにまとめたりして、rb_protectが利用できる形に変換している
      • funcaller→ rb_funcall2を利用。(ちなみに、rb_funcallは可変長引数)
    • VALUE2SV: VALUEをSVに変更。もともとPerlのオブジェクトならそのまま。
      • そのままだと、Rubyのリファレンスカウントで回収される → 独自のリファレンスカウンターを持っている
      • DESTROY()で、Perl側で不要になったタイミングでリファレンスカウントを減らす
  • まとめ
    • RubyのオブジェクトをPerlから見ると、ポインタが整数になって保存されている
    • rb_func2は簡単だが、例外処理が大変
    • 独自のリファレンスカウンタ
    • Ruby側ではmethod_missing()を利用してPerlの関数を呼べるように
  • 現状、Cygwinでしか動かない
  • 質疑応答
    • Q. 1.9対応は??
    • A. APIが大きく変わってるので、書き直し。ParrotでRubyを動かすのは楽しそうだが、専攻が心理学なのでやる暇がない
    • Q. 明日試験なんですよね?
    • A. 明日は臨床心理学と言語心理学の試験です

PerlMachine / wakaponさん

  • PerlMachineとは? 高水準言語マシン(単一言語マシン)
    • 特定のプログラミング言語を専用として動作させるマシン
    • OSから特定言語をターゲットにして構築 ← ハードウェアからではない。VMレベル。
  • PerlMachine : Perlを動かすためだけの計算機
  • 過去の例
  • 目標
    • Perlで記述された高水準言語マシンの実現
    • カーネルも全部Perlで、Perl5処理系コードとおつきあい
    • CPANモジュールの積極的利用
  • 方針
    • 出来る限りPerl、XSUB
    • 俺仕様は作らない
    • 実行速度は・・・現実的じゃないときだけXSUB
    • ハードの上に、直接Perl処理系を載せ、その上に構築
  • perl5.10.0のmicroperl → 処理系もアプリも特権モードで動作
  • 現状
    • XSUBでI/Oやメモリ管理は拡張
    • 標準ライブラリ: strict, warnings, feature, Carp
    • ベアマシン上でPerl5.10.0が動く → main.plが動く
  • 複数のインタプリタインスタンスが動いている
  • ファイル読み込みの実行フロー、printの実行フロー
  • grubでロードしている
  • microperl
  • newlib
  • FatFs 汎用FAT
  • XSUB - 主記憶アクセス、I/Oポートアクセス
  • XSUBの登録を自前でやっている(perl_parse)
  • 今後の展開
  • 質問

ライトニングトーク

  • autobox internals / id:tokuhiromさん
    • autobox is crazy → 真似は良くない
    • 問題: length("foo")は駄目。"foo"->length()がいい
    • "foo"->length()はランタイムエラー。コンパイル時に手を加えればいい
      • VMをハック。昔はPerlのパッチだった。
      • entersubのオペコードをハックする
      • pp_flag に OPf_SPECIAL をセットし、pp_addrを入れる
      • method_nameが呼び出される時に、フックがかけられるようになる
  • PL_check hacks / id:yappoさん
    • XSとは、パッチをあてずにPerlの内部をハックするもの
    • PL_check
      • 関数のフックテーブル。構文チェック、BEGINフェーズ。
    • op.c Perl_ck_delete参照
    • オペコード構造体
    • opecode.hにPL_checkがある
    • PL_checkをいじるには、どのオペコードが何をやってるか熟知する必要がある
      • perl-users.jpに置いてある
    • PL_opマクロでオペコードをとれる
    • まとめ: PL_checkはVM全体に影響があるが、ppaddrをhackすると、影響範囲が局所的
  • Arguments::calleeの作り方 / id:TAKESAKOさん
    • 無名関数の再帰をうまく作りたい。calleeが欲しい。
    • my $foo = sub { $foo->() } ができない
    • Devel::Caller とか B:: でできるらしい
    • arguments.xsを作った!
    • my $foo = sub { arguments::callee->() }
    • DB package を利用
    • cxstack : コンテキストスタック。呼ばれたものスタック
      • これをサブルーチンが出るまで辿る
    • 引数の返し方
      • OUTPUT: RETVAL、PPCODE: ST(i)、XPUSHs()
    • 続きはcoderepos
gdb /usr/sbin/httpd
(gdb) run -X -f httpd_test.conf
    • btと打つと、Cレベルのバックとレースがとれる
    • curinfoマクロ : Perlレベルのどこで落ちたかが見れるマクロ
      • Perl_eval_pvで、任意のPerlコマンドを実行できる
    • 閾値を超えたら、すぐにgdbでアタッチするシェルスクリプトのデモ
    • 便利なgdbの初期マクロの紹介*3
  • Abstract Script Engines / Higuchiさん
    • Perlから.NETを呼ぶデモ、Java swingからPerlを呼ぶ例
    • 各種スクリプト、ランタイムを混ぜて使える例
    • スクリプト言語インタプリタやオブジェクトを抽象化したインタフェースを用意
    • スクリプト言語やランタイムがそのインタフェースを実装
    • ランタイム間のマーシャリング
      • 基本型はそのまま、オブジェクトは代理オブジェクト
    • 共通化の対象
    • 動的と静的言語の結びつけ
      • Javaでは、リフレクションと動的プロクシ
    • スレッド
  • Perl5VM Golf / id:tokuhiromさん
    • オペコードの総和 : 例えば、1000OPを目指す
    • オペコードの大きくてバイトの短いもの紹介
    • Acme::PerlVMGolfで、オペコードとバイト数の計算ができる

感想

濃過ぎました≧(´▽`)≦。

ASEが、ここまで実装進んでるってのがすごいと思いました。

後はもう、脱帽としか言えない感じ。よくもまあ皆様、Perlの内部をここまで読みこんでますね。その情熱と努力には頭が下がるばかりです。

久々に本腰入れてPerlやりたくなりました。internalを。

*1:Perlのプリミティブ型にメソッド生やせる

*2:吹いたw

*3:これは便利そう