Remove computing the JIT read-only data size in advance and use on-demand memory allocation.
This commit is contained in:
parent
925a473b61
commit
af174afe3b
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
8
testdata/testinput16
vendored
8
testdata/testinput16
vendored
@ -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
|
||||
|
8
testdata/testoutput16
vendored
8
testdata/testoutput16
vendored
@ -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
0
testdata/wintestinput3
vendored
Executable file → Normal file
0
testdata/wintestoutput3
vendored
Executable file → Normal file
0
testdata/wintestoutput3
vendored
Executable file → Normal file
Loading…
Reference in New Issue
Block a user