如何通过 Nativecall 回调传递 Perl 6 对象?

How can I pass a Perl 6 object through a Nativecall callback?

我正在使用 NativeCall 界面。

库将多次调用我的回调函数。

效果很好。我可以用正确的方式声明我的回调 签名,将其作为 &callback 传入,库仅调用 sub 很好。

它也有能力设置一个 payload void *pointer 到任何东西 我想要,它会将其包含在对我的回调函数的调用中。

我可以在有效负载中隐藏一个 Perl Str 并成功往返吗?

sub set_userdata(Pointer) returns int32 is native { ... }

sub set_callback(&callback(Pointer $userdata --> int32)) returns int32 is native { ... }

sub callback(Pointer $userdata) returns int32 {
    my Str $mystring = ???
    ...
}

my Str $my-userdata-string;

set_userdata(???);
set_callback(&callback);

它似乎可以与一些绑定咒语一起使用,"is rw",nativecast() and/or .deref.

我通过忽略用户数据并为每个回调函数创建一个直接引用 Perl 对象的新闭包来解决这个问题。由于每次设置回调都会创建一个新的闭包,我认为这会随着时间的推移而泄漏内存。

在这种情况下您只能使用本机表示(例如 CStructCArrayCPointer),或者 Blob。您还负责确保从 Perl 6 的角度来看,您还保留对作为 userdata 传递的内容的引用,因此 GC 不会回收传递给 C 函数的内存。

内存管理是您不能将任何旧的 Perl 6 对象传递给 C 函数的原因:GC 无法知道该对象是否仍然可以通过它无法自省的某些 C 数据结构访问.在像 MoarVM 这样的 VM 中,对象也会随着时间的推移在内存中移动,这也是垃圾收集过程的一部分,这意味着 C 代码可能会以过时的指针结束。

另一种策略是根本不传递指针,而是传递一个整数并使用它来索引对象数组。 (这就是 MoarVM 内部的 libuv 绑定如何跟踪 VM 级回调,fwiw。)