This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Use PADNAME rather than SV in the source
[perl5.git] / op.c
diff --git a/op.c b/op.c
index 104d30f..324991c 100644 (file)
--- a/op.c
+++ b/op.c
@@ -854,6 +854,7 @@ Perl_op_clear(pTHX_ OP *o)
        }
        break;
     case OP_METHOD_NAMED:
+    case OP_METHOD_SUPER:
         SvREFCNT_dec(cMETHOPx(o)->op_u.op_meth_sv);
         cMETHOPx(o)->op_u.op_meth_sv = NULL;
 #ifdef USE_ITHREADS
@@ -2098,9 +2099,13 @@ S_scalarseq(pTHX_ OP *o)
        if (type == OP_LINESEQ || type == OP_SCOPE ||
            type == OP_LEAVE || type == OP_LEAVETRY)
        {
-            OP *kid;
-           for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid)) {
-               if (OP_HAS_SIBLING(kid)) {
+           OP *kid, *sib;
+           for (kid = cLISTOPo->op_first; kid; kid = sib) {
+               if ((sib = OP_SIBLING(kid))
+                && (  OP_HAS_SIBLING(sib) || sib->op_type != OP_NULL
+                   || (  sib->op_targ != OP_NEXTSTATE
+                      && sib->op_targ != OP_DBSTATE  )))
+               {
                    scalarvoid(kid);
                }
            }
@@ -2229,6 +2234,7 @@ S_finalize_op(pTHX_ OP* o)
 #ifdef USE_ITHREADS
     /* Relocate all the METHOP's SVs to the pad for thread safety. */
     case OP_METHOD_NAMED:
+    case OP_METHOD_SUPER:
         op_relocate_sv(&cMETHOPx(o)->op_u.op_meth_sv, &o->op_targ);
         break;
 #endif
@@ -2941,6 +2947,10 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
            break;
        }
        goto nomod;
+
+    case OP_SCALAR:
+       op_lvalue(cUNOPo->op_first, OP_ENTERSUB);
+       goto nomod;
     }
 
     /* [20011101.069] File test operators interpret OPf_REF to mean that
@@ -5491,6 +5501,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
             */
 
            SvREFCNT_inc_simple_void(PL_compcv);
+           CvLVALUE_on(PL_compcv);
            /* these lines are just an unrolled newANONATTRSUB */
            expr = newSVOP(OP_ANONCODE, 0,
                    MUTABLE_SV(newATTRSUB(floor, 0, NULL, NULL, expr)));
@@ -7244,11 +7255,10 @@ Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont)
        else
            Perl_croak(aTHX_ "Can't use %s for loop variable", PL_op_desc[sv->op_type]);
        if (padoff) {
-           SV *const namesv = PAD_COMPNAME_SV(padoff);
-           STRLEN len;
-           const char *const name = SvPV_const(namesv, len);
+           PADNAME * const pn = PAD_COMPNAME(padoff);
+           const char * const name = PadnamePV(pn);
 
-           if (len == 2 && name[0] == '$' && name[1] == '_')
+           if (PadnameLEN(pn) == 2 && name[0] == '$' && name[1] == '_')
                iterpflags |= OPpITER_DEF;
        }
     }
@@ -7321,7 +7331,12 @@ Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont)
        loop = tmp;
     }
     else if (!loop->op_slabbed)
+    {
        loop = (LOOP*)PerlMemShared_realloc(loop, sizeof(LOOP));
+#ifdef PERL_OP_PARENT
+       loop->op_last->op_sibling = (OP *)loop;
+#endif
+    }
     loop->op_targ = padoff;
     wop = newWHILEOP(flags, 1, loop, newOP(OP_ITER, 0), block, cont, 0);
     return wop;
@@ -7908,8 +7923,8 @@ Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        cv = *spot;
     else {
        MAGIC *mg;
-       SvUPGRADE(name, SVt_PVMG);
-       mg = mg_find(name, PERL_MAGIC_proto);
+       SvUPGRADE((SV *)name, SVt_PVMG);
+       mg = mg_find((SV *)name, PERL_MAGIC_proto);
        assert (SvTYPE(*spot) == SVt_PVCV);
        if (CvNAMED(*spot))
            hek = CvNAME_HEK(*spot);
@@ -7920,7 +7935,8 @@ Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            CvNAME_HEK_set(*spot, hek =
                share_hek(
                    PadnamePV(name)+1,
-                   PadnameLEN(name)-1 * (PadnameUTF8(name) ? -1 : 1), hash
+                   (PadnameLEN(name)-1) * (PadnameUTF8(name) ? -1 : 1),
+                   hash
                )
            );
            CvLEXICAL_on(*spot);
@@ -7930,8 +7946,8 @@ Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            cv = (CV *)mg->mg_obj;
        }
        else {
-           sv_magic(name, &PL_sv_undef, PERL_MAGIC_proto, NULL, 0);
-           mg = mg_find(name, PERL_MAGIC_proto);
+           sv_magic((SV *)name, &PL_sv_undef, PERL_MAGIC_proto, NULL, 0);
+           mg = mg_find((SV *)name, PERL_MAGIC_proto);
        }
        spot = (CV **)(svspot = &mg->mg_obj);
     }
@@ -8077,7 +8093,7 @@ Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            U32 hash;
            PERL_HASH(hash, PadnamePV(name)+1, PadnameLEN(name)-1);
            hek = share_hek(PadnamePV(name)+1,
-                     PadnameLEN(name)-1 * (PadnameUTF8(name) ? -1 : 1),
+                     (PadnameLEN(name)-1) * (PadnameUTF8(name) ? -1 : 1),
                      hash);
        }
        CvNAME_HEK_set(cv, hek);
@@ -9357,10 +9373,11 @@ Perl_ck_spair(pTHX_ OP *o)
            const OPCODE type = newop->op_type;
            if (OP_HAS_SIBLING(newop))
                return o;
-           if (o->op_type == OP_REFGEN && !(newop->op_flags & OPf_PARENS)
-               && (type == OP_RV2AV || type == OP_PADAV
-                || type == OP_RV2HV || type == OP_PADHV
-                || type == OP_RV2CV))
+           if (o->op_type == OP_REFGEN
+            && (  type == OP_RV2CV
+               || (  !(newop->op_flags & OPf_PARENS)
+                  && (  type == OP_RV2AV || type == OP_PADAV
+                     || type == OP_RV2HV || type == OP_PADHV))))
                NOOP; /* OK (allow srefgen for \@a and \%h) */
            else if (!(PL_opargs[type] & OA_RETSCALAR))
                return o;
@@ -9614,7 +9631,7 @@ Perl_ck_rvconst(pTHX_ OP *o)
            SvREFCNT_dec(kid->op_sv);
 #ifdef USE_ITHREADS
            /* XXX hack: dependence on sizeof(PADOP) <= sizeof(SVOP) */
-           assert (sizeof(PADOP) <= sizeof(SVOP));
+           STATIC_ASSERT_STMT(sizeof(PADOP) <= sizeof(SVOP));
            kPADOP->op_padix = pad_alloc(OP_GV, SVf_READONLY);
            SvREFCNT_dec(PAD_SVl(kPADOP->op_padix));
            PAD_SETSV(kPADOP->op_padix, MUTABLE_SV(SvREFCNT_inc_simple_NN(gv)));
@@ -9815,10 +9832,11 @@ Perl_ck_fun(pTHX_ OP *o)
                             */
                            priv = OPpDEREF;
                            if (kid->op_type == OP_PADSV) {
-                               SV *const namesv
+                               PADNAME * const pn
                                    = PAD_COMPNAME_SV(kid->op_targ);
-                               name = SvPV_const(namesv, len);
-                                name_utf8 = SvUTF8(namesv);
+                               name = PadnamePV (pn);
+                               len  = PadnameLEN(pn);
+                               name_utf8 = PadnameUTF8(pn);
                            }
                            else if (kid->op_type == OP_RV2SV
                                     && kUNOP->op_first->op_type == OP_GV)
@@ -10289,27 +10307,45 @@ Perl_ck_match(pTHX_ OP *o)
 OP *
 Perl_ck_method(pTHX_ OP *o)
 {
-    SVsv;
+    SV *sv, *methsv;
     const char* method;
+    char* compatptr;
+    int utf8;
+    STRLEN len, nsplit = 0, i;
     OP * const kid = cUNOPo->op_first;
 
     PERL_ARGS_ASSERT_CK_METHOD;
     if (kid->op_type != OP_CONST) return o;
 
     sv = kSVOP->op_sv;
+
+    /* replace ' with :: */
+    while ((compatptr = strchr(SvPVX(sv), '\''))) {
+        *compatptr = ':';
+        sv_insert(sv, compatptr - SvPVX_const(sv), 0, ":", 1);
+    }
+
     method = SvPVX_const(sv);
-    if (!(strchr(method, ':') || strchr(method, '\''))) {
-        OP *cmop;
-        if (!SvIsCOW_shared_hash(sv)) {
-            sv = newSVpvn_share(method, SvUTF8(sv) ? -(I32)SvCUR(sv) : (I32)SvCUR(sv), 0);
-        }
-        else {
-            kSVOP->op_sv = NULL;
-        }
-        cmop = newMETHOP_named(OP_METHOD_NAMED, 0, sv);
+    len = SvCUR(sv);
+    utf8 = SvUTF8(sv) ? -1 : 1;
+
+    for (i = len - 1; i > 0; --i) if (method[i] == ':') {
+        nsplit = i+1;
+        break;
+    }
+
+    methsv = newSVpvn_share(method+nsplit, utf8*(len - nsplit), 0);
+
+    if (!nsplit) { /* $proto->method() */
+        op_free(o);
+        return newMETHOP_named(OP_METHOD_NAMED, 0, methsv);
+    }
+
+    if (nsplit == 7 && memEQ(method, "SUPER::", nsplit)) { /* $proto->SUPER::method() */
         op_free(o);
-        return cmop;
+        return newMETHOP_named(OP_METHOD_SUPER, 0, methsv);
     }
+
     return o;
 }
 
@@ -10743,14 +10779,17 @@ S_simplify_sort(pTHX_ OP *o)
        kid = kBINOP->op_first;
        do {
            if (kid->op_type == OP_PADSV) {
-               SV * const name = PAD_COMPNAME_SV(kid->op_targ);
-               if (SvCUR(name) == 2 && *SvPVX(name) == '$'
-                && (SvPVX(name)[1] == 'a' || SvPVX(name)[1] == 'b'))
+               PADNAME * const name = PAD_COMPNAME(kid->op_targ);
+               if (PadnameLEN(name) == 2 && *PadnamePV(name) == '$'
+                && (  PadnamePV(name)[1] == 'a'
+                   || PadnamePV(name)[1] == 'b'  ))
                    /* diag_listed_as: "my %s" used in sort comparison */
                    Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                                     "\"%s %s\" used in sort comparison",
-                                     SvPAD_STATE(name) ? "state" : "my",
-                                     SvPVX(name));
+                                     PadnameIsSTATE(name)
+                                       ? "state"
+                                       : "my",
+                                     PadnamePV(name));
            }
        } while ((kid = OP_SIBLING(kid)));
        return;
@@ -10964,7 +11003,7 @@ Perl_find_lexical_cv(pTHX_ PADOFFSET off)
     }
     assert(!PadnameIsOUR(name));
     if (!PadnameIsSTATE(name) && SvMAGICAL(name)) {
-       MAGIC * mg = mg_find(name, PERL_MAGIC_proto);
+       MAGIC * mg = mg_find((SV *)name, PERL_MAGIC_proto);
        assert(mg);
        assert(mg->mg_obj);
        return (CV *)mg->mg_obj;
@@ -11228,10 +11267,11 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
                            bad_type_gv(arg, "symbol", namegv, 0, o3);
                        break;
                    case '&':
-                       if (o3->op_type == OP_ENTERSUB)
+                       if (o3->op_type == OP_ENTERSUB
+                        && !(o3->op_flags & OPf_STACKED))
                            goto wrapref;
                        if (!contextclass)
-                           bad_type_gv(arg, "subroutine entry", namegv, 0,
+                           bad_type_gv(arg, "subroutine", namegv, 0,
                                    o3);
                        break;
                    case '$':
@@ -11253,14 +11293,20 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
                    case '@':
                        if (o3->op_type == OP_RV2AV ||
                                o3->op_type == OP_PADAV)
+                       {
+                           o3->op_flags &=~ OPf_PARENS;
                            goto wrapref;
+                       }
                        if (!contextclass)
                            bad_type_gv(arg, "array", namegv, 0, o3);
                        break;
                    case '%':
                        if (o3->op_type == OP_RV2HV ||
                                o3->op_type == OP_PADHV)
+                       {
+                           o3->op_flags &=~ OPf_PARENS;
                            goto wrapref;
+                       }
                        if (!contextclass)
                            bad_type_gv(arg, "hash", namegv, 0, o3);
                        break;
@@ -11436,7 +11482,7 @@ Perl_ck_entersub_args_core(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
            return op_convert_list(opnum,0,aop);
        }
     }
-    assert(0);
+    NOT_REACHED;
     return entersubop;
 }
 
@@ -11576,6 +11622,7 @@ Perl_ck_subr(pTHX_ OP *o)
     OP *aop, *cvop;
     CV *cv;
     GV *namegv;
+    SV **const_class = NULL;
 
     PERL_ARGS_ASSERT_CK_SUBR;
 
@@ -11592,17 +11639,39 @@ Perl_ck_subr(pTHX_ OP *o)
     o->op_private |= (PL_hints & HINT_STRICT_REFS);
     if (PERLDB_SUB && PL_curstash != PL_debstash)
        o->op_private |= OPpENTERSUB_DB;
-    if (cvop->op_type == OP_RV2CV) {
-       o->op_private |= (cvop->op_private & OPpENTERSUB_AMPER);
-       op_null(cvop);
-    } else if (cvop->op_type == OP_METHOD || cvop->op_type == OP_METHOD_NAMED) {
-       if (aop->op_type == OP_CONST)
-           aop->op_private &= ~OPpCONST_STRICT;
-       else if (aop->op_type == OP_LIST) {
-           OP * const sib = OP_SIBLING(((UNOP*)aop)->op_first);
-           if (sib && sib->op_type == OP_CONST)
-               sib->op_private &= ~OPpCONST_STRICT;
-       }
+    switch (cvop->op_type) {
+       case OP_RV2CV:
+           o->op_private |= (cvop->op_private & OPpENTERSUB_AMPER);
+           op_null(cvop);
+           break;
+       case OP_METHOD:
+       case OP_METHOD_NAMED:
+       case OP_METHOD_SUPER:
+           if (aop->op_type == OP_CONST) {
+               aop->op_private &= ~OPpCONST_STRICT;
+               const_class = &cSVOPx(aop)->op_sv;
+           }
+           else if (aop->op_type == OP_LIST) {
+               OP * const sib = OP_SIBLING(((UNOP*)aop)->op_first);
+               if (sib && sib->op_type == OP_CONST) {
+                   sib->op_private &= ~OPpCONST_STRICT;
+                   const_class = &cSVOPx(sib)->op_sv;
+               }
+           }
+           /* make class name a shared cow string to speedup method calls */
+           /* constant string might be replaced with object, f.e. bigint */
+           if (const_class && !SvROK(*const_class)) {
+               STRLEN len;
+               const char* str = SvPV(*const_class, len);
+               if (len) {
+                   SV* const shared = newSVpvn_share(
+                       str, SvUTF8(*const_class) ? -len : len, 0
+                   );
+                   SvREFCNT_dec(*const_class);
+                   *const_class = shared;
+               }
+           }
+           break;
     }
 
     if (!cv) {