Skip to content

Commit

Permalink
Revert "Revert "Use a spesh plugin to optimize .?""
Browse files Browse the repository at this point in the history
This reverts commit 65dccd8.
  • Loading branch information
AlexDaniel committed Jun 16, 2018
1 parent 2a16dd4 commit 708c132
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/Perl6/Optimizer.nqp
Expand Up @@ -1397,6 +1397,9 @@ class Perl6::Optimizer {
elsif $op.name eq 'dispatch:<::>' {
return self.optimize_qual_method_call: $op;
}
elsif $op.name eq 'dispatch:<.?>' {
return self.optimize_maybe_method_call: $op;
}
}

if $op.op eq 'chain' {
Expand Down Expand Up @@ -2104,6 +2107,49 @@ class Perl6::Optimizer {
return $op;
}

method optimize_maybe_method_call($op) {
# Spesh plugins only available on MoarVM.
return $op unless nqp::getcomp('perl6').backend.name eq 'moar';

# 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];
}
return $op unless nqp::istype($name_node, QAST::SVal);

# We need to evaluate the invocant only once, so will bind it into
# a temporary.
my $inv := $op.shift;
my $name := $op.shift;
my @args;
while $op.list {
nqp::push(@args, $op.shift);
}
my $temp := QAST::Node.unique('inv_once');
$op.op('stmts');
$op.push(QAST::Op.new(
:op('bind'),
QAST::Var.new( :name($temp), :scope('local'), :decl('var') ),
$inv
));
$op.push(QAST::Op.new(
:op('call'),
QAST::Op.new(
:op('speshresolve'),
QAST::SVal.new( :value('maybemeth') ),
QAST::Op.new(
:op('decont'),
QAST::Var.new( :name($temp), :scope('local') )
),
$name,
),
QAST::Var.new( :name($temp), :scope('local') ),
|@args
));
return $op;
}

method optimize_for_range($op, $callee, $c2) {
my $code := $callee.ann('code_object');
my $count := $code.count;
Expand Down
19 changes: 19 additions & 0 deletions src/vm/moar/spesh-plugins.nqp
@@ -1,3 +1,6 @@
## Method plugins
## Only used when the name is a constant at the use site!

# 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.
Expand All @@ -24,3 +27,19 @@ nqp::speshreg('perl6', 'qualmeth', -> $obj, str $name, $type {
}
}
});

# A call like `$obj.?foo` is probably worth specializing via the plugin. In
# some cases, it will be code written to be generic that only hits one type
# of invocant under a given use case, so we can handle it via deopt. Even if
# there are a few different invocant types, the table lookup from the guard
# structure is still likely faster than the type lookup. (In the future, we
# should consider an upper limit on table size for the really polymorphic
# things).
sub discard-and-nil(*@pos, *%named) { Nil }
nqp::speshreg('perl6', 'maybemeth', -> $obj, str $name {
nqp::speshguardtype($obj, $obj.WHAT);
my $meth := $obj.HOW.find_method($obj, $name);
nqp::isconcrete($meth)
?? $meth
!! &discard-and-nil
});

0 comments on commit 708c132

Please sign in to comment.