Skip to content

Commit

Permalink
RT 131898: Fix native closures failing on the second run
Browse files Browse the repository at this point in the history
On the first call of a native sub we create a new subroutine body and replace
the original (stored in the routine's $!do attribute). We also set the
invocation spec so the body will be called instead of the CALL-ME method. This
invocation spec is shared between an original routine and it's clones. If the
routine is a clousre, the body won't be shared as only a clone of the routine
will be actually visible in the lexical scope. So until someone comes up with
a better idea, we won't create an optimized version for a closure anymore.
  • Loading branch information
niner committed Aug 16, 2017
1 parent 435f7e3 commit 9a0afcb
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 2 deletions.
11 changes: 10 additions & 1 deletion lib/NativeCall.pm6
Expand Up @@ -298,6 +298,7 @@ my role Native[Routine $r, $libname where Str|Callable|List|IO::Path|Distributio
has $!cpp-name-mangler;
has Pointer $!entry-point;
has int $!arity;
has $!is-clone;

method !setup() {
$setup-lock.protect: {
Expand Down Expand Up @@ -403,9 +404,17 @@ my role Native[Routine $r, $libname where Str|Callable|List|IO::Path|Distributio
}
}

method clone() {
my $clone := callsame;
nqp::bindattr($clone, $?CLASS, '$!is-clone', 1);
$clone
}

method CALL-ME(|args) {
self!setup();
self!create-optimized-call() unless $*W; # Avoid issues with compiling specialized version during BEGIN time
self!create-optimized-call() unless
$!is-clone # Clones and original would share the invokespec but not the $!do attribute
or $*W; # Avoid issues with compiling specialized version during BEGIN time

my Mu $args := nqp::getattr(nqp::decont(args), Capture, '@!list');
if nqp::elems($args) != $!arity {
Expand Down
10 changes: 9 additions & 1 deletion t/04-nativecall/01-argless.t
Expand Up @@ -5,7 +5,7 @@ use CompileTestLib;
use NativeCall;
use Test;

plan 3;
plan 5;

compile_test_lib('01-argless');

Expand All @@ -20,3 +20,11 @@ pass 'survived the call';
is Argless(), 2, 'called argless function';

is short(), 3, 'called long_and_complicated_name';

sub test-native-closure() {
my sub Argless() is native('./01-argless') returns int32 { * }
is Argless(), 2, 'called argless closure';
}

test-native-closure();
test-native-closure(); # again cause we may have created an optimized version to run

0 comments on commit 9a0afcb

Please sign in to comment.