@@ -15,6 +15,7 @@ static struct mro_alg c3_alg =
15
15
typedef struct {
16
16
SV * sv_UNIVERSAL ;
17
17
SV * sv_dfs ;
18
+ SV * sv_c3 ;
18
19
SV * sv_ISA ;
19
20
} my_cxt_t ;
20
21
@@ -27,6 +28,8 @@ init_MY_CXT(pTHX_ pMY_CXT)
27
28
SvREADONLY_on (MY_CXT .sv_UNIVERSAL );
28
29
MY_CXT .sv_dfs = newSVpvs_share ("dfs" );
29
30
SvREADONLY_on (MY_CXT .sv_dfs );
31
+ MY_CXT .sv_c3 = newSVpvn_share ("c3" , sizeof ("c3" )- 1 , c3_alg .hash );
32
+ SvREADONLY_on (MY_CXT .sv_c3 );
30
33
MY_CXT .sv_ISA = newSVpvs_share ("ISA" );
31
34
SvREADONLY_on (MY_CXT .sv_ISA );
32
35
}
@@ -124,8 +127,9 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
124
127
if (!isa_item_stash ) {
125
128
/* if no stash, make a temporary fake MRO
126
129
containing just itself */
130
+ SV * nsv = mro_newSVsvhekok (isa_item );
127
131
AV * const isa_lin = newAV_alloc_xz (4 );
128
- av_push_simple (isa_lin , mro_newSVsvhekok ( isa_item ) );
132
+ av_push_simple (isa_lin , nsv );
129
133
av_push_simple (seqs , MUTABLE_SV (isa_lin ));
130
134
}
131
135
else {
@@ -205,11 +209,12 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
205
209
}
206
210
}
207
211
}
208
-
212
+ {
209
213
/* Initialize retval to build the return value in */
210
- retval = newAV_alloc_xz (4 );
211
- av_push_simple (retval , newSVhek (stashhek )); /* us first */
212
-
214
+ SV * nsv = newSVhek (stashhek );
215
+ retval = newAV_alloc_xz (4 );
216
+ av_push_simple (retval , nsv ); /* us first */
217
+ }
213
218
/* This loop won't terminate until we either finish building
214
219
the MRO, or get an exception. */
215
220
while (1 ) {
@@ -284,13 +289,15 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
284
289
hierarchy is not C3-incompatible */
285
290
if (!winner ) {
286
291
SV * errmsg ;
287
- Size_t i ;
292
+ SSize_t i ;
293
+ SSize_t count ;
288
294
289
295
errmsg = newSVpvf (
290
296
"Inconsistent hierarchy during C3 merge of class '%" HEKf "':\n\t"
291
297
"current merge results [\n" ,
292
298
HEKfARG (stashhek ));
293
- for (i = 0 ; i < av_count (retval ); i ++ ) {
299
+ count = av_count (retval );
300
+ for (i = 0 ; i < count ; i ++ ) {
294
301
SV * * elem = av_fetch (retval , i , 0 );
295
302
sv_catpvf (errmsg , "\t\t%" SVf ",\n" , SVfARG (* elem ));
296
303
}
@@ -306,9 +313,12 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
306
313
}
307
314
}
308
315
else { /* @ISA was undefined or empty */
316
+ /* Do this 1st, the next 2 AV* API calls are likely to be inlined and
317
+ optimize away alot of AvFILL/memset/Renew logic if nothing is between them. */
318
+ SV * nsv = newSVhek (stashhek );
309
319
/* build a retval containing only ourselves */
310
320
retval = newAV_alloc_xz (4 );
311
- av_push_simple (retval , newSVhek ( stashhek ) );
321
+ av_push_simple (retval , nsv );
312
322
}
313
323
314
324
done :
@@ -365,6 +375,9 @@ PPCODE:
365
375
sv = MY_CXT .sv_dfs ;
366
376
MY_CXT .sv_dfs = NULL ;
367
377
SvREFCNT_dec_NN (sv );
378
+ sv = MY_CXT .sv_c3 ;
379
+ MY_CXT .sv_c3 = NULL ;
380
+ SvREFCNT_dec_NN (sv );
368
381
sv = MY_CXT .sv_ISA ;
369
382
MY_CXT .sv_ISA = NULL ;
370
383
SvREFCNT_dec_NN (sv );
@@ -388,8 +401,9 @@ mro_get_linear_isa(...)
388
401
389
402
if (!class_stash ) {
390
403
/* No stash exists yet, give them just the classname */
404
+ SV * nsv = mro_newSVsvhekok (classname );
391
405
AV * isalin = newAV_alloc_xz (4 );
392
- av_push_simple (isalin , mro_newSVsvhekok ( classname ) );
406
+ av_push_simple (isalin , nsv );
393
407
ST (0 ) = sv_2mortal (newRV_noinc (MUTABLE_SV (isalin )));
394
408
XSRETURN (1 );
395
409
}
@@ -433,6 +447,7 @@ mro_get_mro(...)
433
447
SV * classname ;
434
448
HV * class_stash ;
435
449
SV * retsv ;
450
+ U32 which_my_cxt ; /* rel offset MY_CXT, prevents 2 sep dMY_CXT deref lines */
436
451
PPCODE :
437
452
if (items != 1 )
438
453
croak_xs_usage (cv , "classname ");
@@ -442,12 +457,28 @@ mro_get_mro(...)
442
457
443
458
if (class_stash ) {
444
459
const struct mro_alg * const meta = HvMROMETA (class_stash )-> mro_which ;
445
- retsv = newSVpvn_flags (meta -> name , meta -> length ,
446
- SVs_TEMP
447
- | ((meta -> kflags & HVhek_UTF8 ) ? SVf_UTF8 : 0 ));
460
+ if (memEQs (meta -> name , meta -> length , "dfs" )) /* skipping meta->kflags & HVhek_UTF8 */
461
+ goto ret_dfs ;
462
+ /* "c3" shows up here running mro's .t'es */
463
+ else if (memEQs (meta -> name , meta -> length , "c3" )) {
464
+ which_my_cxt = STRUCT_OFFSET (my_cxt_t , sv_c3 );
465
+ goto ret_my_cxt_hek ;
466
+ }
467
+ else { /* pretty sure this string already exists inside PL_strtab by now */
468
+ I32 i32len = meta -> kflags & HVhek_UTF8 ? - (I32 )meta -> length : (I32 )meta -> length ;
469
+ retsv = sv_2mortal (newSVpvn_share (meta -> name , i32len , meta -> hash ));
470
+ }
448
471
} else {
449
- dMY_CXT ;
450
- retsv = newSVhek_mortal (SvSHARED_HEK_FROM_PV (SvPVX (MY_CXT .sv_dfs )));
472
+ ret_dfs :
473
+ which_my_cxt = STRUCT_OFFSET (my_cxt_t , sv_dfs );
474
+
475
+ ret_my_cxt_hek :
476
+ {
477
+ dMY_CXT ;
478
+ SV * * svp = NUM2PTR (SV * * ,(PTR2nat (& MY_CXT )+ which_my_cxt ));
479
+ SV * svhek = * svp ;
480
+ retsv = newSVhek_mortal (SvSHARED_HEK_FROM_PV (SvPVX (svhek )));
481
+ }
451
482
}
452
483
PUSHs (retsv );
453
484
551
582
mro__nextcan (...)
552
583
PREINIT :
553
584
SV * self = ST (0 );
554
- const I32 throw_nomethod = SvIVX (ST (1 ));
585
+ const bool throw_nomethod = cBOOL ( SvIVX (ST (1 ) ));
555
586
I32 cxix = cxstack_ix ;
556
587
const PERL_CONTEXT * ccstack = cxstack ;
557
588
const PERL_SI * top_si = PL_curstackinfo ;
@@ -654,8 +685,10 @@ mro__nextcan(...)
654
685
/* Initialize the next::method cache for this stash
655
686
if necessary */
656
687
selfmeta = HvMROMETA (selfstash );
657
- if (!(nmcache = selfmeta -> mro_nextmethod )) {
658
- nmcache = selfmeta -> mro_nextmethod = newHV ();
688
+ nmcache = selfmeta -> mro_nextmethod ;
689
+ if (!nmcache ) {
690
+ nmcache = newHV ();
691
+ selfmeta -> mro_nextmethod = nmcache ;
659
692
}
660
693
else { /* Use the cached coderef if it exists */
661
694
HE * cache_entry = hv_fetch_ent (nmcache , sv , 0 , 0 );
@@ -678,8 +711,10 @@ mro__nextcan(...)
678
711
/* beyond here is just for cache misses, so perf isn't as critical */
679
712
680
713
stashname_len = subname - fq_subname - 2 ;
681
- stashname = newSVpvn_flags (fq_subname , stashname_len ,
682
- SVs_TEMP | (subname_utf8 ? SVf_UTF8 : 0 ));
714
+ { /* strs like "Qux::foo" "TTop::foo" show up here */
715
+ I32 i32len = subname_utf8 ? - (I32 )stashname_len : (I32 )stashname_len ;
716
+ stashname = sv_2mortal (newSVpvn_share (fq_subname , i32len , 0 ));
717
+ }
683
718
684
719
/* has ourselves at the top of the list */
685
720
linear_av = S_mro_get_linear_isa_c3 (aTHX_ selfstash , 0 );
0 commit comments