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

This commit is contained in:
Zoltán Herczeg 2015-03-06 07:41:36 +00:00
parent c372df5dce
commit 94802eb0d9
10 changed files with 91 additions and 75 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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)
{

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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

0
testdata/wintestinput3 vendored Executable file → Normal file
View File

0
testdata/wintestoutput3 vendored Executable file → Normal file
View File