This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
remove DOES's usage of SvSCREAM
[perl5.git] / universal.c
index c219411..b88d3e2 100644 (file)
@@ -184,6 +184,10 @@ The SV can be a Perl object or the name of a Perl class.
 
 #include "XSUB.h"
 
+/* a special string address whose value is "isa", but whicb perl knows
+ * to treat as if it were really "DOES" */
+char PL_isa_DOES[] = "isa";
+
 bool
 Perl_sv_does_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
 {
@@ -205,7 +209,7 @@ Perl_sv_does_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
        return FALSE;
     }
 
-    if (sv_isobject(sv)) {
+    if (SvROK(sv) && SvOBJECT(SvRV(sv))) {
        classname = sv_ref(NULL,SvRV(sv),TRUE);
     } else {
        classname = sv;
@@ -222,11 +226,14 @@ Perl_sv_does_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
     PUSHs(namesv);
     PUTBACK;
 
-    methodname = newSVpvs_flags("isa", SVs_TEMP);
-    /* ugly hack: use the SvSCREAM flag so S_method_common
-     * can figure out we're calling DOES() and not isa(),
-     * and report eventual errors correctly. --rgs */
-    SvSCREAM_on(methodname);
+    /* create a PV with value "isa", but with a special address
+     * so that perl knows were' realling doing "DOES" instead */
+    methodname = newSV_type(SVt_PV);
+    SvLEN(methodname) = 0;
+    SvCUR(methodname) = strlen(PL_isa_DOES);
+    SvPVX(methodname) = PL_isa_DOES;
+    SvPOK_on(methodname);
+    sv_2mortal(methodname);
     call_sv(methodname, G_SCALAR | G_METHOD);
     SPAGAIN;
 
@@ -294,7 +301,8 @@ A specialised variant of C<croak()> for emitting the usage message for xsubs
 works out the package name and subroutine name from C<cv>, and then calls
 C<croak()>.  Hence if C<cv> is C<&ouch::awk>, it would call C<croak> as:
 
-    Perl_croak(aTHX_ "Usage: %"SVf"::%"SVf"(%s)", "ouch" "awk", "eee_yow");
+ Perl_croak(aTHX_ "Usage: %"SVf"::%"SVf"(%s)", "ouch" "awk",
+                                                     "eee_yow");
 
 =cut
 */
@@ -302,11 +310,12 @@ C<croak()>.  Hence if C<cv> is C<&ouch::awk>, it would call C<croak> as:
 void
 Perl_croak_xs_usage(const CV *const cv, const char *const params)
 {
-    const GV *const gv = CvGV(cv);
+    /* Avoid CvGV as it requires aTHX.  */
+    const GV *gv = CvNAMED(cv) ? NULL : cv->sv_any->xcv_gv_u.xcv_gv;
 
     PERL_ARGS_ASSERT_CROAK_XS_USAGE;
 
-    if (gv) {
+    if (gv) got_gv: {
        const HV *const stash = GvSTASH(gv);
 
        if (HvNAME_get(stash))
@@ -320,9 +329,12 @@ Perl_croak_xs_usage(const CV *const cv, const char *const params)
            Perl_croak_nocontext("Usage: %"HEKf"(%s)",
                                 HEKfARG(GvNAME_HEK(gv)), params);
     } else {
+        dTHX;
+        if ((gv = CvGV(cv))) goto got_gv;
+
        /* Pants. I don't think that it should be possible to get here. */
        /* diag_listed_as: SKIPME */
-       Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
+       Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
     }
 }
 
@@ -519,7 +531,7 @@ XS(XS_utf8_native_to_unicode)
  if (items > 1)
      croak_xs_usage(cv, "sv");
 
- ST(0) = sv_2mortal(newSViv(NATIVE_TO_UNI(uv)));
+ ST(0) = sv_2mortal(newSVuv(NATIVE_TO_UNI(uv)));
  XSRETURN(1);
 }
 
@@ -532,7 +544,7 @@ XS(XS_utf8_unicode_to_native)
  if (items > 1)
      croak_xs_usage(cv, "sv");
 
- ST(0) = sv_2mortal(newSViv(UNI_TO_NATIVE(uv)));
+ ST(0) = sv_2mortal(newSVuv(UNI_TO_NATIVE(uv)));
  XSRETURN(1);
 }
 
@@ -558,15 +570,12 @@ XS(XS_Internals_SvREADONLY)       /* This is dangerous stuff. */
     }
     else if (items == 2) {
        if (SvTRUE(ST(1))) {
-#ifdef PERL_OLD_COPY_ON_WRITE
-           if (SvIsCOW(sv)) sv_force_normal(sv);
-#endif
-           SvREADONLY_on(sv);
+           SvFLAGS(sv) |= SVf_READONLY;
            XSRETURN_YES;
        }
        else {
            /* I hope you really know what you are doing. */
-           SvREADONLY_off(sv);
+           SvFLAGS(sv) &=~ SVf_READONLY;
            XSRETURN_NO;
        }
     }
@@ -587,9 +596,6 @@ XS(XS_constant__make_const) /* This is dangerous stuff. */
 
     sv = SvRV(svz);
 
-#ifdef PERL_OLD_COPY_ON_WRITE
-    if (SvIsCOW(sv)) sv_force_normal(sv);
-#endif
     SvREADONLY_on(sv);
     if (SvTYPE(sv) == SVt_PVAV && AvFILLp(sv) != -1) {
        /* for constant.pm; nobody else should be calling this
@@ -666,19 +672,19 @@ XS(XS_PerlIO_get_layers)
 
                  switch (*key) {
                  case 'i':
-                      if (klen == 5 && memEQ(key, "input", 5)) {
+                       if (memEQs(key, klen, "input")) {
                            input = SvTRUE(*valp);
                            break;
                       }
                       goto fail;
                  case 'o': 
-                      if (klen == 6 && memEQ(key, "output", 6)) {
+                       if (memEQs(key, klen, "output")) {
                            input = !SvTRUE(*valp);
                            break;
                       }
                       goto fail;
                  case 'd':
-                      if (klen == 7 && memEQ(key, "details", 7)) {
+                       if (memEQs(key, klen, "details")) {
                            details = SvTRUE(*valp);
                            break;
                       }
@@ -767,7 +773,6 @@ XS(XS_PerlIO_get_layers)
     XSRETURN(0);
 }
 
-
 XS(XS_re_is_regexp); /* prototype to pass -Wmissing-prototypes */
 XS(XS_re_is_regexp)
 {
@@ -794,9 +799,6 @@ XS(XS_re_regnames_count)
     if (items != 0)
        croak_xs_usage(cv, "");
 
-    SP -= items;
-    PUTBACK;
-
     if (!rx)
         XSRETURN_UNDEF;
 
@@ -899,6 +901,7 @@ XS(XS_re_regexp_pattern)
 {
     dXSARGS;
     REGEXP *re;
+    U8 const gimme = GIMME_V;
 
     EXTEND(SP, 2);
     SP -= items;
@@ -921,7 +924,7 @@ XS(XS_re_regexp_pattern)
         /* Houston, we have a regex! */
         SV *pattern;
 
-        if ( GIMME_V == G_ARRAY ) {
+        if ( gimme == G_ARRAY ) {
            STRLEN left = 0;
            char reflags[sizeof(INT_PAT_MODS) + MAX_CHARSET_NAME_LENGTH];
             const char *fptr;
@@ -961,7 +964,7 @@ XS(XS_re_regexp_pattern)
             XSRETURN(2);
         } else {
             /* Scalar, so use the string that Perl would return */
-            /* return the pattern in (?msix:..) format */
+            /* return the pattern in (?msixn:..) format */
 #if PERL_VERSION >= 11
             pattern = sv_2mortal(newSVsv(MUTABLE_SV(re)));
 #else
@@ -973,9 +976,9 @@ XS(XS_re_regexp_pattern)
         }
     } else {
         /* It ain't a regexp folks */
-        if ( GIMME_V == G_ARRAY ) {
+        if ( gimme == G_ARRAY ) {
             /* return the empty list */
-            XSRETURN_UNDEF;
+            XSRETURN_EMPTY;
         } else {
             /* Because of the (?:..) wrapping involved in a
                stringified pattern it is impossible to get a
@@ -991,7 +994,7 @@ XS(XS_re_regexp_pattern)
             XSRETURN_NO;
         }
     }
-    /* NOT-REACHED */
+    NOT_REACHED; /* NOTREACHED */
 }
 
 #include "vutil.h"
@@ -1019,9 +1022,9 @@ static const struct xsub_details details[] = {
     {"utf8::native_to_unicode", XS_utf8_native_to_unicode, NULL},
     {"utf8::unicode_to_native", XS_utf8_unicode_to_native, NULL},
     {"Internals::SvREADONLY", XS_Internals_SvREADONLY, "\\[$%@];$"},
-    {"constant::_make_const", XS_constant__make_const, "\\[$@]"},
     {"Internals::SvREFCNT", XS_Internals_SvREFCNT, "\\[$%@];$"},
     {"Internals::hv_clear_placeholders", XS_Internals_hv_clear_placehold, "\\%"},
+    {"constant::_make_const", XS_constant__make_const, "\\[$@]"},
     {"PerlIO::get_layers", XS_PerlIO_get_layers, "*;@"},
     {"re::is_regexp", XS_re_is_regexp, "$"},
     {"re::regname", XS_re_regname, ";$$"},
@@ -1030,6 +1033,55 @@ static const struct xsub_details details[] = {
     {"re::regexp_pattern", XS_re_regexp_pattern, "$"},
 };
 
+STATIC OP*
+optimize_out_native_convert_function(pTHX_ OP* entersubop,
+                                           GV* namegv,
+                                           SV* protosv)
+{
+    /* Optimizes out an identity function, i.e., one that just returns its
+     * argument.  The passed in function is assumed to be an identity function,
+     * with no checking.  This is designed to be called for utf8_to_native()
+     * and native_to_utf8() on ASCII platforms, as they just return their
+     * arguments, but it could work on any such function.
+     *
+     * The code is mostly just cargo-culted from Memoize::Lift */
+
+    OP *pushop, *argop;
+    OP *parent;
+    SV* prototype = newSVpvs("$");
+
+    PERL_UNUSED_ARG(protosv);
+
+    assert(entersubop->op_type == OP_ENTERSUB);
+
+    entersubop = ck_entersub_args_proto(entersubop, namegv, prototype);
+    parent = entersubop;
+
+    SvREFCNT_dec(prototype);
+
+    pushop = cUNOPx(entersubop)->op_first;
+    if (! OpHAS_SIBLING(pushop)) {
+        parent = pushop;
+        pushop = cUNOPx(pushop)->op_first;
+    }
+    argop = OpSIBLING(pushop);
+
+    /* Carry on without doing the optimization if it is not something we're
+     * expecting, so continues to work */
+    if (   ! argop
+        || ! OpHAS_SIBLING(argop)
+        ||   OpHAS_SIBLING(OpSIBLING(argop))
+    ) {
+        return entersubop;
+    }
+
+    /* cut argop from the subtree */
+    (void)op_sibling_splice(parent, pushop, 1, NULL);
+
+    op_free(entersubop);
+    return argop;
+}
+
 void
 Perl_boot_core_UNIVERSAL(pTHX)
 {
@@ -1041,22 +1093,34 @@ Perl_boot_core_UNIVERSAL(pTHX)
        newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);
     } while (++xsub < end);
 
+#ifndef EBCDIC
+    { /* On ASCII platforms these functions just return their argument, so can
+         be optimized away */
+
+        CV* to_native_cv = get_cv("utf8::unicode_to_native", 0);
+        CV* to_unicode_cv = get_cv("utf8::native_to_unicode", 0);
+
+        cv_set_call_checker(to_native_cv,
+                            optimize_out_native_convert_function,
+                            (SV*) to_native_cv);
+        cv_set_call_checker(to_unicode_cv,
+                            optimize_out_native_convert_function,
+                            (SV*) to_unicode_cv);
+    }
+#endif
+
     /* Providing a Regexp::DESTROY fixes #21347. See test in t/op/ref.t  */
     {
        CV * const cv =
            newCONSTSUB(get_hv("Regexp::", GV_ADD), "DESTROY", NULL);
-       Safefree(CvFILE(cv));
-       CvFILE(cv) = (char *)file;
+       char ** cvfile = &CvFILE(cv);
+       char * oldfile = *cvfile;
        CvDYNFILE_off(cv);
+       *cvfile = (char *)file;
+       Safefree(oldfile);
     }
 }
 
 /*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
  * ex: set ts=8 sts=4 sw=4 et:
  */