Tassilo von Parseval <[EMAIL PROTECTED]> writes: >Hi, > >for a pairwise-map, thusly: > > my @c = pairwise { $a + $b } @a, @b; > >I have written an XSUB that I think is doing dangerous stuff with the >Perl stack. Here's the gist of it: > >PROTOTYPE: &[EMAIL PROTECTED]@ > > SV *code; /* codeblock argument */ > AV *avs[2]; /* holds the two arrays passed by reference */ > SV **oldsp; > > ... > EXTEND(SP, maxitems); > oldsp = PL_stack_base; > ENTER; > for (i = 0; i < maxitems; i++) { > SV **svp = av_fetch(avs[0], i, FALSE); > GvSV(PL_firstgv) = svp ? *svp : &PL_sv_undef; > svp = av_fetch(avs[1], i, FALSE); > GvSV(PL_secondgv) = svp ? *svp : &PL_sv_undef; > PUSHMARK(SP); > PUTBACK; > call_sv(code, G_EVAL|G_SCALAR); > SPAGAIN; > SvREFCNT_inc(*PL_stack_sp++); > } > PL_stack_base = oldsp; > LEAVE; > XSRETURN(maxitems); > >My goal was to avoid the safe but stupid way of allocating an array of >'maxitems' SVs in which I temporarily store the return value of the >codeblock and later copy that down to SP. > >Instead I came up with the above after many unsuccesful attempts of >avoiding copying any SVs. I store PL_stack_base's address in a safe >place.
But perl may re-alocate stack because 'code' pushes a log of things and free() the old one. Then your PL_stack_base = oldsp; leaves perl with its stack in memory which is possibly re-used for something else. This kind of thing is what PPCODE is _for_. PPCODE pops all the incoming args leaving SP pointing at where return values should go. You can XPUSH these, or get call_sv() to put them there So something like PPCODE: { for (...) { PUSHMARK(SP); PUTBACK; count = call_sv(...); // can handle list return too SPAGAIN; SP += count; } PUTBACK; // XSRETURN* just set SP and then return we have done SP stuff so ... return; } Should do the right thing. Or you could track total count and call XS_RETURN(n); >In the for-loop I advance PL_stack_sp to the position where the >return value of 'code' shall appear in the return list. That way, 'code' >will directly put its return value into this position and afterwards I >just have to increment its refcount I am not sure you do, called code will have set refcount and mortal-ness for one use by its "caller" - you can just pass that on to your caller. >(that's the reason why I don't use >the customary SAVETMPS/FREETMPS couple here). Finally I restore the old >PL_stack_base pointer. That is possibly wrong. > >How robust is this approach? Empirical tests say it's ok but then, I >don't really understand the perl stack stuff very well. I tried to mimic >what perl's map does, but I don't understand at all what pp_mapwhile is >doing. > >Cheers, >Tassilo