How emulate &sname call from XS?

85 Views Asked by At

How to emulate z sub behavior within XS sub?

package XS;
sub hello {
    print "ARGS: >>@_<<\n";
    my $lvl;
    while( my @frame =  caller( $lvl++ ) ) {
        print ">>@frame[0..4]<<\n";
    }
}

sub z {
    &hello;
}

In my .xs file I have:

void
call_perl() {
    call_pv( "XS::hello", G_NOARGS );    
}

void
test(...)
    CODE:
        call_perl();

But calling XS::test(1,2,3) do not pass any arguments to hello.

The output:

ARGS: >><<
>>main -e 1 XS::hello <<

Here we can see that $hasargs flag is not set because of G_NOARG flag, but why @_ is flushed? What did I miss?

UPD
Seems found an half of the answer.

  1. G_NOARGS flag

    has the effect of not creating the @_ array for the Perl subroutine.

  2. When XSUB is called the perl do not create the frame for it (can not remember where this is described) and do not fill @_ for it (this described indirectly here)

    XSUBs refer to their stack arguments with the macro ST(x)

So the more precise question will be:

How to propagate XSUB stack arguments to PP subroutine?

NOTICE: I can not just use:

call_pv( "XS::hello", 0 );

Because this is ordinal PP sub call. And when it returns the XSUB stack arguments will be replaced by a return value from XS::hello sub

int count =  call_pv( "XS::hello", 0 );
STAGAIN;
printf( "%s\n", SvPV_nolen( ST(0) ) );

So I supply G_NOARGS flag to be able to access XSUB stack arguments after call to PP sub

1

There are 1 best solutions below

0
On

Here is code for XSUB how it is done (NOTICE: I do not handle return arguments in this example):

test(...)
CODE:
    AV *defav_old =  GvAV(PL_defgv);   # Save current @_

    AV *av = newAV();                  # Create new array
    av_extend(av, items -1);          
    AvREIFY_only(av);
    AvFILLp(av) =  items -1;
    Copy(MARK+1, AvARRAY(av), items, SV*); # Fill array by elements from stack

    GvAV(PL_defgv) =  av;     # point @_ to our new array


    PUSHMARK(SP);
    int count =  call_pv( "XS::Utils::hello", G_VOID | G_NOARGS );

    GvAV(PL_defgv) =  defav_old;  # Restore old @_