[Pcre-svn] [1440] code/trunk: Improve pattern prefix search …

Top Page
Delete this message
Author: Subversion repository
Date:  
To: pcre-svn
Subject: [Pcre-svn] [1440] code/trunk: Improve pattern prefix search by a simplified Boyer-Moore algorithm in JIT .
Revision: 1440
          http://vcs.pcre.org/viewvc?view=rev&revision=1440
Author:   zherczeg
Date:     2014-01-11 21:54:20 +0000 (Sat, 11 Jan 2014)


Log Message:
-----------
Improve pattern prefix search by a simplified Boyer-Moore algorithm in JIT.

Modified Paths:
--------------
    code/trunk/ChangeLog
    code/trunk/pcre_jit_compile.c
    code/trunk/testdata/testinput2
    code/trunk/testdata/testoutput2


Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog    2014-01-10 16:25:55 UTC (rev 1439)
+++ code/trunk/ChangeLog    2014-01-11 21:54:20 UTC (rev 1440)
@@ -52,7 +52,8 @@
     bracket.


 11. Empty match is not possible, when the minimum length is greater than zero,
-    and there is no \K in the pattern. Remove these unnecessary checks form JIT.
+    and there is no \K in the pattern. JIT should avoid empty match checks in
+    such cases.


 12. In a caseless character class with UCP support, when a character with more
     than one alternative case was not the first character of a range, not all
@@ -64,7 +65,11 @@
     enabled. This is not used in Windows, so I have put this test inside a 
     check for the presence of windows.h (which was already tested for).


+12. Improve pattern prefix search by a simplified Boyer-Moore algorithm in JIT.
+    The algorithm provides a way to skip certain starting offsets, and usually
+    faster than linear prefix searches.


+
Version 8.34 15-December-2013
-----------------------------


Modified: code/trunk/pcre_jit_compile.c
===================================================================
--- code/trunk/pcre_jit_compile.c    2014-01-10 16:25:55 UTC (rev 1439)
+++ code/trunk/pcre_jit_compile.c    2014-01-11 21:54:20 UTC (rev 1440)
@@ -3345,9 +3345,9 @@
       chars[0] = mask;
       chars[1] = mask;


+      consumed++;
       if (--max_chars == 0)
         return consumed;
-      consumed++;
       chars += 2;
       }
     while (--repeat > 0);
@@ -3396,7 +3396,11 @@
         chr |= mask;
         }


+#ifdef COMPILE_PCRE32
+      if (chars[0] == NOTACHAR && chars[1] == 0)
+#else
       if (chars[0] == NOTACHAR)
+#endif
         {
         chars[0] = chr;
         chars[1] = mask;
@@ -3410,9 +3414,9 @@
         }


       len--;
+      consumed++;
       if (--max_chars == 0)
         return consumed;
-      consumed++;
       chars += 2;
       cc++;
       }
@@ -3432,6 +3436,7 @@
 }


#define MAX_N_CHARS 16
+#define MIN_RANGE_SIZE 4

static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common, BOOL firstline)
{
@@ -3440,10 +3445,16 @@
struct sljit_jump *quit;
pcre_uint32 chars[MAX_N_CHARS * 2];
pcre_uint8 ones[MAX_N_CHARS];
-pcre_uint32 mask;
-int i, max;
int offsets[3];
+pcre_uint32 mask, byte;
+int i, max, from;
+int range_right = -1, range_len = -1;
+sljit_ub *update_table = NULL;
+BOOL in_range;

+/* This is even TRUE, if both are NULL. */
+SLJIT_ASSERT(common->read_only_data_ptr == common->read_only_data);
+
 for (i = 0; i < MAX_N_CHARS; i++)
   {
   chars[i << 1] = NOTACHAR;
@@ -3467,6 +3478,59 @@
     }
   }


+in_range = FALSE;
+for (i = 0; i <= max; i++)
+  {
+  if (i < max && ones[i] <= 1)
+    {
+    if (!in_range)
+      {
+      in_range = TRUE;
+      from = i;
+      }
+    }
+  else if (in_range)
+    {
+    if (range_len == -1 || (i - from) > range_len)
+      {
+      range_len = i - from;
+      range_right = i - 1;
+      }
+    in_range = FALSE;
+    }
+  }
+
+if (range_len >= MIN_RANGE_SIZE)
+  {
+  /* Since no data is consumed (see the assert in the beginning
+  of this function), this space can be reallocated. */
+  if (common->read_only_data)
+    SLJIT_FREE(common->read_only_data);
+
+  common->read_only_data_size += 256;
+  common->read_only_data = (sljit_uw *)SLJIT_MALLOC(common->read_only_data_size);
+  if (common->read_only_data == NULL)
+    return TRUE;
+
+  update_table = (sljit_ub *)common->read_only_data;
+  common->read_only_data_ptr = (sljit_uw *)(update_table + 256);
+  memset(update_table, IN_UCHARS(range_len), 256);
+
+  for (i = 0; i < range_len; i++)
+    {
+    byte = chars[(range_right - i) << 1] & 0xff;
+    if (update_table[byte] > IN_UCHARS(i))
+      update_table[byte] = IN_UCHARS(i);
+    mask = chars[((range_right - i) << 1) + 1] & 0xff;
+    if (mask != 0)
+      {
+      byte ^= mask;
+      if (update_table[byte] > IN_UCHARS(i))
+        update_table[byte] = IN_UCHARS(i);
+      }
+    }
+  }
+
 offsets[0] = -1;
 /* Scan forward. */
 for (i = 0; i < max; i++)
@@ -3481,13 +3545,18 @@
 /* Scan backward. */
 offsets[1] = -1;
 for (i = max - 1; i > offsets[0]; i--)
-  if (ones[i] <= 2) {
+  if (ones[i] <= 2 && i != range_right)
+    {
     offsets[1] = i;
     break;
-  }
+    }


+/* This case is handled better by fast_forward_first_char. */
+if (offsets[1] == -1 && offsets[0] == 0)
+ return FALSE;
+
offsets[2] = -1;
-if (offsets[1] >= 0)
+if (offsets[1] >= 0 && range_right == -1)
{
/* Scan from middle. */
for (i = (offsets[0] + offsets[1]) / 2 + 1; i < offsets[1]; i++)
@@ -3528,15 +3597,41 @@
if (firstline)
{
SLJIT_ASSERT(common->first_line_end != 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end);
OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
- OP2(SLJIT_SUB, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end, SLJIT_IMM, IN_UCHARS(max));
+ OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
+ quit = CMP(SLJIT_C_LESS_EQUAL, STR_END, 0, TMP1, 0);
+ OP1(SLJIT_MOV, STR_END, 0, TMP1, 0);
+ JUMPHERE(quit);
}
else
OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));

+#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+if (range_len >= MIN_RANGE_SIZE)
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table);
+#endif
+
start = LABEL();
quit = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);

+if (range_len >= MIN_RANGE_SIZE)
+ {
+#if defined COMPILE_PCRE8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+ OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right));
+#else
+ OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right + 1) - 1);
+#endif
+
+#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM2(RETURN_ADDR, TMP1), 0);
+#else
+ OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)update_table);
+#endif
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+ CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, start);
+ }
+
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offsets[0]));
if (offsets[1] >= 0)
OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offsets[1]));
@@ -3566,13 +3661,24 @@
JUMPHERE(quit);

 if (firstline)
+  {
+  if (range_len >= MIN_RANGE_SIZE)
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end);
   OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+  if (range_len >= MIN_RANGE_SIZE)
+    {
+    quit = CMP(SLJIT_C_LESS_EQUAL, STR_PTR, 0, TMP1, 0);
+    OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0);
+    JUMPHERE(quit);
+    }
+  }
 else
   OP2(SLJIT_ADD, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
 return TRUE;
 }


#undef MAX_N_CHARS
+#undef MIN_RANGE_SIZE

 static SLJIT_INLINE void fast_forward_first_char(compiler_common *common, pcre_uchar first_char, BOOL caseless, BOOL firstline)
 {
@@ -9808,7 +9914,16 @@
   if ((re->options & PCRE_NO_START_OPTIMIZE) == 0)
     {
     if (mode == JIT_COMPILE && fast_forward_first_n_chars(common, (re->options & PCRE_FIRSTLINE) != 0))
-      { /* Do nothing */ }
+      {
+      /* If read_only_data is reallocated, we might have an allocation failure. */
+      if (common->read_only_data_size > 0 && common->read_only_data == NULL)
+        {
+        sljit_free_compiler(compiler);
+        SLJIT_FREE(common->optimized_cbracket);
+        SLJIT_FREE(common->private_data_ptrs);
+        return;
+        }
+      }
     else if ((re->flags & PCRE_FIRSTSET) != 0)
       fast_forward_first_char(common, (pcre_uchar)re->first_char, (re->flags & PCRE_FCH_CASELESS) != 0, (re->options & PCRE_FIRSTLINE) != 0);
     else if ((re->flags & PCRE_STARTLINE) != 0)


Modified: code/trunk/testdata/testinput2
===================================================================
--- code/trunk/testdata/testinput2    2014-01-10 16:25:55 UTC (rev 1439)
+++ code/trunk/testdata/testinput2    2014-01-11 21:54:20 UTC (rev 1440)
@@ -4048,4 +4048,7 @@
 /(?=ab\K)/+
     abcd


+/abcd/f<lf>
+    xx\nxabcd
+
 /-- End of testinput2 --/


Modified: code/trunk/testdata/testoutput2
===================================================================
--- code/trunk/testdata/testoutput2    2014-01-10 16:25:55 UTC (rev 1439)
+++ code/trunk/testdata/testoutput2    2014-01-11 21:54:20 UTC (rev 1440)
@@ -14131,4 +14131,8 @@
  0: ab
  0+ abcd


+/abcd/f<lf>
+    xx\nxabcd
+No match
+
 /-- End of testinput2 --/