re_intuit_start(): do 'not at start' check on BOL
authorDavid Mitchell <davem@iabyn.com>
Tue, 18 Mar 2014 21:32:39 +0000 (21:32 +0000)
committerDavid Mitchell <davem@iabyn.com>
Wed, 19 Mar 2014 18:25:54 +0000 (18:25 +0000)
The quick reject test that says "if a pattern has an absolute anchor,
then immediately reject if strpos != strbeg", currently skips that test
if PREGf_ANCH_GPOS is present. Instead, skip unless BOL or SBOL is present.

This means that something like /^abc\G/ will still do the quick reject
test.

I can't think of any example that will actually give a measurable
performance boost, and this is a fairly unlikely scenario, but the code is
more logical this way, and makes it more robust against future changes
(it's less likely to suddenly skip the quick test where it used to do it).

I've also updated the commentary on why we don't do a quick /\G/ test
akin to the /^/ test, and added some more info about why we test for the
PREGf_IMPLICIT flag.

And I've added an assert about PREGf_IMPLICIT too.

regexec.c

index e3ce022..b7ca27b 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -759,13 +759,24 @@ Perl_re_intuit_start(pTHX_
             /* we are only allowed to match at BOS or \G */
 
             /* trivially reject if there's a BOS anchor and we're not at BOS.
-             * In the case of \G, we hope(!) that the caller has already
-             * set strpos to pos()-gofs, and will already have checked
-             * that this anchor position is legal. So we can skip it here.
+             *
+             * Note that we don't try to do a similar quick reject for
+             * \G, since generally the caller will have calculated strpos
+             * based on pos() and gofs, so the string is already correctly
+             * anchored by definition; and handling the exceptions would
+             * be too fiddly (e.g. REXEC_IGNOREPOS).
+             *
+             * A note about IMPLICIT: on an un-anchored pattern beginning
+             * with /.*.../, these flags will have been added by the
+             * compiler:
+             *   /.*abc/, /.*abc/m:  PREGf_IMPLICIT | PREGf_ANCH_MBOL
+             *   /.*abc/s:           PREGf_IMPLICIT | PREGf_ANCH_SBOL
+             * so just the presence of SBOL isn't enough to guarantee
+             * that we're anchored.
              */
-            if (   !(prog->intflags & PREGf_ANCH_GPOS)
-                && !(prog->intflags & PREGf_IMPLICIT) /* not a real BOL */
-               && (strpos != strbeg))
+            if (   strpos != strbeg
+                && (prog->intflags & (PREGf_ANCH_BOL|PREGf_ANCH_SBOL))
+                && !(prog->intflags & PREGf_IMPLICIT)) /* not a real BOL */
             {
                DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
                                 "  Not at start...\n"));
@@ -789,6 +800,14 @@ Perl_re_intuit_start(pTHX_
                SSize_t slen = SvCUR(check);
                 char *s;
 
+                /* we only get here if there's a fixed substring (min ==
+                 * max). But PREGf_IMPLICIT only gets set if the regex
+                 * begins with /.*.../, and in that case there can't be
+                 * a fixed substring. So assert this truth. If anyone
+                 * changes this assumption (e.g. with lookahead/behind),
+                 * complain and let them fix it */
+                assert(!(prog->intflags & PREGf_IMPLICIT));
+
                s = HOP3c(strpos, prog->check_offset_min, strend);
            
                 DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,