Skip to content

Instantly share code, notes, and snippets.

@niner
Last active September 1, 2018 13:47
Show Gist options
  • Save niner/53c4da1355802e042139ee05a1d7895b to your computer and use it in GitHub Desktop.
Save niner/53c4da1355802e042139ee05a1d7895b to your computer and use it in GitHub Desktop.

When a string is passed to a native sub, it will be encoded (UTF-8 by default) into a NULL delimited C string. This C string will be free()'d immediately after the native sub returns.

Some native subs expect to gain ownership on the passed string and will call free() on it themselves. In that case the argument must be marked explicitly-managed:

sub foo(Str $s is explicitly-managed) is native("foo") { * }

In other cases the native sub will just store the pointer and expect it to be still accessible to other native subs after it returns. The explicitly-managed trait can be used for that if either:

  • some other native sub will free() the string later on or
  • we expect the string to live indefinitely

Note however that each call to a native sub will cause a new C string to be created, even if the argument is marked explicitly-managed.

If the same C string needs to be used over several native calls, but eventually freed by the Perl 6 runtime, the explicitly-managed trait will therefore not be enough. Instead, the Perl 6 string must be encoded into a character array explicitly. That's done by using the encode() method and adjusting the native sub's signature to take a blob. There's one more caveat however. The VM is free to move objects in memory (e.g. for generational GC). If we want to use the same pointer in multiple calls, we need to explicitly request stability by using the stable trait on the argument and by calling explicitly-manage() and using the return value:

sub foo(utf8 $s is stable) is native("foo") { * }
my $blob = explicitly-manage("some string".encode);
foo($blob);
foo($blob);

If the same C string needs to be used over several native calls and will also be free()'d by one of them, it must be detached from Perl 6's garbage collection. This can be done by passing the :!free argument to explicitly-manage():

sub foo(utf8 is stable $s) is native("foo") { * }
sub free-the-foo(utf8 is stable $s) is native("foo") { * }
my $blob = explicitly-manage("some string".encode, :!free);
foo($blob);
free-the-foo($blob);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment