From af174afe3b5c0f8a170734217ccc05b72a54384b Mon Sep 17 00:00:00 2001 From: zherczeg Date: Fri, 6 Mar 2015 07:41:36 +0000 Subject: [PATCH] Remove computing the JIT read-only data size in advance and use on-demand memory allocation. --- src/pcre2_internal.h | 2 + src/pcre2_jit_compile.c | 108 ++++++++++++---------------------- src/pcre2_jit_misc.c | 22 ++++++- src/sljit/sljitLir.c | 6 ++ src/sljit/sljitLir.h | 8 +++ src/sljit/sljitNativeARM_32.c | 4 +- testdata/testinput16 | 8 +++ testdata/testoutput16 | 8 +++ testdata/wintestinput3 | 0 testdata/wintestoutput3 | 0 10 files changed, 91 insertions(+), 75 deletions(-) mode change 100755 => 100644 testdata/wintestinput3 mode change 100755 => 100644 testdata/wintestoutput3 diff --git a/src/pcre2_internal.h b/src/pcre2_internal.h index ba8906a..ee0a670 100644 --- a/src/pcre2_internal.h +++ b/src/pcre2_internal.h @@ -1866,6 +1866,7 @@ is available. */ #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 int _pcre2_auto_possessify(PCRE2_UCHAR *, BOOL, 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); diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c index f6d2a68..651e273 100644 --- a/src/pcre2_jit_compile.c +++ b/src/pcre2_jit_compile.c @@ -193,7 +193,7 @@ typedef struct jit_arguments { 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 @@ typedef struct compiler_common { 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 @@ while (cc < ccend) 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 @@ DEFINE_COMPILER; 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 @@ int range_right = -1, range_len = 3 - 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; @@ -3573,18 +3576,9 @@ for (i = 0; i <= max; i++) 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 @@ else if (has_alternatives) 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 @@ common->name_table = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)); 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 @@ if (common->has_then) 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_ANCHORED) == 0) 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 @@ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) 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 @@ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) 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 @@ while (common->currententry != NULL) 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 @@ if (common->getucd != NULL) } #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 @@ while (label_addr != NULL) 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 @@ else /* 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 @@ else 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; } diff --git a/src/pcre2_jit_misc.c b/src/pcre2_jit_misc.c index f81345e..2d8088c 100644 --- a/src/pcre2_jit_misc.c +++ b/src/pcre2_jit_misc.c @@ -45,6 +45,25 @@ POSSIBILITY OF SUCH DAMAGE. +/************************************************* +* 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 @@ for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++) { 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); diff --git a/src/sljit/sljitLir.c b/src/sljit/sljitLir.c index 8112e8d..5039a7e 100644 --- a/src/sljit/sljitLir.c +++ b/src/sljit/sljitLir.c @@ -435,6 +435,12 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compile 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) { diff --git a/src/sljit/sljitLir.h b/src/sljit/sljitLir.h index 229e04f..24c0f60 100644 --- a/src/sljit/sljitLir.h +++ b/src/sljit/sljitLir.h @@ -429,6 +429,14 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compile 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 diff --git a/src/sljit/sljitNativeARM_32.c b/src/sljit/sljitNativeARM_32.c index a763b81..aca1d31 100644 --- a/src/sljit/sljitNativeARM_32.c +++ b/src/sljit/sljitNativeARM_32.c @@ -315,11 +315,13 @@ struct future_patch { 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]; diff --git a/testdata/testinput16 b/testdata/testinput16 index 796b8c2..6c56699 100644 --- a/testdata/testinput16 +++ b/testdata/testinput16 @@ -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 diff --git a/testdata/testoutput16 b/testdata/testoutput16 index a68ab09..2e7deb6 100644 --- a/testdata/testoutput16 +++ b/testdata/testoutput16 @@ -365,4 +365,12 @@ JIT compilation was successful 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 diff --git a/testdata/wintestinput3 b/testdata/wintestinput3 old mode 100755 new mode 100644 diff --git a/testdata/wintestoutput3 b/testdata/wintestoutput3 old mode 100755 new mode 100644