How do I turn the Perl stack into an AV?

111 views Asked by At

NOTE: This is a question about the Perl internals, the C code itself.

I want to pass the contents of the Perl stack (ie. SP) as an array to a Perl function.

  1. Is there an existing way to copy the stack into an AV?
  2. If not, how would one accomplish it? The array can be read-only.
  3. How does one turn an AV into a reference?
1

There are 1 answers

0
Schwern On

Found the crib I was looking for in pp_anonlist in pp.c

dVAR; dSP; dMARK;
const I32 items = SP - MARK;
SV * const args = MUTABLE_SV(av_make(items, MARK+1));
SPAGAIN;

mXPUSHs(newRV_noinc(args));

It took me a great number of tries before I finally settled on this:

#define NUMARGS         (SP - (PL_stack_base + TOPMARK))

AV *
Perl_get_args(pTHX) {
    dSP;
    AV * args;

    args = av_make(NUMARGS, SP - NUMARGS + 1);

    return args;
}

This is similar to pp_anonlist, but not quite. dMARK expands to SV **mark = PL_stack_base + (*PL_markstack_ptr--). MARK is used extensively but is ill defined in the documentation. Because dMARK modifies the state of the stack, it is unusable in my function which should have no side effects. TOPMARK is just *PL_markstack_ptr, no decrement. NUMARGS is effectively SP - MARK without the side effect.

SP points at the top of the stack, but av_make() works on lists. So it's necessary to pass in SP - NUMARGS to ensure av_make() can read two items off the stack. Why its necessary to add one, I'm not sure.