introduction to perl magic
DESCRIPTION
Used for talks in YAPC::Asia 2009- gfxTRANSCRIPT
Introduction to Perl MAGIC for XS writers
Fuji, Goro (gfx) <[email protected]>
YAPC::Asia 2009, Sep 10th
perlguts says: This section still under construction. Ignore
everything here. Post no bills. Everything not permitted is for bidden.
perlguts says about "Magic Variable": Any SV may be magical, that is, it
has special features that a normal SV does not have. These features are stored in the SV structure in a linked list of struct magic's, typedef'ed to MAGIC.
MAGIC features: hook methods + managed data
/* mg.h of 5.10.1 */struct magic { MAGIC* mg_moremagic;/* pointer to the next magic */ MGVTBL* mg_virtual; /* pointer to magic hook methods */ U16 mg_private; /* user data(1): small integer */ char mg_type; /* type identity, e.g. PERL_MAGIC_ext
*/ U8 mg_flags; /* flags reserved by core */ I32 mg_len; /* the length of mg_ptr (or
HEf_SVKEY) */ SV* mg_obj; /* user data(2): sv */ char* mg_ptr; /* user data(3): managed pointer or
sv */};/* perl.h */typedef struct magic MAGIC;
/* mg.h of 5.10.1 */#ifdef STRUCT_MGVTBL_DEFINITIONSTRUCT_MGVTBL_DEFINITION;#elsestruct mgvtbl { int (CPERLscope(*svt_get)) (pTHX_ SV *sv, MAGIC* mg); int (CPERLscope(*svt_set)) (pTHX_ SV *sv, MAGIC* mg); U32 (CPERLscope(*svt_len)) (pTHX_ SV *sv, MAGIC* mg); int (CPERLscope(*svt_clear)) (pTHX_ SV *sv, MAGIC* mg); int (CPERLscope(*svt_free)) (pTHX_ SV *sv, MAGIC* mg); int (CPERLscope(*svt_copy)) (pTHX_ SV *sv, MAGIC* mg, SV *nsv, const char *name, int
namlen); int (CPERLscope(*svt_dup)) (pTHX_ MAGIC *mg,
CLONE_PARAMS *param); int (CPERLscope(*svt_local)) (pTHX_ SV *nsv, MAGIC
*mg);};#endif
# perlgutsFunction pointer Action taken---------------- ------------svt_get Do something before the value of the SV is
retrieved.svt_set Do something after the SV is assigned a value.svt_len Report on the SV's length.svt_clear Clear something the SV represents.svt_free Free any extra storage associated with the SV.
svt_copy copy tied variable magic to a tied elementsvt_dup duplicate a magic structure during thread
cloningsvt_local copy magic to local value during 'local‘
(snip)
Some special variables are bound to C variables $^H -> PL_hints $! -> errno
Weak references Defer elements UTF8 helpers
To look into MAGICs, you can use Devel::Peek perl –MDevel::Peek –e ‘Dump $^H;’
B::Hooks::EndOfScope via Variable::Magic using hook methods
WeakRef::Auto using hook methods
Sub::Name using managed data
Class::MOP/Moose using managed data under construction!
$ perl -MDevel::Peek -e 'Dump \@ISA'SV = RV(0x8ce3174) at 0x8ce3168 REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x8cf33c0 SV = PVAV(0x8ce4038) at 0x8cf33c0 REFCNT = 2 FLAGS = (SMG,RMG) # has SetMagic and GetMagic MAGIC = 0x8cf62c8 MG_VIRTUAL = &PL_vtbl_isa # mg_virtual MG_TYPE = PERL_MAGIC_isa(I) # mg_type MG_OBJ = 0x8ce3208 # mg_obj ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL)
# @ISA magic will invalidate methods caches when class hierarchies are changed.
If you don’t write XS, you need not to care about MAGIC, but otherwise you must care about it because Perl APIs do not always handle MAGIC.
PerlレベルではMAGICを意識する必要はないが, C レベルではMAGICを扱う APIと扱わない APIが区別されているので, XSを書くならば常に意識しなければならない。
MAGI C をハンドルする APIを知る
MAGIC を起動する API SvIV/SvNV/SvPV など -> SetMAGIC sv_setsv_mg などの sv_setx_mg 系 ->
GetMAGIC sv_isobject など( perlapi に載っていないことが
多い) MAGIC を起動しない API
SvIVX/SvOK などSVの要素を直接参照するもの sv_setx 系で _mg の付かないもの xsubpp のデフォルト typemap のいくつか(後
述)
xsubpp/typemap の特性を知る
typemap のうち、 MAGIC を起動しないものがある char*, int などは MAGIC をハンドルする HV*, AV*, CV* などは MAGIC をハンドルしない
ドキュメントには書いていないので注意 Magic::Example に例
http://github.com/gfx/YAPC-Asia-2009-gfx/tree/master
->> perl Makefile.PL && make test (should fail)
[ah]v_store の戻り値
The return value will be NULL if the operation failed or if the value did not need to be actually stored within the hash (as in the case of tied hashes) (perlapi)
タイハッシュ・配列に store すると、 NULL を返す その場合、 store したSVを解放しなければならな
い XS内のみで使う hv/av ならば戻り値は無視で
きる (void)hv_store_ent(hv, key, val, 0U); /* OK */
スタック操作を伴うケース Question
XPUSHs() などはSPを realloc() する可能性がある newSVsv() などは MAGIC を起動する可能性がある ∴newSVsv() の前後でSPの値が変わる可能性がある?
Answer No. メタスタック (PERL_SI) メカニズムによるSPの保護 MAGIC(tie), destructor などで自動的に呼び出されるサブ
ルーチンについては、SPが変わる心配はない ただし、エクステンションが hook methods 内でサブ
ルーチンを呼ぶ場合は、メタスタックの管理が必要 PUSHSTACK/POPSTACK (but no document)
PERL_MAIGC_ext
sv_magicext(sv, mg_obj, PERL_MAGIC_ext, &mg_vritual, mg_ptr, mg_len) mg_ptr は char* で、 mg_len でその長さを指定
mg_len が 1 以上のとき、 mg_ptr は sv_magicext 内で malloc され、 sv が解放されるときに free される
mg_len が 0 のとき、 mg_ptr はそのまま保存される mg_len が HEf_SVKEY のとき、 mg_ptr は SV* と見な
され、 sv_magicext 内で SvREFCNT_inc され、 sv が解放されるときに SvREFCNT_dec される (mg_obj と同じ扱い )
つまり、 mg_obj と mg_ptr+HEf_SVKEY のSVは、 mortalize するか、 sv_magicext のあとに SvREFCNT_dec しなければならない
PERL_MAGIC_ext の利用
hook methods 挙動が不気味すぎて扱いが難しい
Magic::Watch (on github) に例はあるが… :( 注意事項が沢山ありすぎる
managed data 時代は XS code templates!
XS code templates (1)
XSUBを動的に生成するメカニズム クロージャのXS版 MAGIC を使って cv にデータを添付する Template (XSUB) + Parameters (MAGIC) Used by
Class::XSAccessor Class::MOP/Moose (future version)
XS code templates (2)
動的コード生成の方法 eval $subroutine_source_code closure (anonymous subroutine) XS code templates Inline::x86 による JIT
Gen Time Run Time Maintain
eval slow moderate
hard
closure moderate
slow easy
XSt fast fast hard
Inline::x86
fastest fastest hellish
Example
/* in XS */static MGVTBL xst_id; /* the MAGIC identity */CV* xsub = newXS(name, xs_impl, file);HV* hv = newHV();MAGIC* mg;mg = sv_magic((SV*)xsub, (HV*)hv, PERL_MAGIC_ext,
&xst_id, NULL, 0);SvREFCNT_dec(hv);CvXSUBANY(xsub).any_ptr = (void*)hv; /* shortcut *//* ... */XS(xs_impl){
dVAR; dXSARGS;HV* hv = (HV*)XSANY.any_ptr; /* shortcut *//* ... */
}
That's all
Enjoy Perl MAGIC! Thank you for your attention.