[Pcre-svn] [1009] code/trunk: Improve the matching speed of …

Etusivu
Poista viesti
Lähettäjä: Subversion repository
Päiväys:  
Vastaanottaja: pcre-svn
Aihe: [Pcre-svn] [1009] code/trunk: Improve the matching speed of capturing brackets.
Revision: 1009
          http://vcs.pcre.org/viewvc?view=rev&revision=1009
Author:   zherczeg
Date:     2012-08-22 13:01:22 +0100 (Wed, 22 Aug 2012)


Log Message:
-----------
Improve the matching speed of capturing brackets.

Modified Paths:
--------------
    code/trunk/ChangeLog
    code/trunk/pcre_jit_compile.c


Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog    2012-08-18 16:38:40 UTC (rev 1008)
+++ code/trunk/ChangeLog    2012-08-22 12:01:22 UTC (rev 1009)
@@ -48,7 +48,9 @@


     (h) The documentation has been revised and clarified in places.   


+9. Improve the matching speed of capturing brackets.

+
Version 8.31 06-July-2012
-------------------------


Modified: code/trunk/pcre_jit_compile.c
===================================================================
--- code/trunk/pcre_jit_compile.c    2012-08-18 16:38:40 UTC (rev 1008)
+++ code/trunk/pcre_jit_compile.c    2012-08-22 12:01:22 UTC (rev 1009)
@@ -279,6 +279,9 @@


/* Maps private data offset to each opcode. */
int *private_data_ptrs;
+ /* Tells whether the capturing bracket is optimized. */
+ pcre_uint8 *optimized_cbracket;
+ /* Starting offset of private data for capturing brackets. */
int cbraptr;
/* OVector starting point. Must be divisible by 2. */
int ovector_start;
@@ -759,8 +762,9 @@
{
int private_data_length = 0;
pcre_uchar *alternative;
+pcre_uchar *name;
pcre_uchar *end = NULL;
-int space, size, bracketlen;
+int space, size, bracketlen, i;

 /* Calculate important variables (like stack size) and checks whether all opcodes are supported. */
 while (cc < ccend)
@@ -775,6 +779,12 @@
     cc += 1;
     break;


+    case OP_REF:
+    case OP_REFI:
+    common->optimized_cbracket[GET2(cc, 1)] = 0;
+    cc += 1 + IMM2_SIZE;
+    break;
+
     case OP_ASSERT:
     case OP_ASSERT_NOT:
     case OP_ASSERTBACK:
@@ -784,7 +794,6 @@
     case OP_BRAPOS:
     case OP_SBRA:
     case OP_SBRAPOS:
-    case OP_SCOND:
     private_data_length += sizeof(sljit_w);
     bracketlen = 1 + LINK_SIZE;
     break;
@@ -792,13 +801,46 @@
     case OP_CBRAPOS:
     case OP_SCBRAPOS:
     private_data_length += sizeof(sljit_w);
+    common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] = 0;
     bracketlen = 1 + LINK_SIZE + IMM2_SIZE;
     break;


     case OP_COND:
-    /* Might be a hidden SCOND. */
-    alternative = cc + GET(cc, 1);
-    if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+    case OP_SCOND:
+    bracketlen = cc[1 + LINK_SIZE];
+    if (bracketlen == OP_CREF)
+      {
+      bracketlen = GET2(cc, 1 + LINK_SIZE + 1);
+      common->optimized_cbracket[bracketlen] = 0;
+      }
+    else if (bracketlen == OP_NCREF)
+      {
+      bracketlen = GET2(cc, 1 + LINK_SIZE + 1);
+      name = (pcre_uchar *)common->name_table;
+      alternative = name;
+      for (i = 0; i < common->name_count; i++)
+        {
+        if (GET2(name, 0) == bracketlen) break;
+        name += common->name_entry_size;
+        }
+      SLJIT_ASSERT(i != common->name_count);
+
+      for (i = 0; i < common->name_count; i++)
+        {
+        if (STRCMP_UC_UC(alternative + IMM2_SIZE, name + IMM2_SIZE) == 0)
+          common->optimized_cbracket[GET2(alternative, 0)] = 0;
+        alternative += common->name_entry_size;
+        }
+      }
+
+    if (*cc == OP_COND)
+      {
+      /* Might be a hidden SCOND. */
+      alternative = cc + GET(cc, 1);
+      if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+        private_data_length += sizeof(sljit_w);
+      }
+    else
       private_data_length += sizeof(sljit_w);
     bracketlen = 1 + LINK_SIZE;
     break;
@@ -858,6 +900,9 @@
 #endif


     case OP_RECURSE:
+    alternative = common->start + GET(cc, 1);
+    if (alternative != common->start)
+      common->optimized_cbracket[GET2(alternative, 1 + LINK_SIZE)] = 0;
     /* Set its value only once. */
     if (common->recursive_head == 0)
       {
@@ -1252,12 +1297,14 @@


     case OP_CBRA:
     case OP_SCBRA:
-    private_data_length++;
+    if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+      private_data_length++;
     cc += 1 + LINK_SIZE + IMM2_SIZE;
     break;


     case OP_CBRAPOS:
     case OP_SCBRAPOS:
+    SLJIT_ASSERT(common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0);
     private_data_length += 2;
     cc += 1 + LINK_SIZE + IMM2_SIZE;
     break;
@@ -1415,17 +1462,20 @@


       case OP_CBRA:
       case OP_SCBRA:
-      count = 1;
-      srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
+      if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+        {
+        count = 1;
+        srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
+        }
       cc += 1 + LINK_SIZE + IMM2_SIZE;
       break;


       case OP_CBRAPOS:
       case OP_SCBRAPOS:
       count = 2;
-      srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
-      srcw[1] = PRIVATE_DATA(cc);
-      SLJIT_ASSERT(srcw[0] != 0);
+      srcw[0] = PRIVATE_DATA(cc);
+      srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
+      SLJIT_ASSERT(srcw[0] != 0 && srcw[1] != 0);
       cc += 1 + LINK_SIZE + IMM2_SIZE;
       break;


@@ -5454,8 +5504,16 @@
   {
   /* Capturing brackets has a pre-allocated space. */
   offset = GET2(ccbegin, 1 + LINK_SIZE);
-  private_data_ptr = OVECTOR_PRIV(offset);
-  offset <<= 1;
+  if (common->optimized_cbracket[offset] == 0)
+    {
+    private_data_ptr = OVECTOR_PRIV(offset);
+    offset <<= 1;
+    }
+  else
+    {
+    offset <<= 1;
+    private_data_ptr = OVECTOR(offset);
+    }
   BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr;
   matchingpath += IMM2_SIZE;
   }
@@ -5589,14 +5647,27 @@
 else if (opcode == OP_CBRA || opcode == OP_SCBRA)
   {
   /* Saving the previous values. */
-  allocate_stack(common, 3);
-  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset));
-  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
-  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
-  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
-  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr);
-  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STR_PTR, 0);
-  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
+  if (common->optimized_cbracket[offset >> 1] == 0)
+    {
+    allocate_stack(common, 3);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STR_PTR, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
+    }
+  else
+    {
+    SLJIT_ASSERT(private_data_ptr == OVECTOR(offset));
+    allocate_stack(common, 2);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr + sizeof(sljit_w));
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STR_PTR, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+    }
   }
 else if (opcode == OP_SBRA || opcode == OP_SCOND)
   {
@@ -6405,15 +6476,18 @@
 {
 DEFINE_COMPILER;
 int offset = GET2(cc, 1);
+BOOL optimized_cbracket = common->optimized_cbracket[offset] != 0;


/* Data will be discarded anyway... */
if (common->currententry != NULL)
return cc + 1 + IMM2_SIZE;

-OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR_PRIV(offset));
+if (!optimized_cbracket)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR_PRIV(offset));
offset <<= 1;
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0);
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
+if (!optimized_cbracket)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
return cc + 1 + IMM2_SIZE;
}

@@ -7235,12 +7309,24 @@
 if (offset != 0)
   {
   /* Using both tmp register is better for instruction scheduling. */
-  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
-  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
-  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
-  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0);
-  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(2));
-  free_stack(common, 3);
+  if (common->optimized_cbracket[offset >> 1] == 0)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
+    free_stack(common, 3);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP1, 0);
+    }
+  else
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    free_stack(common, 2);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0);
+    }
   }
 else if (opcode == OP_SBRA || opcode == OP_SCOND)
   {
@@ -7727,11 +7813,18 @@


/* Calculate the local space size on the stack. */
common->ovector_start = CALL_LIMIT + sizeof(sljit_w);
+common->optimized_cbracket = (pcre_uint8 *)SLJIT_MALLOC(re->top_bracket + 1);
+if (!common->optimized_cbracket)
+ return;
+memset(common->optimized_cbracket, 1, re->top_bracket + 1);

SLJIT_ASSERT(*rootbacktrack.cc == OP_BRA && ccend[-(1 + LINK_SIZE)] == OP_KET);
private_data_size = get_private_data_length(common, rootbacktrack.cc, ccend);
if (private_data_size < 0)
+ {
+ SLJIT_FREE(common->optimized_cbracket);
return;
+ }

/* Checking flags and updating ovector_start. */
if (mode == JIT_COMPILE && (re->flags & PCRE_REQCHSET) != 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0)
@@ -7763,16 +7856,23 @@
common->cbraptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_w);
private_data_size += common->cbraptr + (re->top_bracket + 1) * sizeof(sljit_w);
if (private_data_size > SLJIT_MAX_LOCAL_SIZE)
+ {
+ SLJIT_FREE(common->optimized_cbracket);
return;
+ }
common->private_data_ptrs = (int *)SLJIT_MALLOC((ccend - rootbacktrack.cc) * sizeof(int));
if (!common->private_data_ptrs)
+ {
+ SLJIT_FREE(common->optimized_cbracket);
return;
+ }
memset(common->private_data_ptrs, 0, (ccend - rootbacktrack.cc) * sizeof(int));
set_private_data_ptrs(common, common->cbraptr + (re->top_bracket + 1) * sizeof(sljit_w), ccend);

 compiler = sljit_create_compiler();
 if (!compiler)
   {
+  SLJIT_FREE(common->optimized_cbracket);
   SLJIT_FREE(common->private_data_ptrs);
   return;
   }
@@ -7839,6 +7939,7 @@
 if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
   {
   sljit_free_compiler(compiler);
+  SLJIT_FREE(common->optimized_cbracket);
   SLJIT_FREE(common->private_data_ptrs);
   return;
   }
@@ -7869,6 +7970,7 @@
 if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
   {
   sljit_free_compiler(compiler);
+  SLJIT_FREE(common->optimized_cbracket);
   SLJIT_FREE(common->private_data_ptrs);
   return;
   }
@@ -7947,6 +8049,7 @@
   if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
     {
     sljit_free_compiler(compiler);
+    SLJIT_FREE(common->optimized_cbracket);
     SLJIT_FREE(common->private_data_ptrs);
     return;
     }
@@ -8042,6 +8145,7 @@
   }
 #endif


+SLJIT_FREE(common->optimized_cbracket);
SLJIT_FREE(common->private_data_ptrs);
executable_func = sljit_generate_code(compiler);
executable_size = sljit_get_generated_code_size(compiler);