develooper Front page | perl.perl5.porters | Postings from February 2001

[PATCH] XPUSH[insp] was Re: progress

Thread Next
Simon Cozens
February 26, 2001 04:24
[PATCH] XPUSH[insp] was Re: progress
Message ID:
On Sun, Feb 25, 2001 at 10:30:17PM -1000, Tim Jenness wrote:
>   The docs suggest XPUSHi as a good way of placing an integer on the
> stack. Similarly for XPUSHn and XPUSHp. What the docs *don't* say is that
> you can't put
>    XPUSHi(some_int);
>    XPUSHi(some_other_int);
> because the second XPUSHi overwrites the contents of the SV used for the
> first push! It may be obvious after looking at the defines (ie they all
> use a variable called TARG that does not change) but it took me a while to
> track it down. It is definitely not obvious in the docs. In fact the only
> way to do the above is something like:
>    XPUSHs(sv_2mortal(newSViv(some_int)));
>    XPUSHs(sv_2mortal(newSViv(some_other_int)));
> and funnily enough that is how all the functions put multiple values on
> the stack. That's how its always done and how I was going to do it in the
> example but scanning through the docs did not make it obvious *why* the
> simpler XPUSHi routines were not appropriate.

Hmm, you're right! XPUSH[npiu] seem to be only useful if you're pushing
one value on; in fact, you can't even say
because that would put the string on twice. Urgh.

Since this wouldn't work before, (and, naturally, neither would EXTEND +
PUSH*) I guess it's possible to change the behaviour of those definitions so
that they do allow multiple pushes. But then...

> It looks like the only reason XPUSHi is not defined as the above is
> because of the SETMAGIC halfway through the current definition.

Yes, the whole point of TARG is that you have "a value which is being assigned
to", and so when it changes, you need set magic.

Now it looks to me like something's horribly broken with XPUSH* because:
    * You can't use XPUSH[npiu] more than once.
    * If you use XPUSHs instead, you don't get set magic invoked.

If this inconsistency is meant, it *certainly* ought to be documented, but I
don't know if the code needs to change as well. I've copied P5P.

> (no mention of having to do a dTARG at the start of the function either -
> not in any of the docs).

Hm. I guess the implication would be that people futzing around with XPUSH*
would either be using a PPCODE section of XS, or dealing with the guts. (which
should already have dTARG defined.) Oh, well, that can be patched.

The following patch documents both issues:

--- perlguts.pod~	Mon Feb 26 12:14:40 2001
+++ perlguts.pod	Mon Feb 26 12:22:53 2001
@@ -1255,6 +1255,7 @@
 These macros automatically adjust the stack for you, if needed.  Thus, you
 do not need to call C<EXTEND> to extend the stack.
+However, see L</Putting a C value on Perl stack>
 For more information, consult L<perlxs> and L<perlxstut>.
@@ -1383,6 +1384,23 @@
 The macro to put this target on stack is C<PUSHTARG>, and it is
 directly used in some opcodes, as well as indirectly in zillions of
 others, which use it via C<(X)PUSH[pni]>.
+Because the target is reused, you must be careful when pushing multiple
+values on the stack. The following code will not do what you think:
+    XPUSHi(10);
+    XPUSHi(20);
+This translates as "set C<TARG> to 10, push a pointer to C<TARG> onto
+the stack; set C<TARG> to 20, push a pointer to C<TARG> onto the stack".
+At the end of the operation, the stack does not contain the values 10
+and 20, but actually contains two pointers to C<TARG>, which we have set
+to 20. If you need to push multiple different values, use C<XPUSHs>,
+which bypasses C<TARG>.
+On a related note, if you do use C<(X)PUSH[npi]>, then you're going to
+need a C<dTARG> in your variable declarations so that the C<*PUSH*>
+macros can make use of the local variable C<TARG>. 
 =head2 Scratchpads

<TorgoX> EFNet is like one big advertisement for lobotomies.

Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About