Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 68 additions & 45 deletions src/pcre2_jit_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ typedef struct stub_list {

enum frame_types { no_frame = -1, no_stack = -2 };

enum verb_offset_types { verb_offset_then = 0x1, verb_offset_any = 0x2 };

enum control_types { type_mark = 0, type_then_trap = 1 };

enum early_fail_types { type_skip = 0, type_fail = 1, type_fail_range = 2 };
Expand Down Expand Up @@ -403,7 +405,7 @@ typedef struct compiler_common {
/* Bitset for tracking capture bracket status. */
sljit_u8 *cbracket_bitset;
/* Tells whether the starting offset is a target of then. */
sljit_u8 *then_offsets;
sljit_u8 *verb_offsets;
/* Current position where a THEN must jump. */
then_trap_backtrack *then_trap;
/* Starting offset of private data for capturing brackets. */
Expand Down Expand Up @@ -1302,31 +1304,40 @@ check_opcode_types(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend)
cc += 1 + LINK_SIZE;
break;

case OP_THEN:
common->has_then = TRUE;
common->control_head_ptr = 1;
PCRE2_FALLTHROUGH /* Fall through */

case OP_PRUNE:
common->verb_offsets = (sljit_u8*)1;
cc += 1;
break;

case OP_THEN_ARG:
common->has_then = TRUE;
common->control_head_ptr = 1;
PCRE2_FALLTHROUGH /* Fall through */

case OP_COMMIT_ARG:
case OP_PRUNE_ARG:
common->verb_offsets = (sljit_u8*)1;
PCRE2_FALLTHROUGH /* Fall through */

case OP_COMMIT_ARG:
case OP_MARK:
set_mark = TRUE;
cc += 1 + 2 + cc[1];
break;

case OP_THEN:
common->has_then = TRUE;
common->control_head_ptr = 1;
cc += 1;
break;

case OP_SKIP:
common->verb_offsets = (sljit_u8*)1;
if (cc < assert_back_end)
common->has_skip_in_assert_back = TRUE;
cc += 1;
break;

case OP_SKIP_ARG:
common->verb_offsets = (sljit_u8*)1;
common->control_head_ptr = 1;
common->has_skip_arg = TRUE;
if (cc < assert_back_end)
Expand Down Expand Up @@ -1434,7 +1445,7 @@ detect_early_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_star
count = start;
cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0);

if (!common->has_then || common->then_offsets[cc - common->start] == 0)
if (common->verb_offsets == NULL || common->verb_offsets[cc - common->start] == 0)
{
while (TRUE)
{
Expand Down Expand Up @@ -3492,31 +3503,25 @@ copy_recurse_data(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int
delayed_mem_copy_finish(&status);
}

static SLJIT_INLINE void set_then_offsets(compiler_common *common)
static SLJIT_INLINE void set_verb_offsets(compiler_common *common)
{
PCRE2_SPTR cc = common->start;
PCRE2_SPTR end;
PCRE2_SPTR next_top_alternative = cc + GET(cc, 1);
BOOL has_alternatives = TRUE;
sljit_s32 start = 1 + LINK_SIZE;
sljit_s32 last_alternative, end_offset;
sljit_s32 start = 1 + LINK_SIZE, top_start = 1 + LINK_SIZE;
sljit_s32 end_offset;

SLJIT_ASSERT(*cc == OP_BRA);
end = cc;
do
{
last_alternative = (sljit_s32)((end - cc) + 1 + LINK_SIZE);
end += GET(end, 1);
}
while (*end == OP_ALT);
SLJIT_ASSERT(*next_top_alternative == OP_ALT || *next_top_alternative == OP_KET);
cc += 1 + LINK_SIZE;

while (cc < end)
while (*cc != OP_END)
{
if (*cc >= OP_ASSERT && *cc <= OP_SCOND)
{
end_offset = (sljit_s32)((bracketend(cc) - common->start) - (1 + LINK_SIZE));
common->then_offsets[end_offset] = (sljit_u8)has_alternatives;
SLJIT_ASSERT(common->private_data_ptrs[end - common->start] == 0);
common->verb_offsets[end_offset] = (sljit_u8)has_alternatives;
SLJIT_ASSERT(common->private_data_ptrs[end_offset] == 0);
common->private_data_ptrs[end_offset] = start;

has_alternatives = cc[GET(cc, 1)] == OP_ALT;
Expand Down Expand Up @@ -3554,16 +3559,22 @@ static SLJIT_INLINE void set_then_offsets(compiler_common *common)

if (*cc >= OP_KET && *cc <= OP_KETRPOS)
{
has_alternatives = (BOOL)common->then_offsets[cc - common->start];
has_alternatives = (BOOL)common->verb_offsets[cc - common->start];
start = common->private_data_ptrs[cc - common->start];
common->then_offsets[cc - common->start] = 0;
common->verb_offsets[cc - common->start] = 0;
common->private_data_ptrs[cc - common->start] = 0;
cc += 1 + LINK_SIZE;
continue;
}

if (*cc == OP_ALT)
{
if (cc == next_top_alternative) {
next_top_alternative += GET(next_top_alternative, 1);
SLJIT_ASSERT(*next_top_alternative == OP_ALT || *next_top_alternative == OP_KET);
top_start = (sljit_s32)(cc + 1 + LINK_SIZE - common->start);
}

cc += 1 + LINK_SIZE;

if (has_alternatives)
Expand All @@ -3578,9 +3589,21 @@ static SLJIT_INLINE void set_then_offsets(compiler_common *common)
continue;
}

if (*cc >= OP_THEN && *cc <= OP_THEN_ARG && start != 0)
common->then_offsets[start] = (start == last_alternative) + 1;
switch (*cc)
{
case OP_THEN:
case OP_THEN_ARG:
if (start != 0)
common->verb_offsets[start] |= (start == top_start && *next_top_alternative == OP_KET) ? verb_offset_any : verb_offset_then;
break;

case OP_PRUNE:
case OP_PRUNE_ARG:
case OP_SKIP:
case OP_SKIP_ARG:
common->verb_offsets[top_start] |= verb_offset_any;
break;
}
cc = next_opcode(common, cc);
}
}
Expand Down Expand Up @@ -12479,7 +12502,7 @@ compile_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend,

SLJIT_ASSERT(*ccend == OP_END || (*ccend >= OP_ALT && *ccend <= OP_KETRPOS));

if (common->has_then && common->then_offsets[cc - common->start] == 1)
if (common->has_then && (common->verb_offsets[cc - common->start] & verb_offset_then) != 0)
{
SLJIT_ASSERT(*ccend != OP_END && common->control_head_ptr != 0);
has_then_trap = TRUE;
Expand Down Expand Up @@ -14671,18 +14694,18 @@ jit_compile(pcre2_code *code, sljit_u32 mode)
common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw);
private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw);

if (common->has_then)
if (common->verb_offsets != NULL)
{
total_length = ccend - common->start;
common->then_offsets = (sljit_u8 *)SLJIT_MALLOC(total_length, allocator_data);
if (!common->then_offsets)
common->verb_offsets = (sljit_u8 *)SLJIT_MALLOC(total_length, allocator_data);
if (!common->verb_offsets)
{
SLJIT_FREE(common->private_data_ptrs, allocator_data);
return PCRE2_ERROR_NOMEMORY;
}

memset(common->then_offsets, 0, total_length);
set_then_offsets(common);
memset(common->verb_offsets, 0, total_length);
set_verb_offsets(common);
}

if ((re->overall_options & PCRE2_ANCHORED) == 0 &&
Expand All @@ -14697,17 +14720,17 @@ jit_compile(pcre2_code *code, sljit_u32 mode)
if (private_data_size > 65536)
{
SLJIT_FREE(common->private_data_ptrs, allocator_data);
if (common->has_then)
SLJIT_FREE(common->then_offsets, allocator_data);
if (common->verb_offsets != NULL)
SLJIT_FREE(common->verb_offsets, allocator_data);
return PCRE2_ERROR_JIT_UNSUPPORTED;
}

compiler = sljit_create_compiler(allocator_data);
if (!compiler)
{
SLJIT_FREE(common->private_data_ptrs, allocator_data);
if (common->has_then)
SLJIT_FREE(common->then_offsets, allocator_data);
if (common->verb_offsets != NULL)
SLJIT_FREE(common->verb_offsets, allocator_data);
return PCRE2_ERROR_NOMEMORY;
}

Expand Down Expand Up @@ -14809,8 +14832,8 @@ jit_compile(pcre2_code *code, sljit_u32 mode)
{
sljit_free_compiler(compiler);
SLJIT_FREE(common->private_data_ptrs, allocator_data);
if (common->has_then)
SLJIT_FREE(common->then_offsets, allocator_data);
if (common->verb_offsets != NULL)
SLJIT_FREE(common->verb_offsets, allocator_data);
PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data);
return PCRE2_ERROR_NOMEMORY;
}
Expand Down Expand Up @@ -14894,8 +14917,8 @@ jit_compile(pcre2_code *code, sljit_u32 mode)
{
sljit_free_compiler(compiler);
SLJIT_FREE(common->private_data_ptrs, allocator_data);
if (common->has_then)
SLJIT_FREE(common->then_offsets, allocator_data);
if (common->verb_offsets != NULL)
SLJIT_FREE(common->verb_offsets, allocator_data);
PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data);
return PCRE2_ERROR_NOMEMORY;
}
Expand Down Expand Up @@ -15013,8 +15036,8 @@ jit_compile(pcre2_code *code, sljit_u32 mode)

sljit_free_compiler(compiler);
SLJIT_FREE(common->private_data_ptrs, allocator_data);
if (common->has_then)
SLJIT_FREE(common->then_offsets, allocator_data);
if (common->verb_offsets != NULL)
SLJIT_FREE(common->verb_offsets, allocator_data);
PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data);
return PCRE2_ERROR_NOMEMORY;
}
Expand Down Expand Up @@ -15182,8 +15205,8 @@ jit_compile(pcre2_code *code, sljit_u32 mode)
#endif /* SUPPORT_UNICODE */

SLJIT_FREE(common->private_data_ptrs, allocator_data);
if (common->has_then)
SLJIT_FREE(common->then_offsets, allocator_data);
if (common->verb_offsets != NULL)
SLJIT_FREE(common->verb_offsets, allocator_data);

executable_func = sljit_generate_code(compiler, 0, NULL);
executable_size = sljit_get_generated_code_size(compiler);
Expand Down
24 changes: 23 additions & 1 deletion testdata/testinput2
Original file line number Diff line number Diff line change
Expand Up @@ -5527,13 +5527,35 @@ a)"xI
aa
aaaa

/a+?b|a+?(*THEN)/endanchored
/a+?b|a+?(*THEN:arg)/endanchored
aaxaa
aaxaab

/a+?(?:b(*THEN)c|c(*THEN)b)/endanchored
aaabcaaacbaaabc

/a+?(*SKIP)/endanchored
aa
aaaa

/a+?b|a+?(*SKIP:arg)/endanchored
aaxaa
aaxaab

/a+?(?:b(*SKIP)c|c(*SKIP)b)/endanchored
aaabcaaacbaaabc

/a+?(*PRUNE)/endanchored
aa
aaaa

/a+?b|a+?(*PRUNE:arg)/endanchored
aaxaa
aaxaab

/a+?(?:b(*PRUNE)c|c(*PRUNE)b)/endanchored
aaabcaaacbaaabc

# Check auto-anchoring when there is a group that is never obeyed at
# the start of a branch.

Expand Down
34 changes: 33 additions & 1 deletion testdata/testoutput2
Original file line number Diff line number Diff line change
Expand Up @@ -17168,7 +17168,7 @@ No match
aaaa
0: a

/a+?b|a+?(*THEN)/endanchored
/a+?b|a+?(*THEN:arg)/endanchored
aaxaa
0: a
aaxaab
Expand All @@ -17178,6 +17178,38 @@ No match
aaabcaaacbaaabc
0: aaabc

/a+?(*SKIP)/endanchored
aa
0: a
aaaa
0: a

/a+?b|a+?(*SKIP:arg)/endanchored
aaxaa
0: aa
aaxaab
0: aab

/a+?(?:b(*SKIP)c|c(*SKIP)b)/endanchored
aaabcaaacbaaabc
0: aaabc

/a+?(*PRUNE)/endanchored
aa
0: a
aaaa
0: a

/a+?b|a+?(*PRUNE:arg)/endanchored
aaxaa
0: a
aaxaab
0: aab

/a+?(?:b(*PRUNE)c|c(*PRUNE)b)/endanchored
aaabcaaacbaaabc
0: aaabc

# Check auto-anchoring when there is a group that is never obeyed at
# the start of a branch.

Expand Down
Loading