X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=universal.c;h=d333d2342c1150fd36aa57086e72bd0a090bac8b;hb=1bc4b319ba6d50bfdf5332d4378c85af1205184b;hp=008b5933406b1facb0b1668eb9f972a794a66a85;hpb=8565890c866fc4b9562f5d1ac6f565c47d3a90df;p=p5sagit%2Fp5-mst-13.2.git diff --git a/universal.c b/universal.c index 008b593..d333d23 100644 --- a/universal.c +++ b/universal.c @@ -1,7 +1,7 @@ /* universal.c * * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005, 2006, 2007 by Larry Wall and others + * 2005, 2006, 2007, 2008 by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. @@ -9,9 +9,11 @@ */ /* - * "The roots of those mountains must be roots indeed; there must be - * great secrets buried there which have not been discovered since the - * beginning." --Gandalf, relating Gollum's story + * '"The roots of those mountains must be roots indeed; there must be + * great secrets buried there which have not been discovered since the + * beginning."' --Gandalf, relating Gollum's history + * + * [p.54 of _The Lord of the Rings_, I/ii: "The Shadow of the Past"] */ /* This file contains the code that implements the functions in Perl's @@ -31,50 +33,76 @@ #include "perliol.h" /* For the PERLIO_F_XXX */ #endif +static HV * +S_get_isa_hash(pTHX_ HV *const stash) +{ + dVAR; + struct mro_meta *const meta = HvMROMETA(stash); + + PERL_ARGS_ASSERT_GET_ISA_HASH; + + if (!meta->isa) { + AV *const isa = mro_get_linear_isa(stash); + if (!meta->isa) { + HV *const isa_hash = newHV(); + /* Linearisation didn't build it for us, so do it here. */ + SV *const *svp = AvARRAY(isa); + SV *const *const svp_end = svp + AvFILLp(isa) + 1; + const HEK *const canon_name = HvNAME_HEK(stash); + + while (svp < svp_end) { + (void) hv_store_ent(isa_hash, *svp++, &PL_sv_undef, 0); + } + + (void) hv_common(isa_hash, NULL, HEK_KEY(canon_name), + HEK_LEN(canon_name), HEK_FLAGS(canon_name), + HV_FETCH_ISSTORE, &PL_sv_undef, + HEK_HASH(canon_name)); + (void) hv_store(isa_hash, "UNIVERSAL", 9, &PL_sv_undef, 0); + + SvREADONLY_on(isa_hash); + + meta->isa = isa_hash; + } + } + return meta->isa; +} + /* * Contributed by Graham Barr * The main guts of traverse_isa was actually copied from gv_fetchmeth */ STATIC bool -S_isa_lookup(pTHX_ HV *stash, const char * const name, const HV* const name_stash) +S_isa_lookup(pTHX_ HV *stash, const char * const name) { dVAR; - AV* stash_linear_isa; - SV** svp; - const char *hvname; - I32 items; + const struct mro_meta *const meta = HvMROMETA(stash); + HV *const isa = meta->isa ? meta->isa : S_get_isa_hash(aTHX_ stash); + STRLEN len = strlen(name); + const HV *our_stash; PERL_ARGS_ASSERT_ISA_LOOKUP; - /* A stash/class can go by many names (ie. User == main::User), so - we compare the stash itself just in case */ - if (name_stash && ((const HV *)stash == name_stash)) - return TRUE; - - hvname = HvNAME_get(stash); - - if (strEQ(hvname, name)) + if (hv_common(isa, NULL, name, len, 0 /* No "UTF-8" flag possible with only + a char * argument*/, + HV_FETCH_ISEXISTS, NULL, 0)) { + /* Direct name lookup worked. */ return TRUE; + } - if (strEQ(name, "UNIVERSAL")) - return TRUE; + /* A stash/class can go by many names (ie. User == main::User), so + we use the name in the stash itself, which is canonical. */ + our_stash = gv_stashpvn(name, len, 0); - stash_linear_isa = mro_get_linear_isa(stash); - svp = AvARRAY(stash_linear_isa) + 1; - items = AvFILLp(stash_linear_isa); - while (items--) { - SV* const basename_sv = *svp++; - HV* const basestash = gv_stashsv(basename_sv, 0); - if (!basestash) { - if (ckWARN(WARN_SYNTAX)) - Perl_warner(aTHX_ packWARN(WARN_SYNTAX), - "Can't locate package %"SVf" for the parents of %s", - SVfARG(basename_sv), hvname); - continue; - } - if(name_stash == basestash || strEQ(name, SvPVX(basename_sv))) + if (our_stash) { + HEK *const canon_name = HvNAME_HEK(our_stash); + + if (hv_common(isa, NULL, HEK_KEY(canon_name), HEK_LEN(canon_name), + HEK_FLAGS(canon_name), + HV_FETCH_ISEXISTS, NULL, HEK_HASH(canon_name))) { return TRUE; + } } return FALSE; @@ -114,13 +142,7 @@ Perl_sv_derived_from(pTHX_ SV *sv, const char *const name) stash = gv_stashsv(sv, 0); } - if (stash) { - HV * const name_stash = gv_stashpv(name, 0); - return isa_lookup(stash, name, name_stash); - } - else - return FALSE; - + return stash ? isa_lookup(stash, name) : FALSE; } /* @@ -329,7 +351,7 @@ Perl_croak_xs_usage(pTHX_ const CV *const cv, const char *const params) Perl_croak(aTHX_ "Usage: %s(%s)", gvname, params); } else { /* Pants. I don't think that it should be possible to get here. */ - Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", (UV)cv, params); + Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params); } } @@ -381,7 +403,7 @@ XS(XS_UNIVERSAL_can) rv = &PL_sv_undef; if (SvROK(sv)) { - sv = (SV*)SvRV(sv); + sv = MUTABLE_SV(SvRV(sv)); if (SvOBJECT(sv)) pkg = SvSTASH(sv); } @@ -392,7 +414,7 @@ XS(XS_UNIVERSAL_can) if (pkg) { GV * const gv = gv_fetchmethod_autoload(pkg, name, FALSE); if (gv && isGV(gv)) - rv = sv_2mortal(newRV((SV*)GvCV(gv))); + rv = sv_2mortal(newRV(MUTABLE_SV(GvCV(gv)))); } ST(0) = rv; @@ -431,7 +453,7 @@ XS(XS_UNIVERSAL_VERSION) PERL_UNUSED_ARG(cv); if (SvROK(ST(0))) { - sv = (SV*)SvRV(ST(0)); + sv = MUTABLE_SV(SvRV(ST(0))); if (!SvOBJECT(sv)) Perl_croak(aTHX_ "Cannot find version of an unblessed reference"); pkg = SvSTASH(sv); @@ -451,7 +473,7 @@ XS(XS_UNIVERSAL_VERSION) undef = NULL; } else { - sv = (SV*)&PL_sv_undef; + sv = &PL_sv_undef; undef = "(undef)"; } @@ -477,7 +499,7 @@ XS(XS_UNIVERSAL_VERSION) } if ( vcmp( req, sv ) > 0 ) { - if ( hv_exists((HV*)SvRV(req), "qv", 2 ) ) { + if ( hv_exists(MUTABLE_HV(SvRV(req)), "qv", 2 ) ) { Perl_croak(aTHX_ "%s version %"SVf" required--" "this is only version %"SVf"", HvNAME_get(pkg), SVfARG(vnormal(req)), @@ -519,7 +541,7 @@ XS(XS_version_new) if ( items == 1 || vs == &PL_sv_undef ) { /* no param or explicit undef */ /* create empty object */ vs = sv_newmortal(); - sv_setpvn(vs,"",0); + sv_setpvs(vs,""); } else if ( items == 3 ) { vs = sv_newmortal(); @@ -692,7 +714,7 @@ XS(XS_version_is_alpha) SP -= items; if (sv_derived_from(ST(0), "version")) { SV * const lobj = ST(0); - if ( hv_exists((HV*)SvRV(lobj), "alpha", 5 ) ) + if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "alpha", 5 ) ) XSRETURN_YES; else XSRETURN_NO; @@ -899,7 +921,7 @@ XS(XS_Internals_hv_clear_placehold) if (items != 1) croak_xs_usage(cv, "hv"); else { - HV * const hv = (HV *) SvRV(ST(0)); + HV * const hv = MUTABLE_HV(SvRV(ST(0))); hv_clear_placeholders(hv); XSRETURN(0); } @@ -964,11 +986,11 @@ XS(XS_PerlIO_get_layers) } sv = POPs; - gv = (GV*)sv; + gv = MUTABLE_GV(sv); if (!isGV(sv)) { if (SvROK(sv) && isGV(SvRV(sv))) - gv = (GV*)SvRV(sv); + gv = MUTABLE_GV(SvRV(sv)); else if (SvPOKp(sv)) gv = gv_fetchsv(sv, 0, SVt_PVIO); } @@ -1065,8 +1087,9 @@ XS(XS_Internals_HvREHASH) /* Subject to change */ { dVAR; dXSARGS; + PERL_UNUSED_ARG(cv); if (SvROK(ST(0))) { - const HV * const hv = (HV *) SvRV(ST(0)); + const HV * const hv = (const HV *) SvRV(ST(0)); if (items == 1 && SvTYPE(hv) == SVt_PVHV) { if (HvREHASH(hv)) XSRETURN_YES; @@ -1115,7 +1138,7 @@ XS(XS_re_regnames_count) SPAGAIN; if (ret) { - XPUSHs(ret); + mXPUSHs(ret); PUTBACK; return; } else { @@ -1149,10 +1172,7 @@ XS(XS_re_regname) ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(0), (flags | RXapif_REGNAME)); if (ret) { - if (SvROK(ret)) - XPUSHs(ret); - else - XPUSHs(SvREFCNT_inc(ret)); + mXPUSHs(ret); XSRETURN(1); } XSRETURN_UNDEF; @@ -1196,7 +1216,7 @@ XS(XS_re_regnames) if (!ret) XSRETURN_UNDEF; - av = (AV*)SvRV(ret); + av = MUTABLE_AV(SvRV(ret)); length = av_len(av); for (i = 0; i <= length; i++) { @@ -1205,8 +1225,11 @@ XS(XS_re_regnames) if (!entry) Perl_croak(aTHX_ "NULL array element in re::regnames()"); - XPUSHs(*entry); + mXPUSHs(SvREFCNT_inc_simple_NN(*entry)); } + + SvREFCNT_dec(ret); + PUTBACK; return; } @@ -1270,7 +1293,7 @@ XS(XS_re_regexp_pattern) /* Scalar, so use the string that Perl would return */ /* return the pattern in (?msix:..) format */ #if PERL_VERSION >= 11 - pattern = sv_2mortal(newSVsv((SV*)re)); + pattern = sv_2mortal(newSVsv(MUTABLE_SV(re))); #else pattern = newSVpvn_flags(RX_WRAPPED(re), RX_WRAPLEN(re), (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP); @@ -1319,16 +1342,13 @@ XS(XS_Tie_Hash_NamedCapture_FETCH) SP -= items; - flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0)))); + flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0))))); ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(1), flags); SPAGAIN; if (ret) { - if (SvROK(ret)) - XPUSHs(ret); - else - XPUSHs(SvREFCNT_inc(ret)); + mXPUSHs(ret); PUTBACK; return; } @@ -1349,14 +1369,14 @@ XS(XS_Tie_Hash_NamedCapture_STORE) if (!rx) { if (!PL_localizing) - Perl_croak(aTHX_ PL_no_modify); + Perl_croak(aTHX_ "%s", PL_no_modify); else XSRETURN_UNDEF; } SP -= items; - flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0)))); + flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0))))); CALLREG_NAMED_BUFF_STORE(rx,ST(1), ST(2), flags); } @@ -1371,11 +1391,11 @@ XS(XS_Tie_Hash_NamedCapture_DELETE) croak_xs_usage(cv, "$key, $flags"); if (!rx) - Perl_croak(aTHX_ PL_no_modify); + Perl_croak(aTHX_ "%s", PL_no_modify); SP -= items; - flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0)))); + flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0))))); CALLREG_NAMED_BUFF_DELETE(rx, ST(1), flags); } @@ -1392,11 +1412,11 @@ XS(XS_Tie_Hash_NamedCapture_CLEAR) rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL; if (!rx) - Perl_croak(aTHX_ PL_no_modify); + Perl_croak(aTHX_ "%s", PL_no_modify); SP -= items; - flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0)))); + flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0))))); CALLREG_NAMED_BUFF_CLEAR(rx, flags); } @@ -1418,7 +1438,7 @@ XS(XS_Tie_Hash_NamedCapture_EXISTS) SP -= items; - flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0)))); + flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0))))); ret = CALLREG_NAMED_BUFF_EXISTS(rx, ST(1), flags); SPAGAIN; @@ -1446,13 +1466,13 @@ XS(XS_Tie_Hash_NamedCapture_FIRSTK) SP -= items; - flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0)))); + flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0))))); ret = CALLREG_NAMED_BUFF_FIRSTKEY(rx, flags); SPAGAIN; if (ret) { - XPUSHs(SvREFCNT_inc(ret)); + mXPUSHs(ret); PUTBACK; } else { XSRETURN_UNDEF; @@ -1478,13 +1498,13 @@ XS(XS_Tie_Hash_NamedCapture_NEXTK) SP -= items; - flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0)))); + flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0))))); ret = CALLREG_NAMED_BUFF_NEXTKEY(rx, ST(1), flags); SPAGAIN; if (ret) { - XPUSHs(ret); + mXPUSHs(ret); } else { XSRETURN_UNDEF; } @@ -1509,13 +1529,13 @@ XS(XS_Tie_Hash_NamedCapture_SCALAR) SP -= items; - flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0)))); + flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0))))); ret = CALLREG_NAMED_BUFF_SCALAR(rx, flags); SPAGAIN; if (ret) { - XPUSHs(ret); + mXPUSHs(ret); PUTBACK; return; } else {