Skip to content

Commit c1c1b78

Browse files
authored
Track recorded captures during frame construction (#719)
Avoid saving the same capture twice. Furthermore use a bitset for optimized captures to reduce memory consumption.
1 parent e1737b5 commit c1c1b78

File tree

2 files changed

+97
-48
lines changed

2 files changed

+97
-48
lines changed

src/pcre2_jit_compile.c

Lines changed: 96 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,10 @@ typedef struct compiler_common {
398398
sljit_s32 *private_data_ptrs;
399399
/* Chain list of read-only data ptrs. */
400400
void *read_only_data_head;
401-
/* Tells whether the capturing bracket is optimized. */
402-
sljit_u8 *optimized_cbracket;
401+
/* Bitset which tells which capture brackets can be optimized. */
402+
sljit_u8 *optimized_cbrackets;
403+
/* Bitset for tracking capture bracket status. */
404+
sljit_u8 *cbracket_bitset;
403405
/* Tells whether the starting offset is a target of then. */
404406
sljit_u8 *then_offsets;
405407
/* Current position where a THEN must jump. */
@@ -443,6 +445,8 @@ typedef struct compiler_common {
443445
/* Locals used by fast fail optimization. */
444446
sljit_s32 early_fail_start_ptr;
445447
sljit_s32 early_fail_end_ptr;
448+
/* Byte length of optimized_cbrackets and cbracket_bitset. */
449+
sljit_u32 cbracket_bitset_length;
446450
/* Variables used by recursive call generator. */
447451
sljit_s32 recurse_bitset_size;
448452
uint8_t *recurse_bitset;
@@ -1143,6 +1147,18 @@ if (*cc >= OP_CRSTAR && *cc <= OP_CRPOSRANGE)
11431147
return (current_locals_size >= locals_size) ? current_locals_size : locals_size;
11441148
}
11451149

1150+
static SLJIT_INLINE BOOL is_optimized_cbracket(compiler_common *common, sljit_s32 capture_index)
1151+
{
1152+
sljit_u8 bit = (sljit_u8)(1 << (capture_index & 0x7));
1153+
return (common->optimized_cbrackets[capture_index >> 3] & bit) != 0;
1154+
}
1155+
1156+
static SLJIT_INLINE void clear_optimized_cbracket(compiler_common *common, sljit_s32 capture_index)
1157+
{
1158+
sljit_u8 mask = (sljit_u8)~(1 << (capture_index & 0x7));
1159+
common->optimized_cbrackets[capture_index >> 3] &= mask;
1160+
}
1161+
11461162
static BOOL check_opcode_types(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend)
11471163
{
11481164
int count;
@@ -1193,7 +1209,7 @@ while (cc < ccend)
11931209
case OP_REFI:
11941210
case OP_REF:
11951211
locals_size = ref_update_local_size(common, cc, locals_size);
1196-
common->optimized_cbracket[GET2(cc, 1)] = 0;
1212+
clear_optimized_cbracket(common, GET2(cc, 1));
11971213
cc += PRIV(OP_lengths)[*cc];
11981214
break;
11991215

@@ -1208,7 +1224,7 @@ while (cc < ccend)
12081224

12091225
case OP_CBRAPOS:
12101226
case OP_SCBRAPOS:
1211-
common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] = 0;
1227+
clear_optimized_cbracket(common, GET2(cc, 1 + LINK_SIZE));
12121228
cc += 1 + LINK_SIZE + IMM2_SIZE;
12131229
break;
12141230

@@ -1222,7 +1238,7 @@ while (cc < ccend)
12221238
break;
12231239

12241240
case OP_CREF:
1225-
common->optimized_cbracket[GET2(cc, 1)] = 0;
1241+
clear_optimized_cbracket(common, GET2(cc, 1));
12261242
cc += 1 + IMM2_SIZE;
12271243
break;
12281244

@@ -1235,7 +1251,7 @@ while (cc < ccend)
12351251
slot = common->name_table + GET2(cc, 1) * common->name_entry_size;
12361252
while (count-- > 0)
12371253
{
1238-
common->optimized_cbracket[GET2(slot, 0)] = 0;
1254+
clear_optimized_cbracket(common, GET2(slot, 0));
12391255
slot += common->name_entry_size;
12401256
}
12411257
cc += PRIV(OP_lengths)[*cc];
@@ -1247,7 +1263,7 @@ while (cc < ccend)
12471263
cc += 1 + LINK_SIZE;
12481264
while (*cc == OP_CREF)
12491265
{
1250-
common->optimized_cbracket[GET2(cc, 1)] = 0;
1266+
clear_optimized_cbracket(common, GET2(cc, 1));
12511267
cc += 1 + IMM2_SIZE;
12521268
}
12531269
break;
@@ -1384,7 +1400,7 @@ int result = 0;
13841400
int count, prev_count;
13851401

13861402
SLJIT_ASSERT(*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA);
1387-
SLJIT_ASSERT(*cc != OP_CBRA || common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] != 0);
1403+
SLJIT_ASSERT(*cc != OP_CBRA || is_optimized_cbracket(common, GET2(cc, 1 + LINK_SIZE)));
13881404
SLJIT_ASSERT(start < EARLY_FAIL_ENHANCE_MAX);
13891405

13901406
next_alt = cc + GET(cc, 1);
@@ -1662,7 +1678,7 @@ do
16621678
count = 3;
16631679

16641680
end = bracketend(cc);
1665-
if (end[-1 - LINK_SIZE] != OP_KET || (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0))
1681+
if (end[-1 - LINK_SIZE] != OP_KET || (*cc == OP_CBRA && !is_optimized_cbracket(common, GET2(cc, 1 + LINK_SIZE))))
16661682
break;
16671683

16681684
prev_count = detect_early_fail(common, cc, private_data_start, depth + 1, prev_count);
@@ -2124,11 +2140,22 @@ while (cc < ccend)
21242140
*private_data_start = private_data_ptr;
21252141
}
21262142

2143+
static SLJIT_INLINE BOOL is_cbracket_processed(compiler_common *common, sljit_s32 capture_index)
2144+
{
2145+
sljit_u8 bit = (sljit_u8)(1 << (capture_index & 0x7));
2146+
sljit_u8 *ptr = common->cbracket_bitset + (capture_index >> 3);
2147+
sljit_u8 value = *ptr;
2148+
2149+
*ptr |= bit;
2150+
return (value & bit) != 0;
2151+
}
2152+
21272153
/* Returns with a frame_types (always < 0) if no need for frame. */
21282154
static int get_framesize(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, BOOL recursive, BOOL *needs_control_head)
21292155
{
21302156
int length = 0;
21312157
int possessive = 0;
2158+
int offset;
21322159
BOOL stack_restore = FALSE;
21332160
BOOL setsom_found = recursive;
21342161
BOOL setmark_found = recursive;
@@ -2142,6 +2169,8 @@ SLJIT_ASSERT(common->control_head_ptr != 0);
21422169
*needs_control_head = FALSE;
21432170
#endif
21442171

2172+
memset(common->cbracket_bitset, 0, common->cbracket_bitset_length);
2173+
21452174
if (ccend == NULL)
21462175
{
21472176
ccend = bracketend(cc) - (1 + LINK_SIZE);
@@ -2202,10 +2231,13 @@ while (cc < ccend)
22022231
length += 2;
22032232
capture_last_found = TRUE;
22042233
}
2234+
22052235
cc += 1 + LINK_SIZE;
22062236
while (*cc == OP_CREF)
22072237
{
2208-
length += 3;
2238+
offset = GET2(cc, 1);
2239+
if (!is_cbracket_processed(common, offset))
2240+
length += 3;
22092241
cc += 1 + IMM2_SIZE;
22102242
}
22112243
break;
@@ -2220,7 +2252,10 @@ while (cc < ccend)
22202252
length += 2;
22212253
capture_last_found = TRUE;
22222254
}
2223-
length += 3;
2255+
2256+
offset = GET2(cc, 1 + LINK_SIZE);
2257+
if (!is_cbracket_processed(common, offset))
2258+
length += 3;
22242259
cc += 1 + LINK_SIZE + IMM2_SIZE;
22252260
break;
22262261

@@ -2333,6 +2368,8 @@ int offset;
23332368
SLJIT_UNUSED_ARG(stacktop);
23342369
SLJIT_ASSERT(stackpos >= stacktop + 2);
23352370

2371+
memset(common->cbracket_bitset, 0, common->cbracket_bitset_length);
2372+
23362373
stackpos = STACK(stackpos);
23372374
if (ccend == NULL)
23382375
{
@@ -2408,15 +2445,19 @@ while (cc < ccend)
24082445
cc += 1 + LINK_SIZE;
24092446
while (*cc == OP_CREF)
24102447
{
2411-
offset = (GET2(cc, 1)) << 1;
2412-
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset));
2413-
stackpos -= SSIZE_OF(sw);
2414-
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
2415-
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
2416-
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
2417-
stackpos -= SSIZE_OF(sw);
2418-
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0);
2419-
stackpos -= SSIZE_OF(sw);
2448+
offset = GET2(cc, 1);
2449+
if (!is_cbracket_processed(common, offset))
2450+
{
2451+
offset <<= 1;
2452+
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset));
2453+
stackpos -= SSIZE_OF(sw);
2454+
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
2455+
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
2456+
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
2457+
stackpos -= SSIZE_OF(sw);
2458+
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0);
2459+
stackpos -= SSIZE_OF(sw);
2460+
}
24202461
cc += 1 + IMM2_SIZE;
24212462
}
24222463
break;
@@ -2434,15 +2475,20 @@ while (cc < ccend)
24342475
stackpos -= SSIZE_OF(sw);
24352476
capture_last_found = TRUE;
24362477
}
2437-
offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
2438-
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset));
2439-
stackpos -= SSIZE_OF(sw);
2440-
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
2441-
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
2442-
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
2443-
stackpos -= SSIZE_OF(sw);
2444-
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0);
2445-
stackpos -= SSIZE_OF(sw);
2478+
2479+
offset = GET2(cc, 1 + LINK_SIZE);
2480+
if (!is_cbracket_processed(common, offset))
2481+
{
2482+
offset <<= 1;
2483+
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset));
2484+
stackpos -= SSIZE_OF(sw);
2485+
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
2486+
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
2487+
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
2488+
stackpos -= SSIZE_OF(sw);
2489+
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0);
2490+
stackpos -= SSIZE_OF(sw);
2491+
}
24462492

24472493
cc += 1 + LINK_SIZE + IMM2_SIZE;
24482494
break;
@@ -2676,7 +2722,7 @@ while (cc < ccend)
26762722
SLJIT_ASSERT(recurse_check_bit(common, OVECTOR((offset << 1) + 1)));
26772723
length += 2;
26782724
}
2679-
if (common->optimized_cbracket[offset] == 0 && recurse_check_bit(common, OVECTOR_PRIV(offset)))
2725+
if (!is_optimized_cbracket(common, offset) && recurse_check_bit(common, OVECTOR_PRIV(offset)))
26802726
length++;
26812727
if (common->capture_last_ptr != 0 && recurse_check_bit(common, common->capture_last_ptr))
26822728
length++;
@@ -3078,7 +3124,7 @@ while (cc < ccend)
30783124
shared_count++;
30793125
}
30803126

3081-
if (common->optimized_cbracket[offset] == 0)
3127+
if (!is_optimized_cbracket(common, offset))
30823128
{
30833129
private_srcw[0] = OVECTOR_PRIV(offset);
30843130
if (recurse_check_bit(common, private_srcw[0]))
@@ -9434,7 +9480,7 @@ if (common->capture_last_ptr != 0)
94349480
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
94359481
stacksize++;
94369482
}
9437-
if (common->optimized_cbracket[offset >> 1] == 0)
9483+
if (!is_optimized_cbracket(common, offset >> 1))
94389484
{
94399485
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
94409486
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
@@ -9608,7 +9654,7 @@ if (opcode == OP_CBRA || opcode == OP_SCBRA)
96089654
{
96099655
/* Capturing brackets has a pre-allocated space. */
96109656
offset = GET2(ccbegin, 1 + LINK_SIZE);
9611-
if (common->optimized_cbracket[offset] == 0)
9657+
if (!is_optimized_cbracket(common, offset))
96129658
{
96139659
private_data_ptr = OVECTOR_PRIV(offset);
96149660
offset <<= 1;
@@ -9789,7 +9835,7 @@ if (opcode == OP_ONCE)
97899835
else if (opcode == OP_CBRA || opcode == OP_SCBRA)
97909836
{
97919837
/* Saving the previous values. */
9792-
if (common->optimized_cbracket[offset >> 1] != 0)
9838+
if (is_optimized_cbracket(common, offset >> 1))
97939839
{
97949840
SLJIT_ASSERT(private_data_ptr == OVECTOR(offset));
97959841
allocate_stack(common, 2);
@@ -10068,7 +10114,7 @@ if (offset != 0)
1006810114
{
1006910115
if (common->capture_last_ptr != 0)
1007010116
stacksize++;
10071-
if (common->optimized_cbracket[offset >> 1] == 0)
10117+
if (!is_optimized_cbracket(common, offset >> 1))
1007210118
stacksize += 2;
1007310119
}
1007410120
if (has_alternatives && opcode != OP_ONCE)
@@ -10119,7 +10165,7 @@ if (has_alternatives)
1011910165
}
1012010166

1012110167
/* Must be after the matchingpath label. */
10122-
if (offset != 0 && common->optimized_cbracket[offset >> 1] != 0)
10168+
if (offset != 0 && is_optimized_cbracket(common, offset >> 1))
1012310169
{
1012410170
SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0));
1012510171
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
@@ -10281,7 +10327,7 @@ switch(opcode)
1028110327
offset = GET2(cc, 1 + LINK_SIZE);
1028210328
/* This case cannot be optimized in the same way as
1028310329
normal capturing brackets. */
10284-
SLJIT_ASSERT(common->optimized_cbracket[offset] == 0);
10330+
SLJIT_ASSERT(!is_optimized_cbracket(common, offset));
1028510331
cbraprivptr = OVECTOR_PRIV(offset);
1028610332
offset <<= 1;
1028710333
ccbegin = cc + 1 + LINK_SIZE + IMM2_SIZE;
@@ -11463,7 +11509,7 @@ static SLJIT_INLINE PCRE2_SPTR compile_close_matchingpath(compiler_common *commo
1146311509
{
1146411510
DEFINE_COMPILER;
1146511511
int offset = GET2(cc, 1);
11466-
BOOL optimized_cbracket = common->optimized_cbracket[offset] != 0;
11512+
BOOL optimized_cbracket = is_optimized_cbracket(common, offset);
1146711513

1146811514
/* Data will be discarded anyway... */
1146911515
if (common->currententry != NULL)
@@ -12334,7 +12380,7 @@ if (offset != 0)
1233412380
{
1233512381
if (common->capture_last_ptr != 0)
1233612382
{
12337-
SLJIT_ASSERT(common->optimized_cbracket[offset >> 1] == 0);
12383+
SLJIT_ASSERT(!is_optimized_cbracket(common, offset >> 1));
1233812384
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
1233912385
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
1234012386
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0);
@@ -12343,7 +12389,7 @@ if (offset != 0)
1234312389
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP2, 0);
1234412390
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0);
1234512391
}
12346-
else if (common->optimized_cbracket[offset >> 1] == 0)
12392+
else if (!is_optimized_cbracket(common, offset >> 1))
1234712393
{
1234812394
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
1234912395
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
@@ -12525,7 +12571,7 @@ if (has_alternatives)
1252512571
{
1252612572
if (common->capture_last_ptr != 0)
1252712573
stacksize++;
12528-
if (common->optimized_cbracket[offset >> 1] == 0)
12574+
if (!is_optimized_cbracket(common, offset >> 1))
1252912575
stacksize += 2;
1253012576
}
1253112577
if (opcode != OP_ONCE)
@@ -12562,7 +12608,7 @@ if (has_alternatives)
1256212608
mov_addr = sljit_emit_mov_addr(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize));
1256312609
}
1256412610

12565-
if (offset != 0 && ket == OP_KETRMAX && common->optimized_cbracket[offset >> 1] != 0)
12611+
if (offset != 0 && ket == OP_KETRMAX && is_optimized_cbracket(common, offset >> 1))
1256612612
{
1256712613
/* If ket is not OP_KETRMAX, this code path is executed after the jump to alternative_matchingpath. */
1256812614
SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0));
@@ -12624,7 +12670,7 @@ if (has_alternatives)
1262412670
if (offset != 0)
1262512671
{
1262612672
/* Using both tmp register is better for instruction scheduling. */
12627-
if (common->optimized_cbracket[offset >> 1] != 0)
12673+
if (is_optimized_cbracket(common, offset >> 1))
1262812674
{
1262912675
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
1263012676
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
@@ -13496,7 +13542,8 @@ if (private_data_length > ~(sljit_uw)0 / sizeof(sljit_s32))
1349613542

1349713543
private_data_length *= sizeof(sljit_s32);
1349813544
/* Align to 32 bit. */
13499-
total_length = ((re->top_bracket + 1) + (sljit_uw)(sizeof(sljit_s32) - 1)) & ~(sljit_uw)(sizeof(sljit_s32) - 1);
13545+
common->cbracket_bitset_length = ((re->top_bracket + 1) + (sljit_u32)7) & ~(sljit_u32)7;
13546+
total_length = common->cbracket_bitset_length << 1;
1350013547
if (~(sljit_uw)0 - private_data_length < total_length)
1350113548
return PCRE2_ERROR_NOMEMORY;
1350213549

@@ -13506,12 +13553,13 @@ if (!common->private_data_ptrs)
1350613553
return PCRE2_ERROR_NOMEMORY;
1350713554

1350813555
memset(common->private_data_ptrs, 0, private_data_length);
13509-
common->optimized_cbracket = ((sljit_u8 *)common->private_data_ptrs) + private_data_length;
13556+
common->optimized_cbrackets = ((sljit_u8 *)common->private_data_ptrs) + private_data_length;
1351013557
#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 1
13511-
memset(common->optimized_cbracket, 0, re->top_bracket + 1);
13558+
memset(common->optimized_cbrackets, 0, common->cbracket_bitset_length);
1351213559
#else
13513-
memset(common->optimized_cbracket, 1, re->top_bracket + 1);
13560+
memset(common->optimized_cbrackets, 0xff, common->cbracket_bitset_length);
1351413561
#endif
13562+
common->cbracket_bitset = common->optimized_cbrackets + common->cbracket_bitset_length;
1351513563

1351613564
SLJIT_ASSERT(*common->start == OP_BRA && ccend[-(1 + LINK_SIZE)] == OP_KET);
1351713565
#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 2
@@ -13576,7 +13624,7 @@ if (common->start_ptr == 0)
1357613624

1357713625
/* Capturing brackets cannot be optimized if callouts are allowed. */
1357813626
if (common->capture_last_ptr != 0)
13579-
memset(common->optimized_cbracket, 0, re->top_bracket + 1);
13627+
memset(common->optimized_cbrackets, 0, common->cbracket_bitset_length);
1358013628

1358113629
SLJIT_ASSERT(!(common->req_char_ptr != 0 && common->start_used_ptr != 0));
1358213630
common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw);

0 commit comments

Comments
 (0)