develooper Front page | perl.perl5.porters | Postings from July 2009

maint-perl-5.10-RC0 and multicall API

Thread Next
From:
Tassilo von Parseval
Date:
July 28, 2009 16:04
Subject:
maint-perl-5.10-RC0 and multicall API
Message ID:
20090728230416.GA30329@localhost
Hi everyone,

I'm in need of a reliable way to access the old stack (PL_stack_sp)
after calling PUSH_MULTICALL but before the corresponding POP_MULTICALL
occurs. Here's a little background:

Version 0.24 of List-MoreUtils was failing its tests on 5.8.8 and the
maint-5.10 release candidate as was briefly discussed here:

http://www.nntp.perl.org/group/perl.perl5.porters/2009/07/msg149184.html

I was able to track down the problem on 5.8.8 and potentially older
versions that used the API provided by List::Util's multicall.h. The
pattern that was failing was this:

    PUSH_MULTICALL(cv);
    ...
    for(i = 1 ; i < items ; ++i) {
	GvSV(PL_defgv) = PL_stack_base[ax+i];
        ...

    POP_MULTICALL;

I found the culprit in the definition of PUSH_MULTICALL:

    CATCH_SET(TRUE);                        \
    PUSHSTACKi(PERLSI_SORT);                \
    PUSHBLOCK(cx, CXt_SUB, PL_stack_sp);    \
    MULTICALL_PUSHSUB(cx, multicall_cv);    \

The PUSHSTACKi call assigns to PL_stack_base so that PL_stack_base[ax+i]
no longer refers to the i-th element on the stack. This by the way also
renders ST(i) unusable which merely expands to PL_stack_base[ax+i]. 

The multicall stuff was added to cop.h in perl-5.8.9 where the above
looked different:

    CATCH_SET(TRUE);                                    \
    PUSHBLOCK(cx, CXt_SUB|CXp_MULTICALL, PL_stack_sp);  \
    PUSHSUB(cx);                                        \

Note that absensce of PUSHSTACKi. 

What I did was to modify List-MoreUtils's local version of multicall.h
to roughly do what perl-5.8.9's cop.h does.

Now with the main-5.10 release candidate, the PUSHSTACKi thing is back:

    CATCH_SET(TRUE);                                    \
    PUSHSTACKi(PERLSI_SORT);                            \
    PUSHBLOCK(cx, CXt_SUB|CXp_MULTICALL, PL_stack_sp);  \
    PUSHSUB(cx);                                        \

and indeed, virtually all of L-MU's functions bomb out right away
because the stack has moved. There are no issues with 5.10.0 so a change
between 5.10.0 and the release candidate must be responsible for the
change back to using PUSHSTACKi.

I assume there is a good reason for this. However, as it stands right
now, anything accessing PL_stack_base (which includes the officially
documented ST() API) after a call to PUSH_MULTICALL but before
POP_MULTICALL is in for a nasty surprise. The section on lightweight
callbacks in perlcall does not document this, by the way.

The obvious workaround:

    SV **args = &PL_stack_base[ax];
    ...
    PUSH_MULTICALL(cv);
    for(i = 1; i < items; ++i) {
        GvSV(PL_defgv) = newSVsv(args[i]);
        MULTICALL;
        args[i-1] = GvSV(PL_defgv);
    }
    POP_MULTICALL;

fails when the code-reference being called by MULTICALL grows the stack
in such a way that PL_stack_base has been moved to a different memory
location.

So what can I do? I have a solution that fails when PUSH_MULTICALL
assigns a new temporary stack to PL_stack_base and one that works around
that particular problem ('SV **args = &PL_stack_base[ax]' before
PUSH_MULTICALL) but cannot handle a stack growth that results in a
reallocation of PL_stack_base (which is what I presume happens).

I can make a shallow copy of the whole stack and use that but that would
be a significant loss in performance which defeats the purpose of
multicall.

Cheers,
Tassilo
-- 
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval 

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About