X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/ed1db70e12244166baee8553bcdfe1e16a620f19..378516de21aea9be747038c25876881aaf56e166:/universal.c diff --git a/universal.c b/universal.c index a03296d..847de55 100644 --- a/universal.c +++ b/universal.c @@ -154,7 +154,7 @@ Perl_sv_derived_from_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, SvGETMAGIC(sv); - if (SvROK(sv)) { /* hugdo: */ + if (SvROK(sv)) { const char *type; sv = SvRV(sv); type = sv_reftype(sv,0); @@ -164,6 +164,8 @@ Perl_sv_derived_from_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, } else { stash = gv_stashsv(sv, 0); + if (!stash) + stash = gv_stashpvs("UNIVERSAL", 0); } return stash ? isa_lookup(stash, name, len, flags) : FALSE; @@ -196,8 +198,7 @@ Perl_sv_does_sv(pTHX_ SV *sv, SV *namesv, U32 flags) SvGETMAGIC(sv); - if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)) - || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv)))) { + if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)))) { LEAVE; return FALSE; } @@ -297,7 +298,7 @@ C. Hence if C is C<&ouch::awk>, it would call C as: */ void -Perl_croak_xs_usage(pTHX_ const CV *const cv, const char *const params) +Perl_croak_xs_usage(const CV *const cv, const char *const params) { const GV *const gv = CvGV(cv); @@ -307,16 +308,16 @@ Perl_croak_xs_usage(pTHX_ const CV *const cv, const char *const params) const HV *const stash = GvSTASH(gv); if (HvNAME_get(stash)) - Perl_croak(aTHX_ "Usage: %"SVf"::%"SVf"(%s)", - SVfARG(sv_2mortal(newSVhek(HvNAME_HEK(stash)))), - SVfARG(sv_2mortal(newSVhek(GvNAME_HEK(gv)))), + Perl_croak_nocontext("Usage: %"HEKf"::%"HEKf"(%s)", + HEKfARG(HvNAME_HEK(stash)), + HEKfARG(GvNAME_HEK(gv)), params); else - Perl_croak(aTHX_ "Usage: %"SVf"(%s)", - SVfARG(sv_2mortal(newSVhek(GvNAME_HEK(gv)))), params); + Perl_croak_nocontext("Usage: %"HEKf"(%s)", + HEKfARG(GvNAME_HEK(gv)), params); } else { /* Pants. I don't think that it should be possible to get here. */ - Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params); + Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params); } } @@ -332,8 +333,7 @@ XS(XS_UNIVERSAL_isa) SvGETMAGIC(sv); - if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)) - || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv)))) + if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)))) XSRETURN_UNDEF; ST(0) = boolSV(sv_derived_from_sv(sv, ST(1), 0)); @@ -348,6 +348,7 @@ XS(XS_UNIVERSAL_can) SV *sv; SV *rv; HV *pkg = NULL; + GV *iogv; if (items != 2) croak_xs_usage(cv, "object-ref, method"); @@ -356,8 +357,10 @@ XS(XS_UNIVERSAL_can) SvGETMAGIC(sv); - if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)) - || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv)))) + /* Reject undef and empty string. Note that the string form takes + precedence here over the numeric form, as (!1)->foo treats the + invocant as the empty string, though it is a dualvar. */ + if (!SvOK(sv) || (SvPOK(sv) && !SvCUR(sv))) XSRETURN_UNDEF; rv = &PL_sv_undef; @@ -366,9 +369,17 @@ XS(XS_UNIVERSAL_can) sv = MUTABLE_SV(SvRV(sv)); if (SvOBJECT(sv)) pkg = SvSTASH(sv); + else if (isGV_with_GP(sv) && GvIO(sv)) + pkg = SvSTASH(GvIO(sv)); } + else if (isGV_with_GP(sv) && GvIO(sv)) + pkg = SvSTASH(GvIO(sv)); + else if ((iogv = gv_fetchsv_nomg(sv, 0, SVt_PVIO)) && GvIO(iogv)) + pkg = SvSTASH(GvIO(iogv)); else { pkg = gv_stashsv(sv, 0); + if (!pkg) + pkg = gv_stashpv("UNIVERSAL", 0); } if (pkg) { @@ -406,7 +417,6 @@ XS(XS_UNIVERSAL_VERSION) GV **gvp; GV *gv; SV *sv; - SV *ret; const char *undef; PERL_UNUSED_ARG(cv); @@ -423,12 +433,16 @@ XS(XS_UNIVERSAL_VERSION) gvp = pkg ? (GV**)hv_fetchs(pkg, "VERSION", FALSE) : NULL; if (gvp && isGV(gv = *gvp) && (sv = GvSV(gv)) && SvOK(sv)) { - ret = sv_newmortal(); - sv_setsv(ret, sv); + SV * const nsv = sv_newmortal(); + sv_setsv(nsv, sv); + sv = nsv; + if ( !sv_isobject(sv) || !sv_derived_from(sv, "version")) + upg_version(sv, FALSE); + undef = NULL; } else { - sv = ret = &PL_sv_undef; + sv = &PL_sv_undef; undef = "(undef)"; } @@ -437,10 +451,11 @@ XS(XS_UNIVERSAL_VERSION) if (undef) { if (pkg) { - const SV * const name = sv_2mortal(newSVhek(HvNAME_HEK(pkg))); + const HEK * const name = HvNAME_HEK(pkg); Perl_croak(aTHX_ - "%"SVf" does not define $%"SVf"::VERSION--version check failed", - SVfARG(name), SVfARG(name)); + "%"HEKf" does not define $%"HEKf + "::VERSION--version check failed", + HEKfARG(name), HEKfARG(name)); } else { Perl_croak(aTHX_ "%"SVf" defines neither package nor VERSION--version check failed", @@ -448,25 +463,22 @@ XS(XS_UNIVERSAL_VERSION) } } - if ( !sv_derived_from(sv, "version")) - upg_version(sv, FALSE); - - if ( !sv_derived_from(req, "version")) { + if ( !sv_isobject(req) || !sv_derived_from(req, "version")) { /* req may very well be R/O, so create a new object */ req = sv_2mortal( new_version(req) ); } if ( vcmp( req, sv ) > 0 ) { if ( hv_exists(MUTABLE_HV(SvRV(req)), "qv", 2 ) ) { - Perl_croak(aTHX_ "%"SVf" version %"SVf" required--" + Perl_croak(aTHX_ "%"HEKf" version %"SVf" required--" "this is only version %"SVf"", - SVfARG(sv_2mortal(newSVhek(HvNAME_HEK(pkg)))), + HEKfARG(HvNAME_HEK(pkg)), SVfARG(sv_2mortal(vnormal(req))), SVfARG(sv_2mortal(vnormal(sv)))); } else { - Perl_croak(aTHX_ "%"SVf" version %"SVf" required--" + Perl_croak(aTHX_ "%"HEKf" version %"SVf" required--" "this is only version %"SVf, - SVfARG(sv_2mortal(newSVhek(HvNAME_HEK(pkg)))), + HEKfARG(HvNAME_HEK(pkg)), SVfARG(sv_2mortal(vstringify(req))), SVfARG(sv_2mortal(vstringify(sv)))); } @@ -474,7 +486,11 @@ XS(XS_UNIVERSAL_VERSION) } - ST(0) = ret; + if ( SvOK(sv) && sv_derived_from(sv, "version") ) { + ST(0) = sv_2mortal(vstringify(sv)); + } else { + ST(0) = sv; + } XSRETURN(1); } @@ -483,7 +499,7 @@ XS(XS_version_new) { dVAR; dXSARGS; - if (items > 3) + if (items > 3 || items < 1) croak_xs_usage(cv, "class, version"); SP -= items; { @@ -533,7 +549,7 @@ XS(XS_version_stringify) { SV * lobj = ST(0); - if (sv_derived_from(lobj, "version") && SvROK(lobj)) { + if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) { lobj = SvRV(lobj); } else @@ -556,7 +572,7 @@ XS(XS_version_numify) { SV * lobj = ST(0); - if (sv_derived_from(lobj, "version") && SvROK(lobj)) { + if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) { lobj = SvRV(lobj); } else @@ -579,7 +595,7 @@ XS(XS_version_normal) { SV * lobj = ST(0); - if (sv_derived_from(lobj, "version") && SvROK(lobj)) { + if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) { lobj = SvRV(lobj); } else @@ -602,7 +618,7 @@ XS(XS_version_vcmp) { SV * lobj = ST(0); - if (sv_derived_from(lobj, "version") && SvROK(lobj)) { + if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) { lobj = SvRV(lobj); } else @@ -614,7 +630,7 @@ XS(XS_version_vcmp) SV * robj = ST(1); const IV swap = (IV)SvIV(ST(2)); - if ( ! sv_derived_from(robj, "version") ) + if ( !sv_isobject(robj) || !sv_derived_from(robj, "version") ) { robj = new_version(SvOK(robj) ? robj : newSVpvs_flags("0", SVs_TEMP)); sv_2mortal(robj); @@ -645,9 +661,15 @@ XS(XS_version_boolean) if (items < 1) croak_xs_usage(cv, "lobj, ..."); SP -= items; - if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) { + if (sv_isobject(ST(0)) && sv_derived_from(ST(0), "version")) { SV * const lobj = SvRV(ST(0)); - SV * const rs = newSViv( vcmp(lobj,new_version(newSVpvs("0"))) ); + SV * const rs = + newSViv( vcmp(lobj, + sv_2mortal(new_version( + sv_2mortal(newSVpvs("0")) + )) + ) + ); mPUSHs(rs); PUTBACK; return; @@ -662,7 +684,7 @@ XS(XS_version_noop) dXSARGS; if (items < 1) croak_xs_usage(cv, "lobj, ..."); - if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) + if (sv_isobject(ST(0)) && sv_derived_from(ST(0), "version")) Perl_croak(aTHX_ "operation not supported with version object"); else Perl_croak(aTHX_ "lobj is not of type version"); @@ -678,7 +700,7 @@ XS(XS_version_is_alpha) if (items != 1) croak_xs_usage(cv, "lobj"); SP -= items; - if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) { + if (sv_isobject(ST(0)) && sv_derived_from(ST(0), "version")) { SV * const lobj = ST(0); if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "alpha", 5 ) ) XSRETURN_YES; @@ -740,7 +762,7 @@ XS(XS_version_is_qv) if (items != 1) croak_xs_usage(cv, "lobj"); SP -= items; - if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) { + if (sv_isobject(ST(0)) && sv_derived_from(ST(0), "version")) { SV * const lobj = ST(0); if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "qv", 2 ) ) XSRETURN_YES; @@ -795,6 +817,7 @@ XS(XS_utf8_encode) if (items != 1) croak_xs_usage(cv, "sv"); sv_utf8_encode(ST(0)); + SvSETMAGIC(ST(0)); XSRETURN_EMPTY; } @@ -807,8 +830,9 @@ XS(XS_utf8_decode) else { SV * const sv = ST(0); bool RETVAL; - if (SvIsCOW(sv)) sv_force_normal(sv); + SvPV_force_nolen(sv); RETVAL = sv_utf8_decode(sv); + SvSETMAGIC(sv); ST(0) = boolSV(RETVAL); } XSRETURN(1); @@ -888,48 +912,59 @@ XS(XS_Internals_SvREADONLY) /* This is dangerous stuff. */ sv = SvRV(svz); if (items == 1) { - if (SvREADONLY(sv) && !SvIsCOW(sv)) + if (SvREADONLY(sv)) XSRETURN_YES; else XSRETURN_NO; } 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); + if (SvTYPE(sv) == SVt_PVAV && AvFILLp(sv) != -1) { + /* for constant.pm; nobody else should be calling this + on arrays anyway. */ + SV **svp; + for (svp = AvARRAY(sv) + AvFILLp(sv) + ; svp >= AvARRAY(sv) + ; --svp) + if (*svp) SvPADTMP_on(*svp); + } XSRETURN_YES; } else { /* I hope you really know what you are doing. */ - if (!SvIsCOW(sv)) SvREADONLY_off(sv); + SvREADONLY_off(sv); XSRETURN_NO; } } XSRETURN_UNDEF; /* Can't happen. */ } - XS(XS_Internals_SvREFCNT) /* This is dangerous stuff. */ { dVAR; dXSARGS; SV * const svz = ST(0); SV * sv; + U32 refcnt; PERL_UNUSED_ARG(cv); /* [perl #77776] - called as &foo() not foo() */ - if (!SvROK(svz)) + if ((items != 1 && items != 2) || !SvROK(svz)) croak_xs_usage(cv, "SCALAR[, REFCOUNT]"); sv = SvRV(svz); - if (items == 1) - XSRETURN_IV(SvREFCNT(sv) - 1); /* Minus the ref created for us. */ - else if (items == 2) { /* I hope you really know what you are doing. */ - SvREFCNT(sv) = SvIV(ST(1)); - XSRETURN_IV(SvREFCNT(sv)); - } - XSRETURN_UNDEF; /* Can't happen. */ + /* idea is for SvREFCNT(sv) to be accessed only once */ + refcnt = items == 2 ? + /* we free one ref on exit */ + (SvREFCNT(sv) = SvUV(ST(1)) + 1) + : SvREFCNT(sv); + XSRETURN_UV(refcnt - 1); /* Minus the ref created for us. */ + } XS(XS_Internals_hv_clear_placehold) @@ -999,21 +1034,17 @@ XS(XS_PerlIO_get_layers) } sv = POPs; - gv = MUTABLE_GV(sv); + gv = MAYBE_DEREF_GV(sv); - if (!isGV(sv)) { - if (SvROK(sv) && isGV(SvRV(sv))) - gv = MUTABLE_GV(SvRV(sv)); - else if (SvPOKp(sv)) - gv = gv_fetchsv(sv, 0, SVt_PVIO); - } + if (!gv && !SvROK(sv)) + gv = gv_fetchsv_nomg(sv, 0, SVt_PVIO); if (gv && (io = GvIO(gv))) { AV* const av = PerlIO_get_layers(aTHX_ input ? IoIFP(io) : IoOFP(io)); - I32 i; - const I32 last = av_len(av); - I32 nitem = 0; + SSize_t i; + const SSize_t last = av_len(av); + SSize_t nitem = 0; for (i = last; i >= 0; i -= 3) { SV * const * const namsvp = av_fetch(av, i - 2, FALSE); @@ -1024,40 +1055,41 @@ XS(XS_PerlIO_get_layers) const bool argok = argsvp && *argsvp && SvPOK(*argsvp); const bool flgok = flgsvp && *flgsvp && SvIOK(*flgsvp); + EXTEND(SP, 3); /* Three is the max in all branches: better check just once */ if (details) { /* Indents of 5? Yuck. */ /* We know that PerlIO_get_layers creates a new SV for the name and flags, so we can just take a reference and "steal" it when we free the AV below. */ - XPUSHs(namok + PUSHs(namok ? sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp)) : &PL_sv_undef); - XPUSHs(argok + PUSHs(argok ? newSVpvn_flags(SvPVX_const(*argsvp), SvCUR(*argsvp), (SvUTF8(*argsvp) ? SVf_UTF8 : 0) | SVs_TEMP) : &PL_sv_undef); - XPUSHs(flgok + PUSHs(flgok ? sv_2mortal(SvREFCNT_inc_simple_NN(*flgsvp)) : &PL_sv_undef); nitem += 3; } else { if (namok && argok) - XPUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%"SVf"(%"SVf")", + PUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%"SVf"(%"SVf")", SVfARG(*namsvp), SVfARG(*argsvp)))); else if (namok) - XPUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp))); + PUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp))); else - XPUSHs(&PL_sv_undef); + PUSHs(&PL_sv_undef); nitem++; if (flgok) { const IV flags = SvIVX(*flgsvp); if (flags & PERLIO_F_UTF8) { - XPUSHs(newSVpvs_flags("utf8", SVs_TEMP)); + PUSHs(newSVpvs_flags("utf8", SVs_TEMP)); nitem++; } } @@ -1074,44 +1106,6 @@ XS(XS_PerlIO_get_layers) XSRETURN(0); } -XS(XS_Internals_hash_seed) -{ - dVAR; - /* Using dXSARGS would also have dITEM and dSP, - * which define 2 unused local variables. */ - dAXMARK; - PERL_UNUSED_ARG(cv); - PERL_UNUSED_VAR(mark); - XSRETURN_UV(PERL_HASH_SEED); -} - -XS(XS_Internals_rehash_seed) -{ - dVAR; - /* Using dXSARGS would also have dITEM and dSP, - * which define 2 unused local variables. */ - dAXMARK; - PERL_UNUSED_ARG(cv); - PERL_UNUSED_VAR(mark); - XSRETURN_UV(PL_rehash_seed); -} - -XS(XS_Internals_HvREHASH) /* Subject to change */ -{ - dVAR; - dXSARGS; - PERL_UNUSED_ARG(cv); - if (SvROK(ST(0))) { - const HV * const hv = (const HV *) SvRV(ST(0)); - if (items == 1 && SvTYPE(hv) == SVt_PVHV) { - if (HvREHASH(hv)) - XSRETURN_YES; - else - XSRETURN_NO; - } - } - Perl_croak(aTHX_ "Internals::HvREHASH $hashref"); -} XS(XS_re_is_regexp) { @@ -1192,8 +1186,8 @@ XS(XS_re_regnames) U32 flags; SV *ret; AV *av; - I32 length; - I32 i; + SSize_t length; + SSize_t i; SV **entry; if (items > 1) @@ -1223,13 +1217,14 @@ XS(XS_re_regnames) av = MUTABLE_AV(SvRV(ret)); length = av_len(av); + EXTEND(SP, length+1); /* better extend stack just once */ for (i = 0; i <= length; i++) { entry = av_fetch(av, i, FALSE); if (!entry) Perl_croak(aTHX_ "NULL array element in re::regnames()"); - mXPUSHs(SvREFCNT_inc_simple_NN(*entry)); + mPUSHs(SvREFCNT_inc_simple_NN(*entry)); } SvREFCNT_dec(ret); @@ -1244,11 +1239,11 @@ XS(XS_re_regexp_pattern) dXSARGS; REGEXP *re; + EXTEND(SP, 2); + SP -= items; if (items != 1) croak_xs_usage(cv, "sv"); - SP -= items; - /* Checks if a reference is a regex or not. If the parameter is not a ref, or is not the result of a qr// then returns false @@ -1300,8 +1295,8 @@ XS(XS_re_regexp_pattern) (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP); /* return the pattern and the modifiers */ - XPUSHs(pattern); - XPUSHs(newSVpvn_flags(reflags, left, SVs_TEMP)); + PUSHs(pattern); + PUSHs(newSVpvn_flags(reflags, left, SVs_TEMP)); XSRETURN(2); } else { /* Scalar, so use the string that Perl would return */ @@ -1312,7 +1307,7 @@ XS(XS_re_regexp_pattern) pattern = newSVpvn_flags(RX_WRAPPED(re), RX_WRAPLEN(re), (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP); #endif - XPUSHs(pattern); + PUSHs(pattern); XSRETURN(1); } } else { @@ -1344,7 +1339,7 @@ struct xsub_details { const char *proto; }; -struct xsub_details details[] = { +const struct xsub_details details[] = { {"UNIVERSAL::isa", XS_UNIVERSAL_isa, NULL}, {"UNIVERSAL::can", XS_UNIVERSAL_can, NULL}, {"UNIVERSAL::DOES", XS_UNIVERSAL_DOES, NULL}, @@ -1362,6 +1357,15 @@ struct xsub_details details[] = { {"version::vcmp", XS_version_vcmp, NULL}, {"version::(bool", XS_version_boolean, NULL}, {"version::boolean", XS_version_boolean, NULL}, + {"version::(+", XS_version_noop, NULL}, + {"version::(-", XS_version_noop, NULL}, + {"version::(*", XS_version_noop, NULL}, + {"version::(/", XS_version_noop, NULL}, + {"version::(+=", XS_version_noop, NULL}, + {"version::(-=", XS_version_noop, NULL}, + {"version::(*=", XS_version_noop, NULL}, + {"version::(/=", XS_version_noop, NULL}, + {"version::(abs", XS_version_noop, NULL}, {"version::(nomethod", XS_version_noop, NULL}, {"version::noop", XS_version_noop, NULL}, {"version::is_alpha", XS_version_is_alpha, NULL}, @@ -1380,9 +1384,6 @@ struct xsub_details details[] = { {"Internals::SvREFCNT", XS_Internals_SvREFCNT, "\\[$%@];$"}, {"Internals::hv_clear_placeholders", XS_Internals_hv_clear_placehold, "\\%"}, {"PerlIO::get_layers", XS_PerlIO_get_layers, "*;@"}, - {"Internals::hash_seed", XS_Internals_hash_seed, ""}, - {"Internals::rehash_seed", XS_Internals_rehash_seed, ""}, - {"Internals::HvREHASH", XS_Internals_HvREHASH, "\\%"}, {"re::is_regexp", XS_re_is_regexp, "$"}, {"re::regname", XS_re_regname, ";$$"}, {"re::regnames", XS_re_regnames, ";$"}, @@ -1395,7 +1396,7 @@ Perl_boot_core_UNIVERSAL(pTHX) { dVAR; static const char file[] = __FILE__; - struct xsub_details *xsub = details; + const struct xsub_details *xsub = details; const struct xsub_details *end = details + sizeof(details) / sizeof(details[0]); @@ -1403,9 +1404,6 @@ Perl_boot_core_UNIVERSAL(pTHX) newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0); } while (++xsub < end); - /* register the overloading (type 'A') magic */ - PL_amagic_generation++; - /* Providing a Regexp::DESTROY fixes #21347. See test in t/op/ref.t */ { CV * const cv = @@ -1420,8 +1418,8 @@ Perl_boot_core_UNIVERSAL(pTHX) * Local variables: * c-indentation-style: bsd * c-basic-offset: 4 - * indent-tabs-mode: t + * indent-tabs-mode: nil * End: * - * ex: set ts=8 sts=4 sw=4 noet: + * ex: set ts=8 sts=4 sw=4 et: */