Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
"$foo.bar += 1234" should only call $foo.bar once
Besides being more correct, is also much faster, since we're calling the
(potentially high-load) function half as often.

timotimo++ for assistance
  • Loading branch information
Mouq committed Jun 6, 2015
1 parent 501bad2 commit 2ea7d3c
Showing 1 changed file with 22 additions and 9 deletions.
31 changes: 22 additions & 9 deletions src/Perl6/Optimizer.nqp
Expand Up @@ -1371,6 +1371,8 @@ class Perl6::Optimizer {
|| ($op[1].op eq 'hllize'
&& nqp::istype($op[1][0], QAST::Op) && $op[1][0].op eq 'callmethod'))) {
my str $assignop;
my $assignee;
my $assignee_var;
if $is_var {
my str $sigil := nqp::substr($op[1].name, 0, 1);

Expand All @@ -1383,31 +1385,42 @@ class Perl6::Optimizer {
# TODO check what else we need to "copy" from assign_op in Actions
return NQPMu;
}

$assignee := $assignee_var := $op[1];
} else {
$assignop := "assign";

# We want to be careful to only call $foo.bar once,
# so we bind to a local var and assign to that.
my $lhs_ast := $op[1];
my $target_name := QAST::Node.unique('METAOP_assign_');
$assignee := QAST::Op.new( :op('bind'),
QAST::Var.new(:name($target_name), :scope('local'), :decl('var')),
$lhs_ast);
$assignee_var := QAST::Var.new(:name($target_name), :scope('local'));

}

# since the optimizer will only ever walk the first
# branch of a Want node, we have to make sure to change
# the node in place, since it's most likely shared with
# the other branch.
$op.op($assignop);
my $target_var := $op[1];
my $operand := $op[2];
my $operand := $op[2];

$op.pop;
$op.pop;
$op.pop;

$op.push($target_var);
$op.push($assignee);
$op.push(QAST::Op.new( :op('call'), :name($metaop[0].name),
QAST::Op.new( :op('defor'), :name('&infix:<//>'),
$target_var,
QAST::Op.new( :op('call'), :name($metaop[0].name) ) ),
$operand));
QAST::Op.new( :op('defor'), :name('&infix:<//>'),
$assignee_var,
QAST::Op.new( :op('call'), :name($metaop[0].name) ) ),
$operand));

if $assignop ne 'assign' && nqp::objprimspec($target_var.returns) {
$op.returns($target_var.returns);
if $assignop ne 'assign' && nqp::objprimspec($assignee.returns) {
$op.returns($assignee.returns);
}
}
}
Expand Down

0 comments on commit 2ea7d3c

Please sign in to comment.