xref: /openbsd/gnu/usr.bin/perl/universal.c (revision 4bdff4be)
1 #line 2 "universal.c"
2 /*    universal.c
3  *
4  *    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
5  *    2005, 2006, 2007, 2008 by Larry Wall and others
6  *
7  *    You may distribute under the terms of either the GNU General Public
8  *    License or the Artistic License, as specified in the README file.
9  *
10  */
11 
12 /*
13  * '"The roots of those mountains must be roots indeed; there must be
14  *   great secrets buried there which have not been discovered since the
15  *   beginning."'                   --Gandalf, relating Gollum's history
16  *
17  *     [p.54 of _The Lord of the Rings_, I/ii: "The Shadow of the Past"]
18  */
19 
20 /* This file contains the code that implements the functions in Perl's
21  * UNIVERSAL package, such as UNIVERSAL->can().
22  *
23  * It is also used to store XS functions that need to be present in
24  * miniperl for a lack of a better place to put them. It might be
25  * clever to move them to separate XS files which would then be pulled
26  * in by some to-be-written build process.
27  */
28 
29 #include "EXTERN.h"
30 #define PERL_IN_UNIVERSAL_C
31 #include "perl.h"
32 
33 #if defined(USE_PERLIO)
34 #include "perliol.h" /* For the PERLIO_F_XXX */
35 #endif
36 
37 /*
38  * Contributed by Graham Barr  <Graham.Barr@tiuk.ti.com>
39  * The main guts of traverse_isa was actually copied from gv_fetchmeth
40  */
41 
42 #define PERL_ARGS_ASSERT_ISA_LOOKUP \
43     assert(stash); \
44     assert(namesv || name)
45 
46 
47 STATIC bool
48 S_isa_lookup(pTHX_ HV *stash, SV *namesv, const char * name, STRLEN len, U32 flags)
49 {
50     const struct mro_meta *const meta = HvMROMETA(stash);
51     HV *isa = meta->isa;
52     const HV *our_stash;
53 
54     PERL_ARGS_ASSERT_ISA_LOOKUP;
55 
56     if (!isa) {
57         (void)mro_get_linear_isa(stash);
58         isa = meta->isa;
59     }
60 
61     if (hv_common(isa, namesv, name, len, ( flags & SVf_UTF8 ? HVhek_UTF8 : 0),
62                   HV_FETCH_ISEXISTS, NULL, 0)) {
63         /* Direct name lookup worked.  */
64         return TRUE;
65     }
66 
67     /* A stash/class can go by many names (ie. User == main::User), so
68        we use the HvENAME in the stash itself, which is canonical, falling
69        back to HvNAME if necessary.  */
70     our_stash = gv_stashsvpvn_cached(namesv, name, len, flags);
71 
72     if (our_stash) {
73         HEK *canon_name = HvENAME_HEK(our_stash);
74         if (!canon_name) canon_name = HvNAME_HEK(our_stash);
75         assert(canon_name);
76         if (hv_common(isa, NULL, HEK_KEY(canon_name), HEK_LEN(canon_name),
77                       HEK_FLAGS(canon_name),
78                       HV_FETCH_ISEXISTS, NULL, HEK_HASH(canon_name))) {
79             return TRUE;
80         }
81     }
82 
83     return FALSE;
84 }
85 
86 #define PERL_ARGS_ASSERT_SV_DERIVED_FROM_SVPVN \
87     assert(sv); \
88     assert(namesv || name)
89 
90 STATIC bool
91 S_sv_derived_from_svpvn(pTHX_ SV *sv, SV *namesv, const char * name, const STRLEN len, U32 flags)
92 {
93     HV* stash;
94 
95     PERL_ARGS_ASSERT_SV_DERIVED_FROM_SVPVN;
96     SvGETMAGIC(sv);
97 
98     if (SvROK(sv)) {
99         const char *type;
100         sv = SvRV(sv);
101         type = sv_reftype(sv,0);
102         if (type) {
103             if (namesv)
104                 name = SvPV_nolen(namesv);
105             if (strEQ(name, type))
106                 return TRUE;
107         }
108         if (!SvOBJECT(sv))
109             return FALSE;
110         stash = SvSTASH(sv);
111     }
112     else {
113         stash = gv_stashsv(sv, 0);
114     }
115 
116     if (stash && isa_lookup(stash, namesv, name, len, flags))
117         return TRUE;
118 
119     stash = gv_stashpvs("UNIVERSAL", 0);
120     return stash && isa_lookup(stash, namesv, name, len, flags);
121 }
122 
123 /*
124 =for apidoc_section $SV
125 
126 =for apidoc sv_derived_from_pvn
127 
128 Returns a boolean indicating whether the SV is derived from the specified class
129 I<at the C level>.  To check derivation at the Perl level, call C<isa()> as a
130 normal Perl method.
131 
132 Currently, the only significant value for C<flags> is SVf_UTF8.
133 
134 =cut
135 
136 =for apidoc sv_derived_from_sv
137 
138 Exactly like L</sv_derived_from_pvn>, but takes the name string in the form
139 of an SV instead of a string/length pair. This is the advised form.
140 
141 =cut
142 
143 */
144 
145 bool
146 Perl_sv_derived_from_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
147 {
148     PERL_ARGS_ASSERT_SV_DERIVED_FROM_SV;
149     return sv_derived_from_svpvn(sv, namesv, NULL, 0, flags);
150 }
151 
152 /*
153 =for apidoc sv_derived_from
154 
155 Exactly like L</sv_derived_from_pv>, but doesn't take a C<flags> parameter.
156 
157 =cut
158 */
159 
160 bool
161 Perl_sv_derived_from(pTHX_ SV *sv, const char *const name)
162 {
163     PERL_ARGS_ASSERT_SV_DERIVED_FROM;
164     return sv_derived_from_svpvn(sv, NULL, name, strlen(name), 0);
165 }
166 
167 /*
168 =for apidoc sv_derived_from_pv
169 
170 Exactly like L</sv_derived_from_pvn>, but takes a nul-terminated string
171 instead of a string/length pair.
172 
173 =cut
174 */
175 
176 
177 bool
178 Perl_sv_derived_from_pv(pTHX_ SV *sv, const char *const name, U32 flags)
179 {
180     PERL_ARGS_ASSERT_SV_DERIVED_FROM_PV;
181     return sv_derived_from_svpvn(sv, NULL, name, strlen(name), flags);
182 }
183 
184 bool
185 Perl_sv_derived_from_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, U32 flags)
186 {
187     PERL_ARGS_ASSERT_SV_DERIVED_FROM_PVN;
188     return sv_derived_from_svpvn(sv, NULL, name, len, flags);
189 }
190 
191 /*
192 =for apidoc sv_isa_sv
193 
194 Returns a boolean indicating whether the SV is an object reference and is
195 derived from the specified class, respecting any C<isa()> method overloading
196 it may have. Returns false if C<sv> is not a reference to an object, or is
197 not derived from the specified class.
198 
199 This is the function used to implement the behaviour of the C<isa> operator.
200 
201 Does not invoke magic on C<sv>.
202 
203 Not to be confused with the older C<sv_isa> function, which does not use an
204 overloaded C<isa()> method, nor will check subclassing.
205 
206 =cut
207 
208 */
209 
210 bool
211 Perl_sv_isa_sv(pTHX_ SV *sv, SV *namesv)
212 {
213     GV *isagv;
214 
215     PERL_ARGS_ASSERT_SV_ISA_SV;
216 
217     if(!SvROK(sv) || !SvOBJECT(SvRV(sv)))
218         return FALSE;
219 
220     isagv = gv_fetchmeth_pvn(SvSTASH(SvRV(sv)), "isa", 3, -1, GV_NOUNIVERSAL);
221     if(isagv) {
222         dSP;
223         CV *isacv = isGV(isagv) ? GvCV(isagv) : (CV *)isagv;
224         SV *retsv;
225         bool ret;
226 
227         PUTBACK;
228 
229         ENTER;
230         SAVETMPS;
231 
232         EXTEND(SP, 2);
233         PUSHMARK(SP);
234         PUSHs(sv);
235         PUSHs(namesv);
236         PUTBACK;
237 
238         call_sv((SV *)isacv, G_SCALAR);
239 
240         SPAGAIN;
241         retsv = POPs;
242         ret = SvTRUE(retsv);
243         PUTBACK;
244 
245         FREETMPS;
246         LEAVE;
247 
248         return ret;
249     }
250 
251     /* TODO: Support namesv being an HV ref to the stash directly? */
252 
253     return sv_derived_from_sv(sv, namesv, 0);
254 }
255 
256 /*
257 =for apidoc sv_does_sv
258 
259 Returns a boolean indicating whether the SV performs a specific, named role.
260 The SV can be a Perl object or the name of a Perl class.
261 
262 =cut
263 */
264 
265 #include "XSUB.h"
266 
267 bool
268 Perl_sv_does_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
269 {
270     SV *classname;
271     bool does_it;
272     SV *methodname;
273     dSP;
274 
275     PERL_ARGS_ASSERT_SV_DOES_SV;
276     PERL_UNUSED_ARG(flags);
277 
278     ENTER;
279     SAVETMPS;
280 
281     SvGETMAGIC(sv);
282 
283     if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)))) {
284         LEAVE;
285         return FALSE;
286     }
287 
288     if (SvROK(sv) && SvOBJECT(SvRV(sv))) {
289         classname = sv_ref(NULL,SvRV(sv),TRUE);
290     } else {
291         classname = sv;
292     }
293 
294     if (sv_eq(classname, namesv)) {
295         LEAVE;
296         return TRUE;
297     }
298 
299     PUSHMARK(SP);
300     EXTEND(SP, 2);
301     PUSHs(sv);
302     PUSHs(namesv);
303     PUTBACK;
304 
305     /* create a PV with value "isa", but with a special address
306      * so that perl knows we're really doing "DOES" instead */
307     methodname = newSV_type_mortal(SVt_PV);
308     SvLEN_set(methodname, 0);
309     SvCUR_set(methodname, strlen(PL_isa_DOES));
310     SvPVX(methodname) = (char *)PL_isa_DOES; /* discard 'const' qualifier */
311     SvPOK_on(methodname);
312     call_sv(methodname, G_SCALAR | G_METHOD);
313     SPAGAIN;
314 
315     does_it = SvTRUE_NN( TOPs );
316     FREETMPS;
317     LEAVE;
318 
319     return does_it;
320 }
321 
322 /*
323 =for apidoc sv_does
324 
325 Like L</sv_does_pv>, but doesn't take a C<flags> parameter.
326 
327 =cut
328 */
329 
330 bool
331 Perl_sv_does(pTHX_ SV *sv, const char *const name)
332 {
333     PERL_ARGS_ASSERT_SV_DOES;
334     return sv_does_sv(sv, newSVpvn_flags(name, strlen(name), SVs_TEMP), 0);
335 }
336 
337 /*
338 =for apidoc sv_does_pv
339 
340 Like L</sv_does_sv>, but takes a nul-terminated string instead of an SV.
341 
342 =cut
343 */
344 
345 
346 bool
347 Perl_sv_does_pv(pTHX_ SV *sv, const char *const name, U32 flags)
348 {
349     PERL_ARGS_ASSERT_SV_DOES_PV;
350     return sv_does_sv(sv, newSVpvn_flags(name, strlen(name), SVs_TEMP | flags), flags);
351 }
352 
353 /*
354 =for apidoc sv_does_pvn
355 
356 Like L</sv_does_sv>, but takes a string/length pair instead of an SV.
357 
358 =cut
359 */
360 
361 bool
362 Perl_sv_does_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, U32 flags)
363 {
364     PERL_ARGS_ASSERT_SV_DOES_PVN;
365 
366     return sv_does_sv(sv, newSVpvn_flags(name, len, flags | SVs_TEMP), flags);
367 }
368 
369 /*
370 =for apidoc croak_xs_usage
371 
372 A specialised variant of C<croak()> for emitting the usage message for xsubs
373 
374     croak_xs_usage(cv, "eee_yow");
375 
376 works out the package name and subroutine name from C<cv>, and then calls
377 C<croak()>.  Hence if C<cv> is C<&ouch::awk>, it would call C<croak> as:
378 
379  Perl_croak(aTHX_ "Usage: %" SVf "::%" SVf "(%s)", "ouch" "awk",
380                                                      "eee_yow");
381 
382 =cut
383 */
384 
385 void
386 Perl_croak_xs_usage(const CV *const cv, const char *const params)
387 {
388     /* Avoid CvGV as it requires aTHX.  */
389     const GV *gv = CvNAMED(cv) ? NULL : cv->sv_any->xcv_gv_u.xcv_gv;
390 
391     PERL_ARGS_ASSERT_CROAK_XS_USAGE;
392 
393     if (gv) got_gv: {
394         const HV *const stash = GvSTASH(gv);
395 
396         if (HvNAME_get(stash))
397             /* diag_listed_as: SKIPME */
398             Perl_croak_nocontext("Usage: %" HEKf "::%" HEKf "(%s)",
399                                 HEKfARG(HvNAME_HEK(stash)),
400                                 HEKfARG(GvNAME_HEK(gv)),
401                                 params);
402         else
403             /* diag_listed_as: SKIPME */
404             Perl_croak_nocontext("Usage: %" HEKf "(%s)",
405                                 HEKfARG(GvNAME_HEK(gv)), params);
406     } else {
407         dTHX;
408         if ((gv = CvGV(cv))) goto got_gv;
409 
410         /* Pants. I don't think that it should be possible to get here. */
411         /* diag_listed_as: SKIPME */
412         Perl_croak(aTHX_ "Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
413     }
414 }
415 
416 XS(XS_UNIVERSAL_isa); /* prototype to pass -Wmissing-prototypes */
417 XS(XS_UNIVERSAL_isa)
418 {
419     dXSARGS;
420 
421     if (items != 2)
422         croak_xs_usage(cv, "reference, kind");
423     else {
424         SV * const sv = ST(0);
425 
426         SvGETMAGIC(sv);
427 
428         if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))))
429             XSRETURN_UNDEF;
430 
431         ST(0) = boolSV(sv_derived_from_sv(sv, ST(1), 0));
432         XSRETURN(1);
433     }
434 }
435 
436 XS(XS_UNIVERSAL_can); /* prototype to pass -Wmissing-prototypes */
437 XS(XS_UNIVERSAL_can)
438 {
439     dXSARGS;
440     SV   *sv;
441     SV   *rv;
442     HV   *pkg = NULL;
443     GV   *iogv;
444 
445     if (items != 2)
446         croak_xs_usage(cv, "object-ref, method");
447 
448     sv = ST(0);
449 
450     SvGETMAGIC(sv);
451 
452     /* Reject undef and empty string.  Note that the string form takes
453        precedence here over the numeric form, as (!1)->foo treats the
454        invocant as the empty string, though it is a dualvar. */
455     if (!SvOK(sv) || (SvPOK(sv) && !SvCUR(sv)))
456         XSRETURN_UNDEF;
457 
458     rv = &PL_sv_undef;
459 
460     if (SvROK(sv)) {
461         sv = MUTABLE_SV(SvRV(sv));
462         if (SvOBJECT(sv))
463             pkg = SvSTASH(sv);
464         else if (isGV_with_GP(sv) && GvIO(sv))
465             pkg = SvSTASH(GvIO(sv));
466     }
467     else if (isGV_with_GP(sv) && GvIO(sv))
468         pkg = SvSTASH(GvIO(sv));
469     else if ((iogv = gv_fetchsv_nomg(sv, 0, SVt_PVIO)) && GvIO(iogv))
470         pkg = SvSTASH(GvIO(iogv));
471     else {
472         pkg = gv_stashsv(sv, 0);
473         if (!pkg)
474             pkg = gv_stashpvs("UNIVERSAL", 0);
475     }
476 
477     if (pkg) {
478         GV * const gv = gv_fetchmethod_sv_flags(pkg, ST(1), 0);
479         if (gv && isGV(gv))
480             rv = sv_2mortal(newRV(MUTABLE_SV(GvCV(gv))));
481     }
482 
483     ST(0) = rv;
484     XSRETURN(1);
485 }
486 
487 XS(XS_UNIVERSAL_DOES); /* prototype to pass -Wmissing-prototypes */
488 XS(XS_UNIVERSAL_DOES)
489 {
490     dXSARGS;
491     PERL_UNUSED_ARG(cv);
492 
493     if (items != 2)
494         Perl_croak(aTHX_ "Usage: invocant->DOES(kind)");
495     else {
496         SV * const sv = ST(0);
497         if (sv_does_sv( sv, ST(1), 0 ))
498             XSRETURN_YES;
499 
500         XSRETURN_NO;
501     }
502 }
503 
504 XS(XS_utf8_is_utf8); /* prototype to pass -Wmissing-prototypes */
505 XS(XS_utf8_is_utf8)
506 {
507      dXSARGS;
508      if (items != 1)
509          croak_xs_usage(cv, "sv");
510      else {
511         SV * const sv = ST(0);
512         SvGETMAGIC(sv);
513             if (SvUTF8(sv))
514                 XSRETURN_YES;
515             else
516                 XSRETURN_NO;
517      }
518      XSRETURN_EMPTY;
519 }
520 
521 XS(XS_utf8_valid); /* prototype to pass -Wmissing-prototypes */
522 XS(XS_utf8_valid)
523 {
524      dXSARGS;
525      if (items != 1)
526          croak_xs_usage(cv, "sv");
527     else {
528         SV * const sv = ST(0);
529         STRLEN len;
530         const char * const s = SvPV_const(sv,len);
531         if (!SvUTF8(sv) || is_utf8_string((const U8*)s,len))
532             XSRETURN_YES;
533         else
534             XSRETURN_NO;
535     }
536      XSRETURN_EMPTY;
537 }
538 
539 XS(XS_utf8_encode); /* prototype to pass -Wmissing-prototypes */
540 XS(XS_utf8_encode)
541 {
542     dXSARGS;
543     if (items != 1)
544         croak_xs_usage(cv, "sv");
545     sv_utf8_encode(ST(0));
546     SvSETMAGIC(ST(0));
547     XSRETURN_EMPTY;
548 }
549 
550 XS(XS_utf8_decode); /* prototype to pass -Wmissing-prototypes */
551 XS(XS_utf8_decode)
552 {
553     dXSARGS;
554     if (items != 1)
555         croak_xs_usage(cv, "sv");
556     else {
557         SV * const sv = ST(0);
558         bool RETVAL;
559         SvPV_force_nolen(sv);
560         RETVAL = sv_utf8_decode(sv);
561         SvSETMAGIC(sv);
562         ST(0) = boolSV(RETVAL);
563     }
564     XSRETURN(1);
565 }
566 
567 XS(XS_utf8_upgrade); /* prototype to pass -Wmissing-prototypes */
568 XS(XS_utf8_upgrade)
569 {
570     dXSARGS;
571     if (items != 1)
572         croak_xs_usage(cv, "sv");
573     else {
574         SV * const sv = ST(0);
575         STRLEN	RETVAL;
576         dXSTARG;
577 
578         RETVAL = sv_utf8_upgrade(sv);
579         XSprePUSH; PUSHi((IV)RETVAL);
580     }
581     XSRETURN(1);
582 }
583 
584 XS(XS_utf8_downgrade); /* prototype to pass -Wmissing-prototypes */
585 XS(XS_utf8_downgrade)
586 {
587     dXSARGS;
588     if (items < 1 || items > 2)
589         croak_xs_usage(cv, "sv, failok=0");
590     else {
591         SV * const sv0 = ST(0);
592         SV * const sv1 = ST(1);
593         const bool failok = (items < 2) ? 0 : SvTRUE_NN(sv1) ? 1 : 0;
594         const bool RETVAL = sv_utf8_downgrade(sv0, failok);
595 
596         ST(0) = boolSV(RETVAL);
597     }
598     XSRETURN(1);
599 }
600 
601 XS(XS_utf8_native_to_unicode); /* prototype to pass -Wmissing-prototypes */
602 XS(XS_utf8_native_to_unicode)
603 {
604  dXSARGS;
605  const UV uv = SvUV(ST(0));
606 
607  if (items > 1)
608      croak_xs_usage(cv, "sv");
609 
610  ST(0) = sv_2mortal(newSVuv(NATIVE_TO_UNI(uv)));
611  XSRETURN(1);
612 }
613 
614 XS(XS_utf8_unicode_to_native); /* prototype to pass -Wmissing-prototypes */
615 XS(XS_utf8_unicode_to_native)
616 {
617  dXSARGS;
618  const UV uv = SvUV(ST(0));
619 
620  if (items > 1)
621      croak_xs_usage(cv, "sv");
622 
623  ST(0) = sv_2mortal(newSVuv(UNI_TO_NATIVE(uv)));
624  XSRETURN(1);
625 }
626 
627 XS(XS_Internals_SvREADONLY); /* prototype to pass -Wmissing-prototypes */
628 XS(XS_Internals_SvREADONLY)	/* This is dangerous stuff. */
629 {
630     dXSARGS;
631     SV * const svz = ST(0);
632     SV * sv;
633 
634     /* [perl #77776] - called as &foo() not foo() */
635     if (!SvROK(svz))
636         croak_xs_usage(cv, "SCALAR[, ON]");
637 
638     sv = SvRV(svz);
639 
640     if (items == 1) {
641          if (SvREADONLY(sv))
642              XSRETURN_YES;
643          else
644              XSRETURN_NO;
645     }
646     else if (items == 2) {
647         SV *sv1 = ST(1);
648         if (SvTRUE_NN(sv1)) {
649             SvFLAGS(sv) |= SVf_READONLY;
650             XSRETURN_YES;
651         }
652         else {
653             /* I hope you really know what you are doing. */
654             SvFLAGS(sv) &=~ SVf_READONLY;
655             XSRETURN_NO;
656         }
657     }
658     XSRETURN_UNDEF; /* Can't happen. */
659 }
660 
661 XS(XS_constant__make_const); /* prototype to pass -Wmissing-prototypes */
662 XS(XS_constant__make_const)	/* This is dangerous stuff. */
663 {
664     dXSARGS;
665     SV * const svz = ST(0);
666     SV * sv;
667 
668     /* [perl #77776] - called as &foo() not foo() */
669     if (!SvROK(svz) || items != 1)
670         croak_xs_usage(cv, "SCALAR");
671 
672     sv = SvRV(svz);
673 
674     SvREADONLY_on(sv);
675     if (SvTYPE(sv) == SVt_PVAV && AvFILLp(sv) != -1) {
676         /* for constant.pm; nobody else should be calling this
677            on arrays anyway. */
678         SV **svp;
679         for (svp = AvARRAY(sv) + AvFILLp(sv)
680            ; svp >= AvARRAY(sv)
681            ; --svp)
682             if (*svp) SvPADTMP_on(*svp);
683     }
684     XSRETURN(0);
685 }
686 
687 XS(XS_Internals_SvREFCNT); /* prototype to pass -Wmissing-prototypes */
688 XS(XS_Internals_SvREFCNT)	/* This is dangerous stuff. */
689 {
690     dXSARGS;
691     SV * const svz = ST(0);
692     SV * sv;
693     U32 refcnt;
694 
695     /* [perl #77776] - called as &foo() not foo() */
696     if ((items != 1 && items != 2) || !SvROK(svz))
697         croak_xs_usage(cv, "SCALAR[, REFCOUNT]");
698 
699     sv = SvRV(svz);
700 
701          /* I hope you really know what you are doing. */
702     /* idea is for SvREFCNT(sv) to be accessed only once */
703     refcnt = items == 2 ?
704                 /* we free one ref on exit */
705                 (SvREFCNT(sv) = SvUV(ST(1)) + 1)
706                 : SvREFCNT(sv);
707     XSRETURN_UV(refcnt - 1); /* Minus the ref created for us. */
708 
709 }
710 
711 XS(XS_Internals_hv_clear_placehold); /* prototype to pass -Wmissing-prototypes */
712 XS(XS_Internals_hv_clear_placehold)
713 {
714     dXSARGS;
715 
716     if (items != 1 || !SvROK(ST(0)))
717         croak_xs_usage(cv, "hv");
718     else {
719         HV * const hv = MUTABLE_HV(SvRV(ST(0)));
720         hv_clear_placeholders(hv);
721         XSRETURN(0);
722     }
723 }
724 
725 XS(XS_PerlIO_get_layers); /* prototype to pass -Wmissing-prototypes */
726 XS(XS_PerlIO_get_layers)
727 {
728     dXSARGS;
729     if (items < 1 || items % 2 == 0)
730         croak_xs_usage(cv, "filehandle[,args]");
731 #if defined(USE_PERLIO)
732     {
733         SV *	sv;
734         GV *	gv;
735         IO *	io;
736         bool	input = TRUE;
737         bool	details = FALSE;
738 
739         if (items > 1) {
740              SV * const *svp;
741              for (svp = MARK + 2; svp <= SP; svp += 2) {
742                   SV * const * const varp = svp;
743                   SV * const * const valp = svp + 1;
744                   STRLEN klen;
745                   const char * const key = SvPV_const(*varp, klen);
746 
747                   switch (*key) {
748                   case 'i':
749                        if (memEQs(key, klen, "input")) {
750                             input = SvTRUE(*valp);
751                             break;
752                        }
753                        goto fail;
754                   case 'o':
755                        if (memEQs(key, klen, "output")) {
756                             input = !SvTRUE(*valp);
757                             break;
758                        }
759                        goto fail;
760                   case 'd':
761                        if (memEQs(key, klen, "details")) {
762                             details = SvTRUE(*valp);
763                             break;
764                        }
765                        goto fail;
766                   default:
767                   fail:
768                        Perl_croak(aTHX_
769                                   "get_layers: unknown argument '%s'",
770                                   key);
771                   }
772              }
773 
774              SP -= (items - 1);
775         }
776 
777         sv = POPs;
778         gv = MAYBE_DEREF_GV(sv);
779 
780         if (!gv && !SvROK(sv))
781             gv = gv_fetchsv_nomg(sv, 0, SVt_PVIO);
782 
783         if (gv && (io = GvIO(gv))) {
784              AV* const av = PerlIO_get_layers(aTHX_ input ?
785                                         IoIFP(io) : IoOFP(io));
786              SSize_t i;
787              const SSize_t last = av_top_index(av);
788              SSize_t nitem = 0;
789 
790              for (i = last; i >= 0; i -= 3) {
791                   SV * const * const namsvp = av_fetch(av, i - 2, FALSE);
792                   SV * const * const argsvp = av_fetch(av, i - 1, FALSE);
793                   SV * const * const flgsvp = av_fetch(av, i,     FALSE);
794 
795                   const bool namok = namsvp && *namsvp && SvPOK(*namsvp);
796                   const bool argok = argsvp && *argsvp && SvPOK(*argsvp);
797                   const bool flgok = flgsvp && *flgsvp && SvIOK(*flgsvp);
798 
799                   EXTEND(SP, 3); /* Three is the max in all branches: better check just once */
800                   if (details) {
801                       /* Indents of 5? Yuck.  */
802                       /* We know that PerlIO_get_layers creates a new SV for
803                          the name and flags, so we can just take a reference
804                          and "steal" it when we free the AV below.  */
805                        PUSHs(namok
806                               ? sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp))
807                               : &PL_sv_undef);
808                        PUSHs(argok
809                               ? newSVpvn_flags(SvPVX_const(*argsvp),
810                                                SvCUR(*argsvp),
811                                                (SvUTF8(*argsvp) ? SVf_UTF8 : 0)
812                                                | SVs_TEMP)
813                               : &PL_sv_undef);
814                        PUSHs(flgok
815                               ? sv_2mortal(SvREFCNT_inc_simple_NN(*flgsvp))
816                               : &PL_sv_undef);
817                        nitem += 3;
818                   }
819                   else {
820                        if (namok && argok)
821                             PUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%" SVf "(%" SVf ")",
822                                                  SVfARG(*namsvp),
823                                                  SVfARG(*argsvp))));
824                        else if (namok)
825                             PUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp)));
826                        else
827                             PUSHs(&PL_sv_undef);
828                        nitem++;
829                        if (flgok) {
830                             const IV flags = SvIVX(*flgsvp);
831 
832                             if (flags & PERLIO_F_UTF8) {
833                                  PUSHs(newSVpvs_flags("utf8", SVs_TEMP));
834                                  nitem++;
835                             }
836                        }
837                   }
838              }
839 
840              SvREFCNT_dec(av);
841 
842              XSRETURN(nitem);
843         }
844     }
845 #endif
846 
847     XSRETURN(0);
848 }
849 
850 XS(XS_re_is_regexp); /* prototype to pass -Wmissing-prototypes */
851 XS(XS_re_is_regexp)
852 {
853     dXSARGS;
854 
855     if (items != 1)
856         croak_xs_usage(cv, "sv");
857 
858     if (SvRXOK(ST(0))) {
859         XSRETURN_YES;
860     } else {
861         XSRETURN_NO;
862     }
863 }
864 
865 XS(XS_re_regnames_count); /* prototype to pass -Wmissing-prototypes */
866 XS(XS_re_regnames_count)
867 {
868     REGEXP *rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
869     SV * ret;
870     dXSARGS;
871 
872     if (items != 0)
873         croak_xs_usage(cv, "");
874 
875     if (!rx)
876         XSRETURN_UNDEF;
877 
878     ret = CALLREG_NAMED_BUFF_COUNT(rx);
879 
880     SPAGAIN;
881     PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
882     XSRETURN(1);
883 }
884 
885 XS(XS_re_regname); /* prototype to pass -Wmissing-prototypes */
886 XS(XS_re_regname)
887 {
888     dXSARGS;
889     REGEXP * rx;
890     U32 flags;
891     SV * ret;
892 
893     if (items < 1 || items > 2)
894         croak_xs_usage(cv, "name[, all ]");
895 
896     SP -= items;
897     PUTBACK;
898 
899     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
900 
901     if (!rx)
902         XSRETURN_UNDEF;
903 
904     if (items == 2 && SvTRUE_NN(ST(1))) {
905         flags = RXapif_ALL;
906     } else {
907         flags = RXapif_ONE;
908     }
909     ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(0), (flags | RXapif_REGNAME));
910 
911     SPAGAIN;
912     PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
913     XSRETURN(1);
914 }
915 
916 
917 XS(XS_re_regnames); /* prototype to pass -Wmissing-prototypes */
918 XS(XS_re_regnames)
919 {
920     dXSARGS;
921     REGEXP * rx;
922     U32 flags;
923     SV *ret;
924     AV *av;
925     SSize_t length;
926     SSize_t i;
927     SV **entry;
928 
929     if (items > 1)
930         croak_xs_usage(cv, "[all]");
931 
932     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
933 
934     if (!rx)
935         XSRETURN_UNDEF;
936 
937     if (items == 1 && SvTRUE_NN(ST(0))) {
938         flags = RXapif_ALL;
939     } else {
940         flags = RXapif_ONE;
941     }
942 
943     SP -= items;
944     PUTBACK;
945 
946     ret = CALLREG_NAMED_BUFF_ALL(rx, (flags | RXapif_REGNAMES));
947 
948     SPAGAIN;
949 
950     if (!ret)
951         XSRETURN_UNDEF;
952 
953     av = MUTABLE_AV(SvRV(ret));
954     length = av_count(av);
955 
956     EXTEND(SP, length); /* better extend stack just once */
957     for (i = 0; i < length; i++) {
958         entry = av_fetch(av, i, FALSE);
959 
960         if (!entry)
961             Perl_croak(aTHX_ "NULL array element in re::regnames()");
962 
963         mPUSHs(SvREFCNT_inc_simple_NN(*entry));
964     }
965 
966     SvREFCNT_dec(ret);
967 
968     PUTBACK;
969     return;
970 }
971 
972 XS(XS_re_regexp_pattern); /* prototype to pass -Wmissing-prototypes */
973 XS(XS_re_regexp_pattern)
974 {
975     dXSARGS;
976     REGEXP *re;
977     U8 const gimme = GIMME_V;
978 
979     EXTEND(SP, 2);
980     SP -= items;
981     if (items != 1)
982         croak_xs_usage(cv, "sv");
983 
984     /*
985        Checks if a reference is a regex or not. If the parameter is
986        not a ref, or is not the result of a qr// then returns false
987        in scalar context and an empty list in list context.
988        Otherwise in list context it returns the pattern and the
989        modifiers, in scalar context it returns the pattern just as it
990        would if the qr// was stringified normally, regardless as
991        to the class of the variable and any stringification overloads
992        on the object.
993     */
994 
995     if ((re = SvRX(ST(0)))) /* assign deliberate */
996     {
997         /* Houston, we have a regex! */
998         SV *pattern;
999 
1000         if ( gimme == G_LIST ) {
1001             STRLEN left = 0;
1002             char reflags[sizeof(INT_PAT_MODS) + MAX_CHARSET_NAME_LENGTH];
1003             const char *fptr;
1004             char ch;
1005             U16 match_flags;
1006 
1007             /*
1008                we are in list context so stringify
1009                the modifiers that apply. We ignore "negative
1010                modifiers" in this scenario, and the default character set
1011             */
1012 
1013             if (get_regex_charset(RX_EXTFLAGS(re)) != REGEX_DEPENDS_CHARSET) {
1014                 STRLEN len;
1015                 const char* const name = get_regex_charset_name(RX_EXTFLAGS(re),
1016                                                                 &len);
1017                 Copy(name, reflags + left, len, char);
1018                 left += len;
1019             }
1020             fptr = INT_PAT_MODS;
1021             match_flags = (U16)((RX_EXTFLAGS(re) & RXf_PMf_COMPILETIME)
1022                                     >> RXf_PMf_STD_PMMOD_SHIFT);
1023 
1024             while((ch = *fptr++)) {
1025                 if(match_flags & 1) {
1026                     reflags[left++] = ch;
1027                 }
1028                 match_flags >>= 1;
1029             }
1030 
1031             pattern = newSVpvn_flags(RX_PRECOMP(re),RX_PRELEN(re),
1032                                      (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
1033 
1034             /* return the pattern and the modifiers */
1035             PUSHs(pattern);
1036             PUSHs(newSVpvn_flags(reflags, left, SVs_TEMP));
1037             XSRETURN(2);
1038         } else {
1039             /* Scalar, so use the string that Perl would return */
1040             /* return the pattern in (?msixn:..) format */
1041             pattern = sv_2mortal(newSVsv(MUTABLE_SV(re)));
1042             PUSHs(pattern);
1043             XSRETURN(1);
1044         }
1045     } else {
1046         /* It ain't a regexp folks */
1047         if ( gimme == G_LIST ) {
1048             /* return the empty list */
1049             XSRETURN_EMPTY;
1050         } else {
1051             /* Because of the (?:..) wrapping involved in a
1052                stringified pattern it is impossible to get a
1053                result for a real regexp that would evaluate to
1054                false. Therefore we can return PL_sv_no to signify
1055                that the object is not a regex, this means that one
1056                can say
1057 
1058                  if (regex($might_be_a_regex) eq '(?:foo)') { }
1059 
1060                and not worry about undefined values.
1061             */
1062             XSRETURN_NO;
1063         }
1064     }
1065     NOT_REACHED; /* NOTREACHED */
1066 }
1067 
1068 #if defined(HAS_GETCWD) && defined(PERL_IS_MINIPERL)
1069 
1070 XS(XS_Internals_getcwd)
1071 {
1072     dXSARGS;
1073     SV *sv = sv_newmortal();
1074 
1075     if (items != 0)
1076         croak_xs_usage(cv, "");
1077 
1078     (void)getcwd_sv(sv);
1079 
1080     SvTAINTED_on(sv);
1081     PUSHs(sv);
1082     XSRETURN(1);
1083 }
1084 
1085 #endif
1086 
1087 XS(XS_NamedCapture_tie_it)
1088 {
1089     dXSARGS;
1090 
1091     if (items != 1)
1092         croak_xs_usage(cv,  "sv");
1093     {
1094         SV *sv = ST(0);
1095         GV * const gv = (GV *)sv;
1096         HV * const hv = GvHVn(gv);
1097         SV *rv = newSV_type(SVt_IV);
1098         const char *gv_name = GvNAME(gv);
1099 
1100         sv_setrv_noinc(rv, newSVuv(
1101             strEQ(gv_name, "-") || strEQ(gv_name, "\003APTURE_ALL")
1102             ? RXapif_ALL : RXapif_ONE));
1103         sv_bless(rv, GvSTASH(CvGV(cv)));
1104 
1105         sv_unmagic((SV *)hv, PERL_MAGIC_tied);
1106         sv_magic((SV *)hv, rv, PERL_MAGIC_tied, NULL, 0);
1107         SvREFCNT_dec(rv); /* As sv_magic increased it by one.  */
1108     }
1109     XSRETURN_EMPTY;
1110 }
1111 
1112 XS(XS_NamedCapture_TIEHASH)
1113 {
1114     dXSARGS;
1115     if (items < 1)
1116        croak_xs_usage(cv,  "package, ...");
1117     {
1118         const char *	package = (const char *)SvPV_nolen(ST(0));
1119         UV flag = RXapif_ONE;
1120         mark += 2;
1121         while(mark < sp) {
1122             STRLEN len;
1123             const char *p = SvPV_const(*mark, len);
1124             if(memEQs(p, len, "all"))
1125                 flag = SvTRUE(mark[1]) ? RXapif_ALL : RXapif_ONE;
1126             mark += 2;
1127         }
1128         ST(0) = newSV_type_mortal(SVt_IV);
1129         sv_setuv(newSVrv(ST(0), package), flag);
1130     }
1131     XSRETURN(1);
1132 }
1133 
1134 /* These are tightly coupled to the RXapif_* flags defined in regexp.h  */
1135 #define UNDEF_FATAL  0x80000
1136 #define DISCARD      0x40000
1137 #define EXPECT_SHIFT 24
1138 #define ACTION_MASK  0x000FF
1139 
1140 #define FETCH_ALIAS  (RXapif_FETCH  | (2 << EXPECT_SHIFT))
1141 #define STORE_ALIAS  (RXapif_STORE  | (3 << EXPECT_SHIFT) | UNDEF_FATAL | DISCARD)
1142 #define DELETE_ALIAS (RXapif_DELETE | (2 << EXPECT_SHIFT) | UNDEF_FATAL)
1143 #define CLEAR_ALIAS  (RXapif_CLEAR  | (1 << EXPECT_SHIFT) | UNDEF_FATAL | DISCARD)
1144 #define EXISTS_ALIAS (RXapif_EXISTS | (2 << EXPECT_SHIFT))
1145 #define SCALAR_ALIAS (RXapif_SCALAR | (1 << EXPECT_SHIFT))
1146 
1147 XS(XS_NamedCapture_FETCH)
1148 {
1149     dXSARGS;
1150     dXSI32;
1151     PERL_UNUSED_VAR(cv); /* -W */
1152     PERL_UNUSED_VAR(ax); /* -Wall */
1153     SP -= items;
1154     {
1155         REGEXP *const rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1156         U32 flags;
1157         SV *ret;
1158         const U32 action = ix & ACTION_MASK;
1159         const int expect = ix >> EXPECT_SHIFT;
1160         if (items != expect)
1161             croak_xs_usage(cv, expect == 2 ? "$key"
1162                                            : (expect == 3 ? "$key, $value"
1163                                                           : ""));
1164 
1165         if (!rx || !SvROK(ST(0))) {
1166             if (ix & UNDEF_FATAL)
1167                 Perl_croak_no_modify();
1168             else
1169                 XSRETURN_UNDEF;
1170         }
1171 
1172         flags = (U32)SvUV(SvRV(MUTABLE_SV(ST(0))));
1173 
1174         PUTBACK;
1175         ret = RX_ENGINE(rx)->named_buff(aTHX_ (rx), expect >= 2 ? ST(1) : NULL,
1176                                     expect >= 3 ? ST(2) : NULL, flags | action);
1177         SPAGAIN;
1178 
1179         if (ix & DISCARD) {
1180             /* Called with G_DISCARD, so our return stack state is thrown away.
1181                Hence if we were returned anything, free it immediately.  */
1182             SvREFCNT_dec(ret);
1183         } else {
1184             PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
1185         }
1186         PUTBACK;
1187         return;
1188     }
1189 }
1190 
1191 
1192 XS(XS_NamedCapture_FIRSTKEY)
1193 {
1194     dXSARGS;
1195     dXSI32;
1196     PERL_UNUSED_VAR(cv); /* -W */
1197     PERL_UNUSED_VAR(ax); /* -Wall */
1198     SP -= items;
1199     {
1200         REGEXP *const rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1201         U32 flags;
1202         SV *ret;
1203         const int expect = ix ? 2 : 1;
1204         const U32 action = ix ? RXapif_NEXTKEY : RXapif_FIRSTKEY;
1205         if (items != expect)
1206             croak_xs_usage(cv, expect == 2 ? "$lastkey" : "");
1207 
1208         if (!rx || !SvROK(ST(0)))
1209             XSRETURN_UNDEF;
1210 
1211         flags = (U32)SvUV(SvRV(MUTABLE_SV(ST(0))));
1212 
1213         PUTBACK;
1214         ret = RX_ENGINE(rx)->named_buff_iter(aTHX_ (rx),
1215                                              expect >= 2 ? ST(1) : NULL,
1216                                              flags | action);
1217         SPAGAIN;
1218 
1219         PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
1220         PUTBACK;
1221         return;
1222     }
1223 }
1224 
1225 /* is this still needed? */
1226 XS(XS_NamedCapture_flags)
1227 {
1228     dXSARGS;
1229     PERL_UNUSED_VAR(cv); /* -W */
1230     PERL_UNUSED_VAR(ax); /* -Wall */
1231     SP -= items;
1232     {
1233         EXTEND(SP, 2);
1234         mPUSHu(RXapif_ONE);
1235         mPUSHu(RXapif_ALL);
1236         PUTBACK;
1237         return;
1238     }
1239 }
1240 
1241 #include "vutil.h"
1242 #include "vxs.inc"
1243 
1244 struct xsub_details {
1245     const char *name;
1246     XSUBADDR_t xsub;
1247     const char *proto;
1248     int ix;
1249 };
1250 
1251 static const struct xsub_details these_details[] = {
1252     {"UNIVERSAL::isa", XS_UNIVERSAL_isa, NULL, 0 },
1253     {"UNIVERSAL::can", XS_UNIVERSAL_can, NULL, 0 },
1254     {"UNIVERSAL::DOES", XS_UNIVERSAL_DOES, NULL, 0 },
1255 #define VXS_XSUB_DETAILS
1256 #include "vxs.inc"
1257 #undef VXS_XSUB_DETAILS
1258     {"utf8::is_utf8", XS_utf8_is_utf8, NULL, 0 },
1259     {"utf8::valid", XS_utf8_valid, NULL, 0 },
1260     {"utf8::encode", XS_utf8_encode, NULL, 0 },
1261     {"utf8::decode", XS_utf8_decode, NULL, 0 },
1262     {"utf8::upgrade", XS_utf8_upgrade, NULL, 0 },
1263     {"utf8::downgrade", XS_utf8_downgrade, NULL, 0 },
1264     {"utf8::native_to_unicode", XS_utf8_native_to_unicode, NULL, 0 },
1265     {"utf8::unicode_to_native", XS_utf8_unicode_to_native, NULL, 0 },
1266     {"Internals::SvREADONLY", XS_Internals_SvREADONLY, "\\[$%@];$", 0 },
1267     {"Internals::SvREFCNT", XS_Internals_SvREFCNT, "\\[$%@];$", 0 },
1268     {"Internals::hv_clear_placeholders", XS_Internals_hv_clear_placehold, "\\%", 0 },
1269     {"constant::_make_const", XS_constant__make_const, "\\[$@]", 0 },
1270     {"PerlIO::get_layers", XS_PerlIO_get_layers, "*;@", 0 },
1271     {"re::is_regexp", XS_re_is_regexp, "$", 0 },
1272     {"re::regname", XS_re_regname, ";$$", 0 },
1273     {"re::regnames", XS_re_regnames, ";$", 0 },
1274     {"re::regnames_count", XS_re_regnames_count, "", 0 },
1275     {"re::regexp_pattern", XS_re_regexp_pattern, "$", 0 },
1276 #if defined(HAS_GETCWD) && defined(PERL_IS_MINIPERL)
1277     {"Internals::getcwd", XS_Internals_getcwd, "", 0 },
1278 #endif
1279     {"Tie::Hash::NamedCapture::_tie_it", XS_NamedCapture_tie_it, NULL, 0 },
1280     {"Tie::Hash::NamedCapture::TIEHASH", XS_NamedCapture_TIEHASH, NULL, 0 },
1281     {"Tie::Hash::NamedCapture::FETCH", XS_NamedCapture_FETCH, NULL, FETCH_ALIAS },
1282     {"Tie::Hash::NamedCapture::STORE", XS_NamedCapture_FETCH, NULL, STORE_ALIAS },
1283     {"Tie::Hash::NamedCapture::DELETE", XS_NamedCapture_FETCH, NULL, DELETE_ALIAS },
1284     {"Tie::Hash::NamedCapture::CLEAR", XS_NamedCapture_FETCH, NULL, CLEAR_ALIAS },
1285     {"Tie::Hash::NamedCapture::EXISTS", XS_NamedCapture_FETCH, NULL, EXISTS_ALIAS },
1286     {"Tie::Hash::NamedCapture::SCALAR", XS_NamedCapture_FETCH, NULL, SCALAR_ALIAS },
1287     {"Tie::Hash::NamedCapture::FIRSTKEY", XS_NamedCapture_FIRSTKEY, NULL, 0 },
1288     {"Tie::Hash::NamedCapture::NEXTKEY", XS_NamedCapture_FIRSTKEY, NULL, 1 },
1289     {"Tie::Hash::NamedCapture::flags", XS_NamedCapture_flags, NULL, 0 },
1290 };
1291 
1292 STATIC OP*
1293 optimize_out_native_convert_function(pTHX_ OP* entersubop,
1294                                            GV* namegv,
1295                                            SV* protosv)
1296 {
1297     /* Optimizes out an identity function, i.e., one that just returns its
1298      * argument.  The passed in function is assumed to be an identity function,
1299      * with no checking.  This is designed to be called for utf8_to_native()
1300      * and native_to_utf8() on ASCII platforms, as they just return their
1301      * arguments, but it could work on any such function.
1302      *
1303      * The code is mostly just cargo-culted from Memoize::Lift */
1304 
1305     OP *pushop, *argop;
1306     OP *parent;
1307     SV* prototype = newSVpvs("$");
1308 
1309     PERL_UNUSED_ARG(protosv);
1310 
1311     assert(entersubop->op_type == OP_ENTERSUB);
1312 
1313     entersubop = ck_entersub_args_proto(entersubop, namegv, prototype);
1314     parent = entersubop;
1315 
1316     SvREFCNT_dec(prototype);
1317 
1318     pushop = cUNOPx(entersubop)->op_first;
1319     if (! OpHAS_SIBLING(pushop)) {
1320         parent = pushop;
1321         pushop = cUNOPx(pushop)->op_first;
1322     }
1323     argop = OpSIBLING(pushop);
1324 
1325     /* Carry on without doing the optimization if it is not something we're
1326      * expecting, so continues to work */
1327     if (   ! argop
1328         || ! OpHAS_SIBLING(argop)
1329         ||   OpHAS_SIBLING(OpSIBLING(argop))
1330     ) {
1331         return entersubop;
1332     }
1333 
1334     /* cut argop from the subtree */
1335     (void)op_sibling_splice(parent, pushop, 1, NULL);
1336 
1337     op_free(entersubop);
1338     return argop;
1339 }
1340 
1341 void
1342 Perl_boot_core_UNIVERSAL(pTHX)
1343 {
1344     static const char file[] = __FILE__;
1345     const struct xsub_details *xsub = these_details;
1346     const struct xsub_details *end = C_ARRAY_END(these_details);
1347 
1348     do {
1349         CV *cv = newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);
1350         XSANY.any_i32 = xsub->ix;
1351     } while (++xsub < end);
1352 
1353 #ifndef EBCDIC
1354     { /* On ASCII platforms these functions just return their argument, so can
1355          be optimized away */
1356 
1357         CV* to_native_cv = get_cv("utf8::unicode_to_native", 0);
1358         CV* to_unicode_cv = get_cv("utf8::native_to_unicode", 0);
1359 
1360         cv_set_call_checker_flags(to_native_cv,
1361                             optimize_out_native_convert_function,
1362                             (SV*) to_native_cv, 0);
1363         cv_set_call_checker_flags(to_unicode_cv,
1364                             optimize_out_native_convert_function,
1365                             (SV*) to_unicode_cv, 0);
1366     }
1367 #endif
1368 
1369     /* Providing a Regexp::DESTROY fixes #21347. See test in t/op/ref.t  */
1370     {
1371         CV * const cv =
1372             newCONSTSUB(get_hv("Regexp::", GV_ADD), "DESTROY", NULL);
1373         char ** cvfile = &CvFILE(cv);
1374         char * oldfile = *cvfile;
1375         CvDYNFILE_off(cv);
1376         *cvfile = (char *)file;
1377         Safefree(oldfile);
1378     }
1379 }
1380 
1381 /*
1382  * ex: set ts=8 sts=4 sw=4 et:
1383  */
1384