如何从XS模拟和调用?

时间:2018-01-19 22:09:49

标签: perl perl-xs perlapi

如何在z sub?

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

sub z {
    &hello;
}

在我的.xs文件中,我有:

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

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

但是调用XS::test(1,2,3)不会将任何参数传递给hello

输出:

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

在这里,我们可以看到由于$hasargs标志未设置G_NOARG标志,但为什么@_被刷新?我错过了什么?

UPD
似乎找到了答案的一半。

  1. G_NOARGS标志

      

    具有不为Perl子例程创建@_数组的效果。

  2. 当调用XSUB时,perl不为它创建框架(不记得在何处描述)并且不为其填充@_(这是间接描述的 here

      

    XSUB使用宏ST(x)

    引用它们的堆栈参数
  3. 所以更准确的问题是:

    如何将XSUB堆栈参数传播到PP子例程?

    注意:我不能只使用:

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

    因为这是序数PP子调用。当它返回XSUB堆栈时,参数将被XS::hello sub

    的返回值替换
    int count =  call_pv( "XS::hello", 0 );
    STAGAIN;
    printf( "%s\n", SvPV_nolen( ST(0) ) );
    

    所以我提供G_NOARGS标志,以便在调用XSUB sub

    之后能够访问PP堆栈参数

1 个答案:

答案 0 :(得分:1)

以下是XSUB代码的完成方式(注意:我不处理此示例中的返回参数):

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 @_