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