This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
regcomp.c: shrink some optimized [class] nodes
authorKarl Williamson <public@khwilliamson.com>
Sat, 7 Jul 2012 17:46:40 +0000 (11:46 -0600)
committerKarl Williamson <public@khwilliamson.com>
Wed, 25 Jul 2012 03:13:46 +0000 (21:13 -0600)
Various bracketed character class specifications don't need the full
generality, and can be optimized into smaller, faster nodes.  Recent
commits, such as 3a64b5154fffec75126d34d25954f0aef30d9f8a have
introduced some such optimizations.  However, their commit messages are
wrong, in that they don't end taking up any less space than the original
ANYOF node, as there is no provision for giving it back, once reserved.

This commit corrects that for non-locale nodes.  Restructuring of the
code, more than I care to do now, would be required to extend this to
locale nodes.

Only optimizations that are determined in pass1 of the regex compilation
are eligible for this, as once the space is calculated, it is reserved
before pass2 begins.  There are now two sections where optimization is
done in this routine.  The final section is after all the data is
examined and processed, and we know exactly what is to be in the ANYOF
node.  Currently, most of this calculation processing is skipped in pass
1.  We could do everything in both passes, greatly slowing down the
first, in order to figure out the exact space requirements.

But instead, I've chosen to add a separate optimization section that
looks at only the optimizations that are easily computable in the
current first pass, and to apply those early, in time for the shrinking
to occur.  This commit adds that shrinking.

Locale nodes can't be shrunk because the code currently writes into
their larger buffer before this decision to optimize is made.  To
illustrate, say that the node is at the end of the regex, and the data
is written at x+20, within a generic locale ANYOF node's space.  Pass 1
doesn't write anything, but calculates the space needed.  At the point
that this commit addresses, we would shrink the amount of space to be
allocated to be allocated.  Then we carve out space for the regex from
the heap.  That x+20 could be pointing to something entirely different,
which Pass 2 would destroy.  This can be avoided by storing the stuff
that would be written into a temporary until the optimization decision
has been made.  But there is extra work involved in doing this, that I
don't think is worth it at this time.

The same problem doesn't occur in non-locale situations, even though the
flags field of the node is written before the optimization decision.
This is because every node has the space for a flags field, so it just
gets overwritten as necessary when the optimization is done.

regcomp.c

index d5d1cb9..fa407c4 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -11113,6 +11113,7 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, U32 depth)
     regnode * const orig_emit = RExC_emit; /* Save the original RExC_emit in
         case we need to change the emitted regop to an EXACT. */
     const char * orig_parse = RExC_parse;
+    const I32 orig_size = RExC_size;
     GET_RE_DEBUG_FLAGS_DECL;
 
     PERL_ARGS_ASSERT_REGCLASS;
@@ -11882,7 +11883,19 @@ parseit:
              * the parse */
             const char * cur_parse = RExC_parse;
             RExC_parse = (char *)orig_parse;
-            RExC_emit = (regnode *)orig_emit;
+            if ( SIZE_ONLY) {
+                if (! LOC) {
+
+                    /* To get locale nodes to not use the full ANYOF size would
+                     * require moving the code above that writes the portions
+                     * of it that aren't in other nodes to after this point.
+                     * e.g.  ANYOF_CLASS_SET */
+                    RExC_size = orig_size;
+                }
+            }
+            else {
+                RExC_emit = (regnode *)orig_emit;
+            }
 
             ret = reg_node(pRExC_state, op);