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

Reply via email to