Permalink
Browse files

Use a MoarVM spesh plugin for private method calls

For those that we can resolve trivially already because the call is
in a class, we simply do so. However, private method calls in roles
have so far been greatly slower, due to a lack of caching and since
the specializer had no idea how to optimize them even if it could.

With this spesh plugin, a module PM.pm6:

    role R {
        method m() { self!p }
        method !p() { 42 }
    }
    class C does R {
    }
    for ^10_000_000 {
        C.m;
    }

When run with `perl6 -I. -e 'use PM6'` will run in 0.83s, compared to
5.5s before, making private method calls in roles around 6.6x faster.

Note that due to the way roles are handled in non-precompiled code,
the rewrite in Perl6::Optimizer (nor any others in there) will not take
effect in a script, thus the module.
  • Loading branch information...
jnthn committed Jun 8, 2018
1 parent 148d7c5 commit 51ff83c7ca90af8fbe40acaad728c6fa79f65b76
Showing with 41 additions and 4 deletions.
  1. +29 −1 src/Perl6/Optimizer.nqp
  2. +7 −0 src/vm/moar/spesh-plugins.nqp
  3. +5 −3 tools/build/Makefile-Moar.in
View
@@ -1998,12 +1998,20 @@ class Perl6::Optimizer {
}
method optimize_private_method_call($op) {
# We can only optimize if we have a compile-time-known name.
my $name_node := $op[1];
if nqp::istype($name_node, QAST::Want) && $name_node[1] eq 'Ss' {
$name_node := $name_node[2];
}
unless (nqp::istype($name_node, QAST::SVal)) {
return 0;
}
# For private method calls within a class, we can try to resolve them
# at this point. If they are missing, that's an error. In a role, this
# optimization won't help.
my $pkg_node := $op[2];
if nqp::istype($name_node, QAST::SVal) && $pkg_node.has_compile_time_value {
if $pkg_node.has_compile_time_value {
my str $name := $name_node.value; # get raw string name
my $pkg := $pkg_node.returns; # actions sets this unless in role
if nqp::can($pkg.HOW, 'find_private_method') {
@@ -2020,15 +2028,35 @@ class Perl6::Optimizer {
$op.unshift($call);
$op.op('call');
$op.name(NQPMu);
return 1;
}
}
else {
$!problems.add_exception(['X', 'Method', 'NotFound'], $op,
:private(nqp::p6bool(1)), :method($name),
:typename($pkg.HOW.name($pkg)), :invocant($pkg));
return 1;
}
}
}
# If resolution didn't work out this way, and we're on the MoarVM
# backend, use a spesh plugin to help speed it up.
if nqp::getcomp('perl6').backend.name eq 'moar' {
my $inv := $op.shift;
my $name := $op.shift;
my $pkg := $op.shift;
$op.unshift($inv);
$op.unshift(QAST::Op.new(
:op('speshresolve'),
QAST::SVal.new( :value('privmeth') ),
$pkg,
$name
));
$op.op('call');
$op.name(NQPMu);
return 1;
}
}
method optimize_for_range($op, $callee, $c2) {
@@ -0,0 +1,7 @@
# Private method resolution can be specialized based on invocant type. This is
# used for speeding up resolution of private method calls in roles; those in
# classes can be resolved by static optimization.
nqp::speshreg('perl6', 'privmeth', -> $obj, str $name {
nqp::speshguardtype($obj, $obj.WHAT);
$obj.HOW.find_private_method($obj, $name)
});
@@ -50,6 +50,8 @@ M_PERL6_LANG_OUTPUT = \
M_METAMODEL_SOURCES = $(COMMON_BOOTSTRAP_SOURCES)
M_BOOTSTRAP_SOURCES = $(BOOTSTRAP_SOURCES) src/vm/moar/spesh-plugins.nqp
# The ordering here is important for bootstrapping reasons. In general:
# * traits almost certainly have to come first
# * stubs have to come after traits since they use them
@@ -148,7 +150,7 @@ $(PERL6_C_MOAR): src/Perl6/Compiler.nqp $(PERL6_O_MOAR)
$(M_NQP) --module-path=blib --target=mbc --output=$(PERL6_C_MOAR) --encoding=utf8 \
src/Perl6/Compiler.nqp
$(PERL6_MOAR): src/main.nqp $(PERL6_G_MOAR) $(PERL6_A_MOAR) $(PERL6_C_MOAR) $(PERL6_P_MOAR) $(M_METAMODEL_SOURCES) $(BOOTSTRAP_SOURCES) $(M_CORE_SOURCES) $(M_CORE_D_SOURCES)
$(PERL6_MOAR): src/main.nqp $(PERL6_G_MOAR) $(PERL6_A_MOAR) $(PERL6_C_MOAR) $(PERL6_P_MOAR) $(M_METAMODEL_SOURCES) $(M_BOOTSTRAP_SOURCES) $(M_CORE_SOURCES) $(M_CORE_D_SOURCES)
$(PERL5) tools/build/gen-version.pl $(PREFIX) $(LIBDIR) > $(M_BUILD_DIR)/main-version.nqp
$(M_NQP) $(M_GEN_CAT) src/main.nqp $(M_BUILD_DIR)/main-version.nqp > $(M_BUILD_DIR)/main.nqp
$(M_NQP) --module-path=blib --target=mbc --output=$(PERL6_MOAR) \
@@ -159,8 +161,8 @@ $(PERL6_M_MOAR): $(M_METAMODEL_SOURCES) $(PERL6_OPS_MOAR)
$(M_NQP) --module-path=blib --target=mbc --output=$(PERL6_M_MOAR) --encoding=utf8 \
$(M_BUILD_DIR)/Metamodel.nqp
$(PERL6_B_MOAR): $(BOOTSTRAP_SOURCES) $(PERL6_M_MOAR)
$(M_NQP) $(M_GEN_CAT) $(BOOTSTRAP_SOURCES) > $(M_BUILD_DIR)/BOOTSTRAP.nqp
$(PERL6_B_MOAR): $(M_BOOTSTRAP_SOURCES) $(PERL6_M_MOAR)
$(M_NQP) $(M_GEN_CAT) $(M_BOOTSTRAP_SOURCES) > $(M_BUILD_DIR)/BOOTSTRAP.nqp
$(M_NQP) --module-path=blib --target=mbc --output=$(PERL6_B_MOAR) --encoding=utf8 \
--vmlibs=$(M_PERL6_OPS_DLL)=Rakudo_ops_init $(M_BUILD_DIR)/BOOTSTRAP.nqp

0 comments on commit 51ff83c

Please sign in to comment.