in reply to Re: Re: Re: aliasing
in thread aliasing

I think what's happening is that the original assignment @r = 1..1000000 is expanding perl's stack to accomodate a million entries. Then reverse @r doesn't require any additional space. But the million entries are still put on the stack and then assigned.

Replies are listed 'Best First'.
Re: Re: Re: Re: Re: aliasing
by BrowserUk (Patriarch) on Jan 13, 2004 at 01:06 UTC

    The relevant piece of code is this

    if (GIMME == G_ARRAY) { MARK++; while (MARK < SP) { tmp = *MARK; *MARK++ = *SP; *SP-- = tmp; } /* safe as long as stack cannot get extended in the above */ SP = oldsp; }

    which is roughly equivalent to

    ( $MARK, $SP ) = ( 0, $#array ); while( $MARK < $SP ) { $tmp = $array[ $mark ]; $array[ $MARK++ } = $array[ $SP ]; $array[ $SP-- ] = tmp; }

    which suggests that if the argument to reverse is a single array, rather than stack the array to create @_, the stack pointer is effectively pointed at the top of the array. This is born out (but not confirmed--I can;t find the relevant part of the source) by doing

    @r = reverse 1, @r;

    when substantial memory growth occurs. In this case, @_ has to be built fresh to incorporate the extra element.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Timing (and a little luck) are everything!

      Goodness knows, there are optimizations lurking that are hard to spot, and there may be one for the @r = reverse @r, but if so I don't see it.

      The above (in pp_reverse) is only executed after the array has been moved onto the stack, and in your pseudo-code, @array represents the stack, not the array being reversed. What you quote is the general code for any list-context reverse, which just reverses everything from the MARK showing the beginning of reverse's arguments to the SP stack pointer at the top of the stack.

      I'm intrigued that @r = reverse 1,@r seems to take more memory; how much more?

        how much more?
        P:\test>p1 # 2368k @r = 1 .. 1000000; # 62804k @r = reverse @r; # 62812k @r = reverse 1, @r; # 71020k

        I work that out at around 8MB, or 8 bytes per element. Just enough to build a single linked list of references to the scalars that constitute the elements of the array.

        The above (in pp_reverse) is only executed after the array has been moved onto the stack, and in your pseudo-code, @array represents the stack, not the array being reversed.

        Agreed. But the reversal, is done by reversing the order ot the linked list of pointers to the scalars. So, if the input argument is a single array, rather than copying the array's linked list onto the stack and set @_ to point to the copy.

        I speculate that the SP is pointed at the end of the linked-list that is the array argument, and the linked list is reversed in place. When the sub exits, and the SP is reset to its previous position, the array has been reversed in-situ with no copying to/from the stack required.

        That doesn't work when the extra element is passed to reverse, so it has to copy the new element + linked list from the array, to a new lump of memory before calling PP_reverse to re-order the new list. Afterwards, the stash entry for the array is pointed at the new list which was reversed in-situ, and the old list becomes available for garbage collection.

        The scalars that form the elements of the array never move at all.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        Timing (and a little luck) are everything!