Assertion code generator in JIT has been optimized.

This commit is contained in:
Zoltán Herczeg 2015-03-12 11:21:38 +00:00
parent d0cf279d87
commit bccfdcb172
2 changed files with 82 additions and 13 deletions

View File

@ -1393,6 +1393,9 @@ while (cc < ccend)
case OP_NCLASS: case OP_NCLASS:
case OP_XCLASS: case OP_XCLASS:
case OP_CALLOUT:
case OP_CALLOUT_STR:
cc = next_opcode(common, cc); cc = next_opcode(common, cc);
SLJIT_ASSERT(cc != NULL); SLJIT_ASSERT(cc != NULL);
break; break;
@ -2092,6 +2095,7 @@ static SLJIT_INLINE void allocate_stack(compiler_common *common, int size)
/* May destroy all locals and registers except TMP2. */ /* May destroy all locals and registers except TMP2. */
DEFINE_COMPILER; DEFINE_COMPILER;
SLJIT_ASSERT(size > 0);
OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
#ifdef DESTROY_REGISTERS #ifdef DESTROY_REGISTERS
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345);
@ -2106,6 +2110,7 @@ add_stub(common, CMP(SLJIT_GREATER, STACK_TOP, 0, STACK_LIMIT, 0));
static SLJIT_INLINE void free_stack(compiler_common *common, int size) static SLJIT_INLINE void free_stack(compiler_common *common, int size)
{ {
DEFINE_COMPILER; DEFINE_COMPILER;
SLJIT_ASSERT(size > 0);
OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
} }
@ -6401,6 +6406,32 @@ return cc + callout_length;
#undef CALLOUT_ARG_SIZE #undef CALLOUT_ARG_SIZE
#undef CALLOUT_ARG_OFFSET #undef CALLOUT_ARG_OFFSET
static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(PCRE2_SPTR cc)
{
while (TRUE)
{
switch (*cc)
{
case OP_CALLOUT_STR:
cc += GET(cc, 1 + 2*LINK_SIZE);
break;
case OP_NOT_WORD_BOUNDARY:
case OP_WORD_BOUNDARY:
case OP_CALLOUT:
case OP_ALT:
cc += PRIV(OP_lengths)[*cc];
break;
case OP_KET:
return FALSE;
default:
return TRUE;
}
}
}
static PCRE2_SPTR compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backtrack *backtrack, BOOL conditional) static PCRE2_SPTR compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backtrack *backtrack, BOOL conditional)
{ {
DEFINE_COMPILER; DEFINE_COMPILER;
@ -6457,15 +6488,28 @@ if (bra == OP_BRAMINZERO)
if (framesize < 0) if (framesize < 0)
{ {
extrasize = needs_control_head ? 2 : 1; extrasize = 1;
if (bra == OP_BRA && !assert_needs_str_ptr_saving(ccbegin + 1 + LINK_SIZE))
extrasize = 0;
if (needs_control_head)
extrasize++;
if (framesize == no_frame) if (framesize == no_frame)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0);
allocate_stack(common, extrasize);
if (extrasize > 0)
allocate_stack(common, extrasize);
if (needs_control_head) if (needs_control_head)
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
if (extrasize > 0)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
if (needs_control_head) if (needs_control_head)
{ {
SLJIT_ASSERT(extrasize == 2);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
} }
@ -6474,12 +6518,14 @@ else
{ {
extrasize = needs_control_head ? 3 : 2; extrasize = needs_control_head ? 3 : 2;
allocate_stack(common, framesize + extrasize); allocate_stack(common, framesize + extrasize);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
if (needs_control_head) if (needs_control_head)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
if (needs_control_head) if (needs_control_head)
{ {
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
@ -6488,6 +6534,7 @@ else
} }
else else
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize, FALSE); init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize, FALSE);
} }
@ -6511,7 +6558,7 @@ while (1)
altbacktrack.top = NULL; altbacktrack.top = NULL;
altbacktrack.topbacktracks = NULL; altbacktrack.topbacktracks = NULL;
if (*ccbegin == OP_ALT) if (*ccbegin == OP_ALT && extrasize > 0)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
altbacktrack.cc = ccbegin; altbacktrack.cc = ccbegin;
@ -6540,8 +6587,9 @@ while (1)
{ {
if (framesize == no_frame) if (framesize == no_frame)
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
else else if (extrasize > 0)
free_stack(common, extrasize); free_stack(common, extrasize);
if (needs_control_head) if (needs_control_head)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), 0);
} }
@ -6567,7 +6615,10 @@ while (1)
{ {
/* We know that STR_PTR was stored on the top of the stack. */ /* We know that STR_PTR was stored on the top of the stack. */
if (conditional) if (conditional)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? sizeof(sljit_sw) : 0); {
if (extrasize > 0)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? sizeof(sljit_sw) : 0);
}
else if (bra == OP_BRAZERO) else if (bra == OP_BRAZERO)
{ {
if (framesize < 0) if (framesize < 0)
@ -6644,7 +6695,7 @@ if (needs_control_head)
if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
{ {
/* Assert is failed. */ /* Assert is failed. */
if (conditional || bra == OP_BRAZERO) if ((conditional && extrasize > 0) || bra == OP_BRAZERO)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
if (framesize < 0) if (framesize < 0)
@ -6656,7 +6707,7 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
free_stack(common, 1); free_stack(common, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
} }
else else if (extrasize > 0)
free_stack(common, extrasize); free_stack(common, extrasize);
} }
else else
@ -6681,7 +6732,9 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
if (framesize < 0) if (framesize < 0)
{ {
/* We know that STR_PTR was stored on the top of the stack. */ /* We know that STR_PTR was stored on the top of the stack. */
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 1) * sizeof(sljit_sw)); if (extrasize > 0)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 1) * sizeof(sljit_sw));
/* Keep the STR_PTR on the top of the stack. */ /* Keep the STR_PTR on the top of the stack. */
if (bra == OP_BRAZERO) if (bra == OP_BRAZERO)
{ {
@ -6744,14 +6797,16 @@ else
/* AssertNot is successful. */ /* AssertNot is successful. */
if (framesize < 0) if (framesize < 0)
{ {
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (extrasize > 0)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
if (bra != OP_BRA) if (bra != OP_BRA)
{ {
if (extrasize == 2) if (extrasize == 2)
free_stack(common, 1); free_stack(common, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
} }
else else if (extrasize > 0)
free_stack(common, extrasize); free_stack(common, extrasize);
} }
else else
@ -6813,7 +6868,9 @@ if (framesize < 0)
stacksize = needs_control_head ? 1 : 0; stacksize = needs_control_head ? 1 : 0;
if (ket != OP_KET || has_alternatives) if (ket != OP_KET || has_alternatives)
stacksize++; stacksize++;
free_stack(common, stacksize);
if (stacksize > 0)
free_stack(common, stacksize);
} }
if (needs_control_head) if (needs_control_head)
@ -9203,7 +9260,9 @@ else if (opcode == OP_ONCE)
/* The STR_PTR must be released. */ /* The STR_PTR must be released. */
stacksize++; stacksize++;
} }
free_stack(common, stacksize);
if (stacksize > 0)
free_stack(common, stacksize);
JUMPHERE(once); JUMPHERE(once);
/* Restore previous private_data_ptr */ /* Restore previous private_data_ptr */

View File

@ -579,6 +579,16 @@ static struct regression_test_case regression_test_cases[] = {
{ MU, A, 0, 0, "(?:(?=.)??[a-c])+m", "abacdcbacacdcaccam" }, { MU, A, 0, 0, "(?:(?=.)??[a-c])+m", "abacdcbacacdcaccam" },
{ MU, A, 0, 0, "((?!a)?(?!([^a]))?)+$", "acbab" }, { MU, A, 0, 0, "((?!a)?(?!([^a]))?)+$", "acbab" },
{ MU, A, 0, 0, "((?!a)?\?(?!([^a]))?\?)+$", "acbab" }, { MU, A, 0, 0, "((?!a)?\?(?!([^a]))?\?)+$", "acbab" },
{ MU, A, 0, 0, "a(?=(?C)\\B(?C`x`))b", "ab" },
{ MU, A, 0, 0, "a(?!(?C)\\B(?C`x`))bb|ab", "abb" },
{ MU, A, 0, 0, "a(?=\\b|(?C)\\B(?C`x`))b", "ab" },
{ MU, A, 0, 0, "a(?!\\b|(?C)\\B(?C`x`))bb|ab", "abb" },
{ MU, A, 0, 0, "c(?(?=(?C)\\B(?C`x`))ab|a)", "cab" },
{ MU, A, 0, 0, "c(?(?!(?C)\\B(?C`x`))ab|a)", "cab" },
{ MU, A, 0, 0, "c(?(?=\\b|(?C)\\B(?C`x`))ab|a)", "cab" },
{ MU, A, 0, 0, "c(?(?!\\b|(?C)\\B(?C`x`))ab|a)", "cab" },
{ MU, A, 0, 0, "a(?=)b", "ab" },
{ MU, A, 0, 0 | F_NOMATCH, "a(?!)b", "ab" },
/* Not empty, ACCEPT, FAIL */ /* Not empty, ACCEPT, FAIL */
{ MU, A, PCRE2_NOTEMPTY, 0 | F_NOMATCH, "a*", "bcx" }, { MU, A, PCRE2_NOTEMPTY, 0 | F_NOMATCH, "a*", "bcx" },