This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Don’t call intuit_method twice for the same barewords
authorFather Chrysostomos <sprout@cpan.org>
Thu, 4 Sep 2014 01:21:18 +0000 (18:21 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Thu, 4 Sep 2014 02:07:54 +0000 (19:07 -0700)
This calls intuit_method once:

    sub fooo; print foo bar

This calls it twice:

    sub foo; print foo bar

because seeing whether we are dealing with a bareword after ‘print’,
‘say’ etc. must happen *before* we look past the space after ‘foo’ to
see whether ‘foo bar’ could be a method call.  That’s because skipping
a space could reset the internal variables that track whether we have
just seen ‘print’.

Hence, we end up with a call to intuit_method (i.e., is this a
method?) inside the block that deals with print FOO.

But then we have another call to intuit_method later that deals with
the non-print cases.

But the former can fall through to the latter if we don’t have a
method call here.  And then intuit_method is called again with exactly
the same arguments.  So we just repeat the check needlessly.

Avoiding the call the second time (if we have already called it above)
will allow the next commit to put a GV lookup that occurs only for the
sake of intuit_method directly inside intuit_method, avoiding the need
for that lookup for most barewords.

toke.c

diff --git a/toke.c b/toke.c
index 4471f52..fec45dd 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -6564,6 +6564,10 @@ Perl_yylex(pTHX)
                        : rv2cv_op_cv(rv2cv_op, RV2CVOPCV_RETURN_STUB);
                }
 
+               /* Use this var to track whether intuit_method has been
+                  called.  intuit_method returns 0 or > 255.  */
+               tmp = 1;
+
                /* See if it's the indirect object for a list operator. */
 
                if (PL_oldoldbufptr &&
@@ -6662,7 +6666,7 @@ Perl_yylex(pTHX)
 
                /* If followed by a bareword, see if it looks like indir obj. */
 
-               if (!orig_keyword
+               if (tmp == 1 && !orig_keyword
                        && (isIDFIRST_lazy_if(s,UTF) || *s == '$')
                        && (tmp = intuit_method(s, gv, cv))) {
                    op_free(rv2cv_op);