[Pcre-svn] [213] code/trunk: Remove computing the JIT read-o…

Top Page
Delete this message
Author: Subversion repository
Date:  
To: pcre-svn
Subject: [Pcre-svn] [213] code/trunk: Remove computing the JIT read-only data size in advance and use on-demand memory allocation .
Revision: 213
          http://www.exim.org/viewvc/pcre2?view=rev&revision=213
Author:   zherczeg
Date:     2015-03-06 07:41:36 +0000 (Fri, 06 Mar 2015)


Log Message:
-----------
Remove computing the JIT read-only data size in advance and use on-demand memory allocation.

Modified Paths:
--------------
    code/trunk/src/pcre2_internal.h
    code/trunk/src/pcre2_jit_compile.c
    code/trunk/src/pcre2_jit_misc.c
    code/trunk/src/sljit/sljitLir.c
    code/trunk/src/sljit/sljitLir.h
    code/trunk/src/sljit/sljitNativeARM_32.c
    code/trunk/testdata/testinput16
    code/trunk/testdata/testoutput16


Property Changed:
----------------
    code/trunk/testdata/testinput1
    code/trunk/testdata/testinput6
    code/trunk/testdata/testoutput1
    code/trunk/testdata/testoutput6
    code/trunk/testdata/wintestinput3
    code/trunk/testdata/wintestoutput3


Modified: code/trunk/src/pcre2_internal.h
===================================================================
--- code/trunk/src/pcre2_internal.h    2015-03-01 18:34:05 UTC (rev 212)
+++ code/trunk/src/pcre2_internal.h    2015-03-06 07:41:36 UTC (rev 213)
@@ -1866,6 +1866,7 @@
 #define _pcre2_auto_possessify       PCRE2_SUFFIX(_pcre2_auto_possessify_)
 #define _pcre2_find_bracket          PCRE2_SUFFIX(_pcre2_find_bracket_)
 #define _pcre2_is_newline            PCRE2_SUFFIX(_pcre2_is_newline_)
+#define _pcre2_jit_free_rodata       PCRE2_SUFFIX(_pcre2_jit_free_rodata_)
 #define _pcre2_jit_free              PCRE2_SUFFIX(_pcre2_jit_free_)
 #define _pcre2_jit_get_size          PCRE2_SUFFIX(_pcre2_jit_get_size_)
 #define _pcre2_jit_get_target        PCRE2_SUFFIX(_pcre2_jit_get_target_)
@@ -1887,6 +1888,7 @@
 extern PCRE2_SPTR   _pcre2_find_bracket(PCRE2_SPTR, BOOL, int);
 extern BOOL         _pcre2_is_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
                       uint32_t *, BOOL);
+extern void         _pcre2_jit_free_rodata(void *, void *);
 extern void         _pcre2_jit_free(void *, pcre2_memctl *);
 extern size_t       _pcre2_jit_get_size(void *);
 const char *        _pcre2_jit_get_target(void);


Modified: code/trunk/src/pcre2_jit_compile.c
===================================================================
--- code/trunk/src/pcre2_jit_compile.c    2015-03-01 18:34:05 UTC (rev 212)
+++ code/trunk/src/pcre2_jit_compile.c    2015-03-06 07:41:36 UTC (rev 213)
@@ -193,7 +193,7 @@


 typedef struct executable_functions {
   void *executable_funcs[JIT_NUMBER_OF_COMPILE_MODES];
-  sljit_uw *read_only_data[JIT_NUMBER_OF_COMPILE_MODES];
+  void *read_only_data_heads[JIT_NUMBER_OF_COMPILE_MODES];
   sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_MODES];
   sljit_ui top_bracket;
   sljit_ui limit_match;
@@ -334,12 +334,8 @@
   PCRE2_SPTR start;
   /* Maps private data offset to each opcode. */
   sljit_si *private_data_ptrs;
-  /* This read-only data is available during runtime. */
-  sljit_uw *read_only_data;
-  /* The total size of the read-only data. */
-  sljit_uw read_only_data_size;
-  /* The next free entry of the read_only_data. */
-  sljit_uw *read_only_data_ptr;
+  /* Chain list of read-only data ptrs. */
+  void *read_only_data_head;
   /* Tells whether the capturing bracket is optimized. */
   sljit_ub *optimized_cbracket;
   /* Tells whether the starting offset is a target of then. */
@@ -815,16 +811,6 @@
     cc += 1 + IMM2_SIZE;
     break;


-    case OP_BRA:
-    case OP_CBRA:
-    case OP_SBRA:
-    case OP_SCBRA:
-    count = no_alternatives(cc);
-    if (count > 4)
-      common->read_only_data_size += count * sizeof(sljit_uw);
-    cc += 1 + LINK_SIZE + (*cc == OP_CBRA || *cc == OP_SCBRA ? IMM2_SIZE : 0);
-    break;
-
     case OP_CBRAPOS:
     case OP_SCBRAPOS:
     common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] = 0;
@@ -2119,6 +2105,26 @@
 OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
 }


+static sljit_uw * allocate_read_only_data(compiler_common *common, sljit_uw size)
+{
+DEFINE_COMPILER;
+sljit_uw *result;
+
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return NULL;
+
+result = (sljit_uw *)SLJIT_MALLOC(size + sizeof(sljit_uw), compiler->allocator_data);
+if (SLJIT_UNLIKELY(result == NULL))
+ {
+ sljit_set_compiler_memory_error(compiler);
+ return NULL;
+ }
+
+*(void**)result = common->read_only_data_head;
+common->read_only_data_head = (void *)result;
+return result + 1;
+}
+
static SLJIT_INLINE void reset_ovector(compiler_common *common, int length)
{
DEFINE_COMPILER;
@@ -3522,9 +3528,6 @@
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;
@@ -3573,18 +3576,9 @@

 if (range_right >= 0)
   {
-  /* 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, compiler->allocator_data);
-
-  common->read_only_data_size += 256;
-  common->read_only_data = (sljit_uw *)SLJIT_MALLOC(common->read_only_data_size, compiler->allocator_data);
-  if (common->read_only_data == NULL)
+  update_table = (sljit_ub *)allocate_read_only_data(common, 256);
+  if (update_table == 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++)
@@ -8967,8 +8961,9 @@
   if (alt_max > 4)
     {
     /* Table jump if alt_max is greater than 4. */
-    next_update_addr = common->read_only_data_ptr;
-    common->read_only_data_ptr += alt_max;
+    next_update_addr = allocate_read_only_data(common, alt_max * sizeof(sljit_uw));
+    if (SLJIT_UNLIKELY(next_update_addr == NULL))
+      return;
     sljit_emit_ijump(compiler, SLJIT_JUMP, SLJIT_MEM1(TMP1), (sljit_sw)next_update_addr);
     add_label_addr(common, next_update_addr++);
     }
@@ -9748,9 +9743,7 @@
 rootbacktrack.cc = common->name_table + re->name_count * re->name_entry_size;


common->start = rootbacktrack.cc;
-common->read_only_data = NULL;
-common->read_only_data_size = 0;
-common->read_only_data_ptr = NULL;
+common->read_only_data_head = NULL;
common->fcc = tables + fcc_offset;
common->lcc = (sljit_sw)(tables + lcc_offset);
common->mode = mode;
@@ -9913,25 +9906,11 @@
set_then_offsets(common, common->start, NULL);
}

-if (common->read_only_data_size > 0)
-  {
-  common->read_only_data = (sljit_uw *)SLJIT_MALLOC(common->read_only_data_size, allocator_data);
-  if (common->read_only_data == NULL)
-    {
-    SLJIT_FREE(common->optimized_cbracket, allocator_data);
-    SLJIT_FREE(common->private_data_ptrs, allocator_data);
-    return PCRE2_ERROR_NOMEMORY;
-    }
-  common->read_only_data_ptr = common->read_only_data;
-  }
-
 compiler = sljit_create_compiler(allocator_data);
 if (!compiler)
   {
   SLJIT_FREE(common->optimized_cbracket, allocator_data);
   SLJIT_FREE(common->private_data_ptrs, allocator_data);
-  if (common->read_only_data)
-    SLJIT_FREE(common->read_only_data, allocator_data);
   return PCRE2_ERROR_NOMEMORY;
   }
 common->compiler = compiler;
@@ -9970,16 +9949,7 @@
   if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
     {
     if (mode == PCRE2_JIT_COMPLETE && fast_forward_first_n_chars(common, (re->overall_options & PCRE2_FIRSTLINE) != 0))
-      {
-      /* 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, allocator_data);
-        SLJIT_FREE(common->private_data_ptrs, allocator_data);
-        return PCRE2_ERROR_NOMEMORY;
-        }
-      }
+      ;
     else if ((re->flags & PCRE2_FIRSTSET) != 0)
       fast_forward_first_char(common, (PCRE2_UCHAR)(re->first_codeunit), (re->flags & PCRE2_FIRSTCASELESS) != 0, (re->overall_options & PCRE2_FIRSTLINE) != 0);
     else if ((re->flags & PCRE2_STARTLINE) != 0)
@@ -10026,8 +9996,7 @@
   sljit_free_compiler(compiler);
   SLJIT_FREE(common->optimized_cbracket, allocator_data);
   SLJIT_FREE(common->private_data_ptrs, allocator_data);
-  if (common->read_only_data)
-    SLJIT_FREE(common->read_only_data, allocator_data);
+  PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
   return PCRE2_ERROR_NOMEMORY;
   }


@@ -10067,8 +10036,7 @@
   sljit_free_compiler(compiler);
   SLJIT_FREE(common->optimized_cbracket, allocator_data);
   SLJIT_FREE(common->private_data_ptrs, allocator_data);
-  if (common->read_only_data)
-    SLJIT_FREE(common->read_only_data, allocator_data);
+  PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
   return PCRE2_ERROR_NOMEMORY;
   }


@@ -10148,8 +10116,7 @@
     sljit_free_compiler(compiler);
     SLJIT_FREE(common->optimized_cbracket, allocator_data);
     SLJIT_FREE(common->private_data_ptrs, allocator_data);
-    if (common->read_only_data)
-      SLJIT_FREE(common->read_only_data, allocator_data);
+    PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
     return PCRE2_ERROR_NOMEMORY;
     }
   flush_stubs(common);
@@ -10257,7 +10224,6 @@
   }
 #endif /* SUPPORT_UNICODE */


-SLJIT_ASSERT(common->read_only_data + (common->read_only_data_size >> SLJIT_WORD_SHIFT) == common->read_only_data_ptr);
SLJIT_FREE(common->optimized_cbracket, allocator_data);
SLJIT_FREE(common->private_data_ptrs, allocator_data);

@@ -10272,8 +10238,7 @@
 sljit_free_compiler(compiler);
 if (executable_func == NULL)
   {
-  if (common->read_only_data)
-    SLJIT_FREE(common->read_only_data, allocator_data);
+  PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
   return PCRE2_ERROR_NOMEMORY;
   }


@@ -10288,8 +10253,7 @@
     /* This case is highly unlikely since we just recently
     freed a lot of memory. Not impossible though. */
     sljit_free_code(executable_func);
-    if (common->read_only_data)
-      SLJIT_FREE(common->read_only_data, allocator_data);
+    PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
     return PCRE2_ERROR_NOMEMORY;
     }
   memset(functions, 0, sizeof(executable_functions));
@@ -10306,7 +10270,7 @@


SLJIT_ASSERT(mode >= 0 && mode < JIT_NUMBER_OF_COMPILE_MODES);
functions->executable_funcs[mode] = executable_func;
-functions->read_only_data[mode] = common->read_only_data;
+functions->read_only_data_heads[mode] = common->read_only_data_head;
functions->executable_sizes[mode] = executable_size;
return 0;
}

Modified: code/trunk/src/pcre2_jit_misc.c
===================================================================
--- code/trunk/src/pcre2_jit_misc.c    2015-03-01 18:34:05 UTC (rev 212)
+++ code/trunk/src/pcre2_jit_misc.c    2015-03-06 07:41:36 UTC (rev 213)
@@ -46,6 +46,25 @@



 /*************************************************
+*           Free JIT read-only data              *
+*************************************************/
+
+void
+PRIV(jit_free_rodata)(void *current, void *allocator_data)
+{
+void *next;
+
+SLJIT_UNUSED_ARG(allocator_data);
+
+while (current != NULL)
+  {
+  next = *(void**)current;
+  SLJIT_FREE(current, allocator_data);
+  current = next;
+  }
+}
+
+/*************************************************
 *           Free JIT compiled code               *
 *************************************************/


@@ -65,8 +84,7 @@
   {
   if (functions->executable_funcs[i] != NULL)
     sljit_free_code(functions->executable_funcs[i]);
-  if (functions->read_only_data[i] != NULL)
-    SLJIT_FREE(functions->read_only_data[i], allocator_data);
+  PRIV(jit_free_rodata)(functions->read_only_data_heads[i], allocator_data);
   }


SLJIT_FREE(functions, allocator_data);

Modified: code/trunk/src/sljit/sljitLir.c
===================================================================
--- code/trunk/src/sljit/sljitLir.c    2015-03-01 18:34:05 UTC (rev 212)
+++ code/trunk/src/sljit/sljitLir.c    2015-03-06 07:41:36 UTC (rev 213)
@@ -435,6 +435,12 @@
     SLJIT_FREE(compiler, allocator_data);
 }


+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler)
+{
+    if (compiler->error == SLJIT_SUCCESS)
+        compiler->error = SLJIT_ERR_ALLOC_FAILED;
+}
+
 #if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
 SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code)
 {


Modified: code/trunk/src/sljit/sljitLir.h
===================================================================
--- code/trunk/src/sljit/sljitLir.h    2015-03-01 18:34:05 UTC (rev 212)
+++ code/trunk/src/sljit/sljitLir.h    2015-03-06 07:41:36 UTC (rev 213)
@@ -429,6 +429,14 @@
    these checks increases the performance of the compiling process. */
 static SLJIT_INLINE sljit_si sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; }


+/* Sets the compiler error code to SLJIT_ERR_ALLOC_FAILED except
+   if an error was detected before. After the error code is set
+   the compiler behaves as if the allocation failure happened
+   during an sljit function call. This can greatly simplify error
+   checking, since only the compiler status needs to be checked
+   after the compilation. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler);
+
 /*
    Allocate a small amount of memory. The size must be <= 64 bytes on 32 bit,
    and <= 128 bytes on 64 bit architectures. The memory area is owned by the


Modified: code/trunk/src/sljit/sljitNativeARM_32.c
===================================================================
--- code/trunk/src/sljit/sljitNativeARM_32.c    2015-03-01 18:34:05 UTC (rev 212)
+++ code/trunk/src/sljit/sljitNativeARM_32.c    2015-03-06 07:41:36 UTC (rev 213)
@@ -315,11 +315,13 @@
     sljit_si value;
 };


-static SLJIT_INLINE sljit_si resolve_const_pool_index(struct sljit_compiler *compiler, struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr)
+static sljit_si resolve_const_pool_index(struct sljit_compiler *compiler, struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr)
 {
     sljit_si value;
     struct future_patch *curr_patch, *prev_patch;


+    SLJIT_UNUSED_ARG(compiler);
+
     /* Using the values generated by patch_pc_relative_loads. */
     if (!*first_patch)
         value = (sljit_si)cpool_start_address[cpool_current_index];



Property changes on: code/trunk/testdata/testinput1
___________________________________________________________________
Name: svn:mime-type
- application/octet-stream

Modified: code/trunk/testdata/testinput16
===================================================================
--- code/trunk/testdata/testinput16    2015-03-01 18:34:05 UTC (rev 212)
+++ code/trunk/testdata/testinput16    2015-03-06 07:41:36 UTC (rev 213)
@@ -190,4 +190,12 @@
 #pop jit,jitverify
     abcdef


+# Test pattern compilation
+
+/(?:a|b|c|d|e)(?R)/jit=1
+
+/(?:a|b|c|d|e)(?R)(?R)/jit=1
+
+/(a(?:a|b|c|d|e)b){8,16}/jit=1
+
# End of testinput16


Property changes on: code/trunk/testdata/testinput6
___________________________________________________________________
Name: svn:mime-type
- application/octet-stream


Property changes on: code/trunk/testdata/testoutput1
___________________________________________________________________
Name: svn:mime-type
- application/octet-stream

Modified: code/trunk/testdata/testoutput16
===================================================================
--- code/trunk/testdata/testoutput16    2015-03-01 18:34:05 UTC (rev 212)
+++ code/trunk/testdata/testoutput16    2015-03-06 07:41:36 UTC (rev 213)
@@ -365,4 +365,12 @@
     abcdef
  0: def (JIT)


+# Test pattern compilation
+
+/(?:a|b|c|d|e)(?R)/jit=1
+
+/(?:a|b|c|d|e)(?R)(?R)/jit=1
+
+/(a(?:a|b|c|d|e)b){8,16}/jit=1
+
# End of testinput16


Property changes on: code/trunk/testdata/testoutput6
___________________________________________________________________
Name: svn:mime-type
- application/octet-stream


Property changes on: code/trunk/testdata/wintestinput3
___________________________________________________________________
Name: svn:executable
- *


Property changes on: code/trunk/testdata/wintestoutput3
___________________________________________________________________
Name: svn:executable
- *