@@ -218,7 +218,6 @@ static void S_setup_eval_state(pTHX_ regmatch_info *const reginfo);
218
218
static void S_cleanup_regmatch_info_aux (pTHX_ void * arg );
219
219
static regmatch_state * S_push_slab (pTHX );
220
220
221
- #define REGCP_PAREN_ELEMS 3
222
221
#define REGCP_OTHER_ELEMS 3
223
222
#define REGCP_FRAME_ELEMS 1
224
223
/* REGCP_FRAME_ELEMS are not part of the REGCP_OTHER_ELEMS and
@@ -228,19 +227,23 @@ STATIC CHECKPOINT
228
227
S_regcppush (pTHX_ const regexp * rex , I32 parenfloor , U32 maxopenparen _pDEPTH )
229
228
{
230
229
const int retval = PL_savestack_ix ;
231
- const int paren_elems_to_push =
232
- (maxopenparen - parenfloor ) * REGCP_PAREN_ELEMS ;
230
+ const SSize_t paren_bytes_to_push = sizeof (* rex -> offs ) * (maxopenparen - parenfloor );
231
+ /* Number of savestack[] entries to be filled by the paren data */
232
+ const int paren_elems_to_push = (paren_bytes_to_push + sizeof (* PL_savestack ) - 1 ) / sizeof (* PL_savestack );
233
233
const UV total_elems = paren_elems_to_push + REGCP_OTHER_ELEMS ;
234
234
const UV elems_shifted = total_elems << SAVE_TIGHT_SHIFT ;
235
235
I32 p ;
236
236
DECLARE_AND_GET_RE_DEBUG_FLAGS ;
237
237
238
+ /* static assert that offs struc size is not less than stack elem size */
239
+ STATIC_ASSERT_STMT (sizeof (* rex -> offs ) >= sizeof (* PL_savestack ));
240
+
238
241
PERL_ARGS_ASSERT_REGCPPUSH ;
239
242
240
243
if (paren_elems_to_push < 0 )
241
- Perl_croak (aTHX_ "panic: paren_elems_to_push, %i < 0, maxopenparen: %i parenfloor: %i REGCP_PAREN_ELEMS: %u " ,
244
+ Perl_croak (aTHX_ "panic: paren_elems_to_push, %i < 0, maxopenparen: %i parenfloor: %i" ,
242
245
(int )paren_elems_to_push , (int )maxopenparen ,
243
- (int )parenfloor , ( unsigned ) REGCP_PAREN_ELEMS );
246
+ (int )parenfloor );
244
247
245
248
if ((elems_shifted >> SAVE_TIGHT_SHIFT ) != total_elems )
246
249
Perl_croak (aTHX_ "panic: paren_elems_to_push offset %" UVuf
@@ -249,31 +252,35 @@ S_regcppush(pTHX_ const regexp *rex, I32 parenfloor, U32 maxopenparen _pDEPTH)
249
252
(unsigned long )maxopenparen ,
250
253
(long )parenfloor );
251
254
252
- SSGROW (total_elems + REGCP_FRAME_ELEMS );
253
-
254
255
DEBUG_BUFFERS_r (
255
256
if ((int )maxopenparen > (int )parenfloor )
256
- Perl_re_exec_indentf ( aTHX_
257
+ Perl_re_exec_indentf (aTHX_
257
258
"rex=0x%" UVxf " offs=0x%" UVxf ": saving capture indices:\n" ,
258
259
depth ,
259
260
PTR2UV (rex ),
260
261
PTR2UV (rex -> offs )
261
262
);
262
263
);
263
- for (p = parenfloor + 1 ; p <= (I32 )maxopenparen ; p ++ ) {
264
- /* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
265
- SSPUSHIV (rex -> offs [p ].end );
266
- SSPUSHIV (rex -> offs [p ].start );
267
- SSPUSHINT (rex -> offs [p ].start_tmp );
268
- DEBUG_BUFFERS_r (Perl_re_exec_indentf ( aTHX_
269
- " \\%" UVuf ": %" IVdf "(%" IVdf ")..%" IVdf "\n" ,
270
- depth ,
271
- (UV )p ,
272
- (IV )rex -> offs [p ].start ,
273
- (IV )rex -> offs [p ].start_tmp ,
274
- (IV )rex -> offs [p ].end
275
- ));
276
- }
264
+
265
+ SSGROW (total_elems + REGCP_FRAME_ELEMS );
266
+
267
+ /* memcpy the offs inside the stack - it's faster than for loop */
268
+ memcpy (& PL_savestack [PL_savestack_ix ], rex -> offs + parenfloor + 1 , paren_bytes_to_push );
269
+ PL_savestack_ix += paren_elems_to_push ;
270
+
271
+ DEBUG_BUFFERS_r (
272
+ for (p = parenfloor + 1 ; p <= (I32 )maxopenparen ; p ++ ) {
273
+ Perl_re_exec_indentf (aTHX_
274
+ " \\%" UVuf ": %" IVdf "(%" IVdf ")..%" IVdf "\n" ,
275
+ depth ,
276
+ (UV )p ,
277
+ (IV )rex -> offs [p ].start ,
278
+ (IV )rex -> offs [p ].start_tmp ,
279
+ (IV )rex -> offs [p ].end
280
+ );
281
+ }
282
+ );
283
+
277
284
/* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
278
285
SSPUSHINT (maxopenparen );
279
286
SSPUSHINT (rex -> lastparen );
@@ -366,25 +373,31 @@ S_regcppop(pTHX_ regexp *rex, U32 *maxopenparen_p _pDEPTH)
366
373
PTR2UV (rex -> offs )
367
374
);
368
375
);
369
- paren = * maxopenparen_p ;
370
- for ( ; i > 0 ; i -= REGCP_PAREN_ELEMS ) {
371
- SSize_t tmps ;
372
- rex -> offs [paren ].start_tmp = SSPOPINT ;
373
- rex -> offs [paren ].start = SSPOPIV ;
374
- tmps = SSPOPIV ;
375
- if (paren <= rex -> lastparen )
376
- rex -> offs [paren ].end = tmps ;
377
- DEBUG_BUFFERS_r ( Perl_re_exec_indentf ( aTHX_
378
- " \\%" UVuf ": %" IVdf "(%" IVdf ")..%" IVdf "%s\n" ,
379
- depth ,
380
- (UV )paren ,
381
- (IV )rex -> offs [paren ].start ,
382
- (IV )rex -> offs [paren ].start_tmp ,
383
- (IV )rex -> offs [paren ].end ,
384
- (paren > rex -> lastparen ? "(skipped)" : "" ));
385
- );
386
- paren -- ;
387
- }
376
+ /* substract remaining elements from the stack */
377
+ PL_savestack_ix -= i ;
378
+
379
+ /* calculate number of offs/capture groups stored */
380
+ i = (i * sizeof (* PL_savestack )) / sizeof (* rex -> offs );
381
+
382
+ /* calculate paren starting point */
383
+ paren = * maxopenparen_p - i + 1 ;
384
+
385
+ /* restore them */
386
+ memcpy (rex -> offs + paren , & PL_savestack [PL_savestack_ix ], i * sizeof (* rex -> offs ));
387
+
388
+ DEBUG_BUFFERS_r (
389
+ for (; paren <= * maxopenparen_p ; ++ paren ) {
390
+ DEBUG_BUFFERS_r (Perl_re_exec_indentf (aTHX_
391
+ " \\%" UVuf ": %" IVdf "(%" IVdf ")..%" IVdf "%s\n" ,
392
+ depth ,
393
+ (UV )paren ,
394
+ (IV )rex -> offs [paren ].start ,
395
+ (IV )rex -> offs [paren ].start_tmp ,
396
+ (IV )rex -> offs [paren ].end ,
397
+ (paren > rex -> lastparen ? "(skipped)" : "" ));
398
+ );
399
+ }
400
+ );
388
401
#if 1
389
402
/* It would seem that the similar code in regtry()
390
403
* already takes care of this, and in fact it is in
0 commit comments