1

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?
Schwern
  • 153,029
  • 25
  • 195
  • 336
  • 1
    I feel a bit dumb asking, but what's an `AV`? – Mr. Llama Nov 13 '14 at 21:56
  • A curious question, but before I try writing an answer I'd like to enquire why - specifically, do you want just a readable snapshot, or are you expecting to mutate either the values stored, or the array itself by pushing/popping it? – LeoNerd Nov 13 '14 at 22:25
  • @LeoNerd I'm creating an `autodie::exception->new` object inside a core function and it needs the list of arguments to the function as an array ref. autodie::exception uses the arguments to provide a good error message, the array and values will not be mutated... but they can be gotten at with `$@->args` and potentially changed by the caller. This is not a feature, and if they can be made read-only that would be fine. – Schwern Nov 13 '14 at 22:28
  • 2
    @Mr.Llama An AV is the Perl internal data type for an array. SV for scalars. HV for hashes. See http://perldoc.perl.org/perlguts.html#Variables – Schwern Nov 13 '14 at 22:29

1 Answers1

4

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.

Schwern
  • 153,029
  • 25
  • 195
  • 336