Skip to content

Commit

Permalink
Extend OPpTARGET_MY optimisation to state var init
Browse files Browse the repository at this point in the history
ck_sassign does two things:

• See if $lexical = <some op> can have the assignment optimised away
  (OPpTARGET_MY/targlex).
• See if we have state $x = foo, which needs to run only once
  per closure.

The former optimisation is skipped for variable declarations (‘my $x
= time’), because ‘my $x’ does more than just return the SV at a pad
offset.  It also arranges for it to be cleared on scope exit.  That
does not apply to state variable.  The OPpLVAL_INTRO flag (indicating
the presence of ‘my’ or ‘state’ before the variable) has no run-time
effect on state vars, so there is no need to skip the optimisation
because of it.

That optimisation destroys the assignment operator and its lhs before
we get to the state var init code, which needs the lhs to do its
checks.  So we change the order that these checks happen, and make the
state var code invoke the optimisation itself.
  • Loading branch information
Father Chrysostomos committed Nov 11, 2014
1 parent 53fd57a commit a1b22ab
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 9 deletions.
4 changes: 3 additions & 1 deletion lib/B/Deparse.pm
Expand Up @@ -3215,7 +3215,9 @@ sub pp_once {
my $cond = $op->first;
my $true = $cond->sibling;

return $self->deparse($true, $cx);
my $ret = $self->deparse($true, $cx);
$ret =~ s/^(\(?)\$/$1 . $self->keyword("state") . ' $'/e;
$ret;
}

sub loop_common {
Expand Down
13 changes: 5 additions & 8 deletions op.c
Expand Up @@ -10155,7 +10155,8 @@ S_maybe_targlex(pTHX_ OP *o)

/* Can just relocate the target. */
if (kkid && kkid->op_type == OP_PADSV
&& !(kkid->op_private & OPpLVAL_INTRO))
&& (!(kkid->op_private & OPpLVAL_INTRO)
|| kkid->op_private & OPpPAD_STATE))
{
kid->op_targ = kkid->op_targ;
kkid->op_targ = 0;
Expand All @@ -10178,11 +10179,6 @@ Perl_ck_sassign(pTHX_ OP *o)

PERL_ARGS_ASSERT_CK_SASSIGN;

{
OP * const newop = S_maybe_targlex(aTHX_ o);
if (newop != o)
return newop;
}
if (OP_HAS_SIBLING(kid)) {
OP *kkid = OP_SIBLING(kid);
/* For state variable assignment with attributes, kkid is a list op
Expand All @@ -10199,7 +10195,8 @@ Perl_ck_sassign(pTHX_ OP *o)
kkid->op_flags
| ((kkid->op_private & ~OPpLVAL_INTRO) << 8));
OP *const first = newOP(OP_NULL, 0);
OP *const nullop = newCONDOP(0, first, o, other);
OP *const nullop =
newCONDOP(0, first, S_maybe_targlex(aTHX_ o), other);
OP *const condop = first->op_next;

CHANGE_TYPE(condop, OP_ONCE);
Expand All @@ -10215,7 +10212,7 @@ Perl_ck_sassign(pTHX_ OP *o)
return nullop;
}
}
return o;
return S_maybe_targlex(aTHX_ o);
}

OP *
Expand Down

0 comments on commit a1b22ab

Please sign in to comment.