Skip to content

Commit

Permalink
Speed up setup of NativeCall subs and reduce memory usage
Browse files Browse the repository at this point in the history
When replacing a native sub's stub body with a generated one, we need to remove
the scheduled fixups, lest they undo our replacement. The easiest way to do
this is to just run the compiler thunk, which takes care of this after dynamic
compilation. This however is a very expensive operation as it not only compiles
that body but has to create setup code for the lexical scope. This makes
compiling a computation unit containing native subs scale O(n^2) with the
number of native subs in the lexical scope.

We can avoid this by doing a more targeted removal of the stub code.
This speeds up compiling a comp unit containing some 3K native subs from almost
5 minutes to just 2 1/2 minutes and reduces memory usage from 16 GiB to 8 GiB.
  • Loading branch information
niner committed Jun 5, 2021
1 parent 0de28ae commit 3b7fef2
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 10 deletions.
8 changes: 1 addition & 7 deletions lib/NativeCall.rakumod
Expand Up @@ -578,8 +578,7 @@ our role Native[Routine $r, $libname where Str|Callable|List|IO::Path|Distributi

# finish compilation of the original routine so our changes won't
# become undone right afterwards
my Mu \compstuff := nqp::getattr(self, Code, q<@!compstuff>);
compstuff[1]() unless nqp::isnull(compstuff);
$*W.unstub_code_object(self, Code) if $*W;

my $replacement := -> |args {
self.create-optimized-call() unless
Expand All @@ -594,11 +593,6 @@ our role Native[Routine $r, $libname where Str|Callable|List|IO::Path|Distributi
nqp::nativecall($!rettype, self, $args)
};

if $*W { # prevent compile_in_context from undoing our replacement
my $cuid := nqp::getcodecuid(nqp::getattr(self, Code, '$!do'));
nqp::deletekey($*W.context().sub_id_to_code_object(), $cuid);
}

my $do := nqp::getattr($replacement, Code, '$!do');
nqp::bindattr(self, Code, '$!do', $do);
nqp::setcodename($do, $!name);
Expand Down
26 changes: 23 additions & 3 deletions src/Perl6/World.nqp
Expand Up @@ -2682,11 +2682,11 @@ class Perl6::World is HLL::World {
# do dynamic compilation.
%!code_object_fixup_list{$cuid} := $fixups;
}

# Stash the QAST block in the comp stuff.
@compstuff[0] := $code_past;
}

# Stash the QAST block in the comp stuff.
@compstuff[0] := $code_past;

# If this is a dispatcher, install dispatchee list that we can
# add the candidates too.
if $is_dispatcher {
Expand Down Expand Up @@ -2982,6 +2982,26 @@ class Perl6::World is HLL::World {
# asked to compile.
$result
}
method unstub_code_object($code, $code_type) {
my @compstuff := nqp::getattr($code, $code_type, q<@!compstuff>);
unless nqp::isnull(@compstuff) {
my $subid := @compstuff[0].cuid;

nqp::bindattr($code, $code_type, '@!compstuff', nqp::null());

my %sub_id_to_sc_idx := self.context().sub_id_to_sc_idx();
my $code_ref := nqp::getattr($code, $code_type, '$!do');
if nqp::existskey(%sub_id_to_sc_idx, $subid) {
nqp::markcodestatic($code_ref); # maybe $!do instead
self.update_root_code_ref(%sub_id_to_sc_idx{$subid}, $code_ref);
}
if nqp::existskey(%!code_object_fixup_list, $subid) {
my $fixups := %!code_object_fixup_list{$subid};
$fixups.pop() while $fixups.list;
}
nqp::deletekey(self.context().sub_id_to_code_object(), $subid);
}
}
method try_add_to_sc($value, $fallback) {
if nqp::isnull($value) {
return $fallback;
Expand Down

0 comments on commit 3b7fef2

Please sign in to comment.