@@ -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
}
@@ -121,8 +124,9 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
121
124
if (!isa_item_stash ) {
122
125
/* if no stash, make a temporary fake MRO
123
126
containing just itself */
127
+ SV * nsv = mro_newSVsvhekok (isa_item );
124
128
AV * const isa_lin = newAV_alloc_xz (4 );
125
- av_push_simple (isa_lin , mro_newSVsvhekok ( isa_item ) );
129
+ av_push_simple (isa_lin , nsv );
126
130
av_push_simple (seqs , MUTABLE_SV (isa_lin ));
127
131
}
128
132
else {
@@ -202,11 +206,12 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
202
206
}
203
207
}
204
208
}
205
-
209
+ {
206
210
/* Initialize retval to build the return value in */
207
- retval = newAV_alloc_xz (4 );
208
- av_push_simple (retval , newSVhek (stashhek )); /* us first */
209
-
211
+ SV * nsv = newSVhek (stashhek );
212
+ retval = newAV_alloc_xz (4 );
213
+ av_push_simple (retval , nsv ); /* us first */
214
+ }
210
215
/* This loop won't terminate until we either finish building
211
216
the MRO, or get an exception. */
212
217
while (1 ) {
@@ -280,14 +285,12 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
280
285
/* If we had candidates, but nobody won, then the @ISA
281
286
hierarchy is not C3-incompatible */
282
287
if (!winner ) {
283
- SV * errmsg ;
284
- Size_t i ;
285
-
286
- errmsg = newSVpvf (
288
+ SV * errmsg = newSVpvf (
287
289
"Inconsistent hierarchy during C3 merge of class '%" HEKf "':\n\t"
288
290
"current merge results [\n" ,
289
291
HEKfARG (stashhek ));
290
- for (i = 0 ; i < av_count (retval ); i ++ ) {
292
+ SSize_t count = av_count (retval );
293
+ for (SSize_t i = 0 ; i < count ; i ++ ) {
291
294
SV * * elem = av_fetch (retval , i , 0 );
292
295
sv_catpvf (errmsg , "\t\t%" SVf ",\n" , SVfARG (* elem ));
293
296
}
@@ -303,9 +306,12 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
303
306
}
304
307
}
305
308
else { /* @ISA was undefined or empty */
309
+ /* Do this 1st, the next 2 AV* API calls are likely to be inlined and
310
+ optimize away alot of AvFILL/memset/Renew logic if nothing is between them. */
311
+ SV * nsv = newSVhek (stashhek );
306
312
/* build a retval containing only ourselves */
307
313
retval = newAV_alloc_xz (4 );
308
- av_push_simple (retval , newSVhek ( stashhek ) );
314
+ av_push_simple (retval , nsv );
309
315
}
310
316
311
317
done :
@@ -362,6 +368,9 @@ PPCODE:
362
368
sv = MY_CXT .sv_dfs ;
363
369
MY_CXT .sv_dfs = NULL ;
364
370
SvREFCNT_dec_NN (sv );
371
+ sv = MY_CXT .sv_c3 ;
372
+ MY_CXT .sv_c3 = NULL ;
373
+ SvREFCNT_dec_NN (sv );
365
374
sv = MY_CXT .sv_ISA ;
366
375
MY_CXT .sv_ISA = NULL ;
367
376
SvREFCNT_dec_NN (sv );
@@ -385,8 +394,9 @@ mro_get_linear_isa(...)
385
394
386
395
if (!class_stash ) {
387
396
/* No stash exists yet, give them just the classname */
397
+ SV * nsv = mro_newSVsvhekok (classname );
388
398
AV * isalin = newAV_alloc_xz (4 );
389
- av_push_simple (isalin , mro_newSVsvhekok ( classname ) );
399
+ av_push_simple (isalin , nsv );
390
400
ST (0 ) = sv_2mortal (newRV_noinc (MUTABLE_SV (isalin )));
391
401
XSRETURN (1 );
392
402
}
@@ -430,6 +440,7 @@ mro_get_mro(...)
430
440
SV * classname ;
431
441
HV * class_stash ;
432
442
SV * retsv ;
443
+ U32 which_my_cxt ; /* rel offset MY_CXT, prevents 2 sep dMY_CXT deref lines */
433
444
PPCODE :
434
445
if (items != 1 )
435
446
croak_xs_usage (cv , "classname ");
@@ -439,12 +450,28 @@ mro_get_mro(...)
439
450
440
451
if (class_stash ) {
441
452
const struct mro_alg * const meta = HvMROMETA (class_stash )-> mro_which ;
442
- retsv = newSVpvn_flags (meta -> name , meta -> length ,
443
- SVs_TEMP
444
- | ((meta -> kflags & HVhek_UTF8 ) ? SVf_UTF8 : 0 ));
453
+ if (memEQs (meta -> name , meta -> length , "dfs" )) /* skipping meta->kflags & HVhek_UTF8 */
454
+ goto ret_dfs ;
455
+ /* "c3" shows up here running mro's .t'es */
456
+ else if (memEQs (meta -> name , meta -> length , "c3" )) {
457
+ which_my_cxt = STRUCT_OFFSET (my_cxt_t , sv_c3 );
458
+ goto ret_my_cxt_hek ;
459
+ }
460
+ else { /* pretty sure this string already exists inside PL_strtab by now */
461
+ I32 i32len = meta -> kflags & HVhek_UTF8 ? - (I32 )meta -> length : (I32 )meta -> length ;
462
+ retsv = sv_2mortal (newSVpvn_share (meta -> name , i32len , meta -> hash ));
463
+ }
445
464
} else {
446
- dMY_CXT ;
447
- retsv = newSVhek_mortal (SvSHARED_HEK_FROM_PV (SvPVX (MY_CXT .sv_dfs )));
465
+ ret_dfs :
466
+ which_my_cxt = STRUCT_OFFSET (my_cxt_t , sv_dfs );
467
+
468
+ ret_my_cxt_hek :
469
+ {
470
+ dMY_CXT ;
471
+ SV * * svp = NUM2PTR (SV * * ,(PTR2nat (& MY_CXT )+ which_my_cxt ));
472
+ SV * svhek = * svp ;
473
+ retsv = newSVhek_mortal (SvSHARED_HEK_FROM_PV (SvPVX (svhek )));
474
+ }
448
475
}
449
476
PUSHs (retsv );
450
477
546
573
mro__nextcan (...)
547
574
PREINIT :
548
575
SV * self = ST (0 );
549
- const I32 throw_nomethod = SvIVX (ST (1 ));
576
+ const bool throw_nomethod = cBOOL ( SvIVX (ST (1 ) ));
550
577
I32 cxix = cxstack_ix ;
551
578
const PERL_CONTEXT * ccstack = cxstack ;
552
579
const PERL_SI * top_si = PL_curstackinfo ;
@@ -649,8 +676,10 @@ mro__nextcan(...)
649
676
/* Initialize the next::method cache for this stash
650
677
if necessary */
651
678
selfmeta = HvMROMETA (selfstash );
652
- if (!(nmcache = selfmeta -> mro_nextmethod )) {
653
- nmcache = selfmeta -> mro_nextmethod = newHV ();
679
+ nmcache = selfmeta -> mro_nextmethod ;
680
+ if (!nmcache ) {
681
+ nmcache = newHV ();
682
+ selfmeta -> mro_nextmethod = nmcache ;
654
683
}
655
684
else { /* Use the cached coderef if it exists */
656
685
HE * cache_entry = hv_fetch_ent (nmcache , sv , 0 , 0 );
@@ -673,8 +702,10 @@ mro__nextcan(...)
673
702
/* beyond here is just for cache misses, so perf isn't as critical */
674
703
675
704
stashname_len = subname - fq_subname - 2 ;
676
- stashname = newSVpvn_flags (fq_subname , stashname_len ,
677
- SVs_TEMP | (subname_utf8 ? SVf_UTF8 : 0 ));
705
+ { /* strs like "Qux::foo" "TTop::foo" show up here */
706
+ I32 i32len = subname_utf8 ? - (I32 )stashname_len : (I32 )stashname_len ;
707
+ stashname = sv_2mortal (newSVpvn_share (fq_subname , i32len , 0 ));
708
+ }
678
709
679
710
/* has ourselves at the top of the list */
680
711
linear_av = S_mro_get_linear_isa_c3 (aTHX_ selfstash , 0 );
0 commit comments