X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=op.c;h=9b33ff2f2cb63462365f6d44acad34b515e1a49b;hb=63315e187a785a8535d1f84110e060293f0f744c;hp=0c688da6559434b5f64127a7bdc385ffe2b3e96b;hpb=b5a930ec3bf87d0d126b3ddd1f5cc0587aae7f49;p=p5sagit%2Fp5-mst-13.2.git diff --git a/op.c b/op.c index 0c688da..9b33ff2 100644 --- a/op.c +++ b/op.c @@ -1,7 +1,7 @@ /* op.c * * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - * 2000, 2001, 2002, 2003, by Larry Wall and others + * 2000, 2001, 2002, 2003, 2004, 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. @@ -16,6 +16,30 @@ * either way, as the saying is, if you follow me." --the Gaffer */ +/* This file contains the functions that create, manipulate and optimize + * the OP structures that hold a compiled perl program. + * + * A Perl program is compiled into a tree of OPs. Each op contains + * structural pointers (eg to its siblings and the next op in the + * execution sequence), a pointer to the function that would execute the + * op, plus any data specific to that op. For example, an OP_CONST op + * points to the pp_const() function and to an SV containing the constant + * value. When pp_const() is executed, its job is to push that SV onto the + * stack. + * + * OPs are mainly created by the newFOO() functions, which are mainly + * called from the parser (in perly.y) as the code is parsed. For example + * the Perl code $a + $b * $c would cause the equivalent of the following + * to be called (oversimplifying a bit): + * + * newBINOP(OP_ADD, flags, + * newSVREF($a), + * newBINOP(OP_MULTIPLY, flags, newSVREF($b), newSVREF($c)) + * ) + * + * Note that during the build of miniperl, a temporary copy of this file + * is made, called opmini.c. + */ #include "EXTERN.h" #define PERL_IN_OP_C @@ -661,6 +685,15 @@ Perl_scalarvoid(pTHX_ OP *o) useless = OP_DESC(o); break; + case OP_NOT: + kid = cUNOPo->op_first; + if (kid->op_type != OP_MATCH && kid->op_type != OP_SUBST && + kid->op_type != OP_TRANS) { + goto func_ops; + } + useless = "negative pattern binding (!~)"; + break; + case OP_RV2GV: case OP_RV2SV: case OP_RV2AV: @@ -1728,7 +1761,7 @@ Perl_bind_match(pTHX_ I32 type, OP *left, OP *right) } else return bind_match(type, left, - pmruntime(newPMOP(OP_MATCH, 0), right, Nullop)); + pmruntime(newPMOP(OP_MATCH, 0), right, 0)); } OP * @@ -1763,13 +1796,11 @@ Perl_scope(pTHX_ OP *o) return o; } +/* XXX kept for BINCOMPAT only */ void Perl_save_hints(pTHX) { - SAVEI32(PL_hints); - SAVESPTR(GvHV(PL_hintgv)); - GvHV(PL_hintgv) = newHVhv(GvHV(PL_hintgv)); - SAVEFREESV(GvHV(PL_hintgv)); + Perl_croak(aTHX_ "internal error: obsolete function save_hints() called"); } int @@ -2629,15 +2660,56 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags) return CHECKOP(type, pmop); } +/* Given some sort of match op o, and an expression expr containing a + * pattern, either compile expr into a regex and attach it to o (if it's + * constant), or convert expr into a runtime regcomp op sequence (if it's + * not) + * + * isreg indicates that the pattern is part of a regex construct, eg + * $x =~ /pattern/ or split /pattern/, as opposed to $x =~ $pattern or + * split "pattern", which aren't. In the former case, expr will be a list + * if the pattern contains more than one term (eg /a$b/) or if it contains + * a replacement, ie s/// or tr///. + */ + OP * -Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl) +Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg) { PMOP *pm; LOGOP *rcop; I32 repl_has_vars = 0; + OP* repl = Nullop; + bool reglist; + + if (o->op_type == OP_SUBST || o->op_type == OP_TRANS) { + /* last element in list is the replacement; pop it */ + OP* kid; + repl = cLISTOPx(expr)->op_last; + kid = cLISTOPx(expr)->op_first; + while (kid->op_sibling != repl) + kid = kid->op_sibling; + kid->op_sibling = Nullop; + cLISTOPx(expr)->op_last = kid; + } - if (o->op_type == OP_TRANS) + if (isreg && expr->op_type == OP_LIST && + cLISTOPx(expr)->op_first->op_sibling == cLISTOPx(expr)->op_last) + { + /* convert single element list to element */ + OP* oe = expr; + expr = cLISTOPx(oe)->op_first->op_sibling; + cLISTOPx(oe)->op_first->op_sibling = Nullop; + cLISTOPx(oe)->op_last = Nullop; + op_free(oe); + } + + if (o->op_type == OP_TRANS) { return pmtrans(o, expr, repl); + } + + reglist = isreg && expr->op_type == OP_LIST; + if (reglist) + op_null(expr); PL_hints |= HINT_BLOCK_SCOPE; pm = (PMOP*)o; @@ -2668,11 +2740,14 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl) rcop->op_type = OP_REGCOMP; rcop->op_ppaddr = PL_ppaddr[OP_REGCOMP]; rcop->op_first = scalar(expr); - rcop->op_flags |= ((PL_hints & HINT_RE_EVAL) - ? (OPf_SPECIAL | OPf_KIDS) - : OPf_KIDS); + rcop->op_flags |= OPf_KIDS + | ((PL_hints & HINT_RE_EVAL) ? OPf_SPECIAL : 0) + | (reglist ? OPf_STACKED : 0); rcop->op_private = 1; rcop->op_other = o; + if (reglist) + rcop->op_targ = pad_alloc(rcop->op_type, SVs_PADTMP); + /* /$x/ may cause an eval, since $x might be qr/(?{..})/ */ PL_cv_has_eval = 1; @@ -3126,6 +3201,15 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right) op_free(right); return Nullop; } + /* optimise C to C, and likewise for hashes */ + if ((left->op_type == OP_PADAV || left->op_type == OP_PADHV) + && right->op_type == OP_STUB + && (left->op_private & OPpLVAL_INTRO)) + { + op_free(right); + left->op_flags &= ~(OPf_REF|OPf_SPECIAL); + return left; + } curop = list(force_list(left)); o = newBINOP(OP_AASSIGN, flags, list(force_list(right)), curop); o->op_private = (U8)(0 | (flags >> 8)); @@ -3320,9 +3404,7 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o) } } - o = prepend_elem(OP_LINESEQ, (OP*)cop, o); - CHECKOP(cop->op_type, cop); - return o; + return prepend_elem(OP_LINESEQ, (OP*)cop, o); } @@ -3364,16 +3446,37 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp) no_bareword_allowed(first); else if (ckWARN(WARN_BAREWORD) && (first->op_private & OPpCONST_BARE)) Perl_warner(aTHX_ packWARN(WARN_BAREWORD), "Bareword found in conditional"); - if ((type == OP_AND) == (SvTRUE(((SVOP*)first)->op_sv))) { + if ((type == OP_AND && SvTRUE(((SVOP*)first)->op_sv)) || + (type == OP_OR && !SvTRUE(((SVOP*)first)->op_sv)) || + (type == OP_DOR && !SvOK(((SVOP*)first)->op_sv))) { op_free(first); *firstp = Nullop; - other->op_private |= OPpCONST_SHORTCIRCUIT; + if (other->op_type == OP_CONST) + other->op_private |= OPpCONST_SHORTCIRCUIT; return other; } else { + /* check for C, or C */ + OP *o2 = other; + if ( ! (o2->op_type == OP_LIST + && (( o2 = cUNOPx(o2)->op_first)) + && o2->op_type == OP_PUSHMARK + && (( o2 = o2->op_sibling)) ) + ) + o2 = other; + if ((o2->op_type == OP_PADSV || o2->op_type == OP_PADAV + || o2->op_type == OP_PADHV) + && o2->op_private & OPpLVAL_INTRO + && ckWARN(WARN_DEPRECATED)) + { + Perl_warner(aTHX_ packWARN(WARN_DEPRECATED), + "Deprecated use of my() in false conditional"); + } + op_free(other); *otherp = Nullop; - first->op_private |= OPpCONST_SHORTCIRCUIT; + if (first->op_type == OP_CONST) + first->op_private |= OPpCONST_SHORTCIRCUIT; return first; } } @@ -3896,6 +3999,8 @@ Perl_cv_ckproto(pTHX_ CV *cv, GV *gv, char *p) Perl_sv_catpvf(aTHX_ msg, " sub %"SVf, name); if (SvPOK(cv)) Perl_sv_catpvf(aTHX_ msg, " (%"SVf")", (SV *)cv); + else + Perl_sv_catpvf(aTHX_ msg, ": none"); sv_catpv(msg, " vs "); if (p) Perl_sv_catpvf(aTHX_ msg, "(%s)", p); @@ -4032,11 +4137,19 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block) char *name; char *aname; GV *gv; - char *ps = proto ? SvPVx(((SVOP*)proto)->op_sv, n_a) : Nullch; + char *ps; register CV *cv=0; SV *const_sv; name = o ? SvPVx(cSVOPo->op_sv, n_a) : Nullch; + + if (proto) { + assert(proto->op_type == OP_CONST); + ps = SvPVx(((SVOP*)proto)->op_sv, n_a); + } + else + ps = Nullch; + if (!name && PERLDB_NAMEANON && CopLINE(PL_curcop)) { SV *sv = sv_newmortal(); Perl_sv_setpvf(aTHX_ sv, "%s[%s:%"IVdf"]", @@ -5061,6 +5174,7 @@ Perl_ck_ftst(pTHX_ OP *o) gv_fetchpv(SvPVx(kid->op_sv, n_a), TRUE, SVt_PVIO)); op_free(o); o = newop; + return o; } else { if ((PL_hints & HINT_FILETEST_ACCESS) && @@ -5403,7 +5517,7 @@ Perl_ck_grep(pTHX_ OP *o) OP* k; o = ck_sort(o); kid = cLISTOPo->op_first->op_sibling; - for (k = cLISTOPo->op_first->op_sibling->op_next; k; k = k->op_next) { + for (k = cUNOPx(kid)->op_first; k; k = k->op_next) { kid = k; } kid->op_next = (OP*)gwop; @@ -5576,6 +5690,19 @@ Perl_ck_sassign(pTHX_ OP *o) return kid; } } + /* optimise C to C */ + if (kid->op_type == OP_UNDEF) { + OP *kkid = kid->op_sibling; + if (kkid && kkid->op_type == OP_PADSV + && (kkid->op_private & OPpLVAL_INTRO)) + { + cLISTOPo->op_first = NULL; + kid->op_sibling = NULL; + op_free(o); + op_free(kid); + return kkid; + } + } return o; } @@ -5854,7 +5981,7 @@ S_simplify_sort(pTHX_ OP *o) { register OP *kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */ OP *k; - int reversed; + int descending; GV *gv; if (!(o->op_flags & OPf_STACKED)) return; @@ -5883,11 +6010,12 @@ S_simplify_sort(pTHX_ OP *o) if (GvSTASH(gv) != PL_curstash) return; if (strEQ(GvNAME(gv), "a")) - reversed = 0; + descending = 0; else if (strEQ(GvNAME(gv), "b")) - reversed = 1; + descending = 1; else return; + kid = k; /* back to cmp */ if (kBINOP->op_last->op_type != OP_RV2SV) return; @@ -5897,13 +6025,13 @@ S_simplify_sort(pTHX_ OP *o) kid = kUNOP->op_first; /* get past rv2sv */ gv = kGVOP_gv; if (GvSTASH(gv) != PL_curstash - || ( reversed + || ( descending ? strNE(GvNAME(gv), "a") : strNE(GvNAME(gv), "b"))) return; o->op_flags &= ~(OPf_STACKED | OPf_SPECIAL); - if (reversed) - o->op_private |= OPpSORT_REVERSE; + if (descending) + o->op_private |= OPpSORT_DESCEND; if (k->op_type == OP_NCMP) o->op_private |= OPpSORT_NUMERIC; if (k->op_type == OP_I_NCMP) @@ -5935,7 +6063,7 @@ Perl_ck_split(pTHX_ OP *o) if (kid->op_type != OP_MATCH || kid->op_flags & OPf_STACKED) { OP *sibl = kid->op_sibling; kid->op_sibling = 0; - kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, Nullop); + kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, 0); if (cLISTOPo->op_first == cLISTOPo->op_last) cLISTOPo->op_last = kid; cLISTOPo->op_first = kid; @@ -5986,42 +6114,6 @@ Perl_ck_join(pTHX_ OP *o) } OP * -Perl_ck_state(pTHX_ OP *o) -{ - /* warn on C , C<$a && my $x=1;> style statements */ - OP *kid; - o = o->op_sibling; - if (!o || o->op_type != OP_NULL || !(o->op_flags & OPf_KIDS)) - return o; - kid = cUNOPo->op_first; - if (!(kid->op_type == OP_AND || kid->op_type == OP_OR)) - return o; - kid = kUNOP->op_first->op_sibling; - if (kid->op_type == OP_SASSIGN) - kid = kBINOP->op_first->op_sibling; - else if (kid->op_type == OP_AASSIGN) - kid = kBINOP->op_first->op_sibling; - - if (kid->op_type == OP_LIST - || (kid->op_type == OP_NULL && kid->op_targ == OP_LIST)) - { - kid = kUNOP->op_first; - if (kid->op_type == OP_PUSHMARK) - kid = kid->op_sibling; - } - if ((kid->op_type == OP_PADSV || kid->op_type == OP_PADAV - || kid->op_type == OP_PADHV) - && (kid->op_private & OPpLVAL_INTRO) - && (ckWARN(WARN_DEPRECATED))) - { - Perl_warner(aTHX_ packWARN(WARN_DEPRECATED), - "Deprecated use of my() in conditional"); - } - return o; -} - - -OP * Perl_ck_subr(pTHX_ OP *o) { OP *prev = ((cUNOPo->op_first->op_sibling) @@ -6424,7 +6516,7 @@ Perl_peep(pTHX_ register OP *o) o->op_next : o->op_next->op_next; IV i; if (pop && pop->op_type == OP_CONST && - (PL_op = pop->op_next) && + ((PL_op = pop->op_next)) && pop->op_next->op_type == OP_AELEM && !(pop->op_next->op_private & (OPpLVAL_INTRO|OPpLVAL_DEFER|OPpDEREF|OPpMAYBE_LVSUB)) && @@ -6433,6 +6525,8 @@ Perl_peep(pTHX_ register OP *o) i >= 0) { GV *gv; + if (cSVOPx(pop)->op_private & OPpCONST_STRICT) + no_bareword_allowed(pop); if (o->op_type == OP_GV) op_null(o->op_next); op_null(pop->op_next); @@ -6550,7 +6644,9 @@ Perl_peep(pTHX_ register OP *o) break; case OP_HELEM: { + UNOP *rop; SV *lexname; + GV **fields; SV **svp, *sv; char *key = NULL; STRLEN keylen; @@ -6570,22 +6666,121 @@ Perl_peep(pTHX_ register OP *o) SvREFCNT_dec(sv); *svp = lexname; } + + if ((o->op_private & (OPpLVAL_INTRO))) + break; + + rop = (UNOP*)((BINOP*)o)->op_first; + if (rop->op_type != OP_RV2HV || rop->op_first->op_type != OP_PADSV) + break; + lexname = *av_fetch(PL_comppad_name, rop->op_first->op_targ, TRUE); + if (!(SvFLAGS(lexname) & SVpad_TYPED)) + break; + fields = (GV**)hv_fetch(SvSTASH(lexname), "FIELDS", 6, FALSE); + if (!fields || !GvHV(*fields)) + break; + key = SvPV(*svp, keylen); + if (!hv_fetch(GvHV(*fields), key, + SvUTF8(*svp) ? -(I32)keylen : keylen, FALSE)) + { + Perl_croak(aTHX_ "No such class field \"%s\" " + "in variable %s of type %s", + key, SvPV_nolen(lexname), HvNAME(SvSTASH(lexname))); + } + break; } - case OP_SORT: { - /* make @a = sort @a act in-place */ + case OP_HSLICE: { + UNOP *rop; + SV *lexname; + GV **fields; + SV **svp; + char *key; + STRLEN keylen; + SVOP *first_key_op, *key_op; + if ((o->op_private & (OPpLVAL_INTRO)) + /* I bet there's always a pushmark... */ + || ((LISTOP*)o)->op_first->op_sibling->op_type != OP_LIST) + /* hmmm, no optimization if list contains only one key. */ + break; + rop = (UNOP*)((LISTOP*)o)->op_last; + if (rop->op_type != OP_RV2HV) + break; + if (rop->op_first->op_type == OP_PADSV) + /* @$hash{qw(keys here)} */ + rop = (UNOP*)rop->op_first; + else { + /* @{$hash}{qw(keys here)} */ + if (rop->op_first->op_type == OP_SCOPE + && cLISTOPx(rop->op_first)->op_last->op_type == OP_PADSV) + { + rop = (UNOP*)cLISTOPx(rop->op_first)->op_last; + } + else + break; + } + + lexname = *av_fetch(PL_comppad_name, rop->op_targ, TRUE); + if (!(SvFLAGS(lexname) & SVpad_TYPED)) + break; + fields = (GV**)hv_fetch(SvSTASH(lexname), "FIELDS", 6, FALSE); + if (!fields || !GvHV(*fields)) + break; + /* Again guessing that the pushmark can be jumped over.... */ + first_key_op = (SVOP*)((LISTOP*)((LISTOP*)o)->op_first->op_sibling) + ->op_first->op_sibling; + for (key_op = first_key_op; key_op; + key_op = (SVOP*)key_op->op_sibling) { + if (key_op->op_type != OP_CONST) + continue; + svp = cSVOPx_svp(key_op); + key = SvPV(*svp, keylen); + if (!hv_fetch(GvHV(*fields), key, + SvUTF8(*svp) ? -(I32)keylen : keylen, FALSE)) + { + Perl_croak(aTHX_ "No such class field \"%s\" " + "in variable %s of type %s", + key, SvPV_nolen(lexname), HvNAME(SvSTASH(lexname))); + } + } + break; + } + + case OP_SORT: { /* will point to RV2AV or PADAV op on LHS/RHS of assign */ OP *oleft, *oright; OP *o2; - o->op_opt = 1; - /* check that RHS of sort is a single plain array */ oright = cUNOPo->op_first; if (!oright || oright->op_type != OP_PUSHMARK) break; + + /* reverse sort ... can be optimised. */ + if (!cUNOPo->op_sibling) { + /* Nothing follows us on the list. */ + OP *reverse = o->op_next; + + if (reverse->op_type == OP_REVERSE && + (reverse->op_flags & OPf_WANT) == OPf_WANT_LIST) { + OP *pushmark = cUNOPx(reverse)->op_first; + if (pushmark && (pushmark->op_type == OP_PUSHMARK) + && (cUNOPx(pushmark)->op_sibling == o)) { + /* reverse -> pushmark -> sort */ + o->op_private |= OPpSORT_REVERSE; + op_null(reverse); + pushmark->op_next = oright->op_next; + op_null(oright); + } + } + } + + /* make @a = sort @a act in-place */ + + o->op_opt = 1; + oright = cUNOPx(oright)->op_sibling; if (!oright) break; @@ -6625,6 +6820,17 @@ Perl_peep(pTHX_ register OP *o) || (o2->op_flags & OPf_WANT) != OPf_WANT_VOID) break; + /* check that the sort is the first arg on RHS of assign */ + + o2 = cUNOPx(o2)->op_first; + if (!o2 || o2->op_type != OP_NULL) + break; + o2 = cUNOPx(o2)->op_first; + if (!o2 || o2->op_type != OP_PUSHMARK) + break; + if (o2->op_sibling != o) + break; + /* check the array is the same on both sides */ if (oleft->op_type == OP_RV2AV) { if (oright->op_type != OP_RV2AV @@ -6660,9 +6866,97 @@ Perl_peep(pTHX_ register OP *o) break; } - + case OP_REVERSE: { + OP *ourmark, *theirmark, *ourlast, *iter, *expushmark, *rv2av; + OP *gvop = NULL; + LISTOP *enter, *exlist; + o->op_opt = 1; + + enter = (LISTOP *) o->op_next; + if (!enter) + break; + if (enter->op_type == OP_NULL) { + enter = (LISTOP *) enter->op_next; + if (!enter) + break; + } + /* for $a (...) will have OP_GV then OP_RV2GV here. + for (...) just has an OP_GV. */ + if (enter->op_type == OP_GV) { + gvop = (OP *) enter; + enter = (LISTOP *) enter->op_next; + if (!enter) + break; + if (enter->op_type == OP_RV2GV) { + enter = (LISTOP *) enter->op_next; + if (!enter) + break; + } + } + + if (enter->op_type != OP_ENTERITER) + break; + + iter = enter->op_next; + if (!iter || iter->op_type != OP_ITER) + break; + + expushmark = enter->op_first; + if (!expushmark || expushmark->op_type != OP_NULL + || expushmark->op_targ != OP_PUSHMARK) + break; + + exlist = (LISTOP *) expushmark->op_sibling; + if (!exlist || exlist->op_type != OP_NULL + || exlist->op_targ != OP_LIST) + break; + if (exlist->op_last != o) { + /* Mmm. Was expecting to point back to this op. */ + break; + } + theirmark = exlist->op_first; + if (!theirmark || theirmark->op_type != OP_PUSHMARK) + break; + + if (theirmark->op_sibling != o) { + /* There's something between the mark and the reverse, eg + for (1, reverse (...)) + so no go. */ + break; + } + + ourmark = ((LISTOP *)o)->op_first; + if (!ourmark || ourmark->op_type != OP_PUSHMARK) + break; + + ourlast = ((LISTOP *)o)->op_last; + if (!ourlast || ourlast->op_next != o) + break; + + rv2av = ourmark->op_sibling; + if (rv2av && rv2av->op_type == OP_RV2AV && rv2av->op_sibling == 0 + && rv2av->op_flags == (OPf_WANT_LIST | OPf_KIDS) + && enter->op_flags == (OPf_WANT_LIST | OPf_KIDS)) { + /* We're just reversing a single array. */ + rv2av->op_flags = OPf_WANT_SCALAR | OPf_KIDS | OPf_REF; + enter->op_flags |= OPf_STACKED; + } + + /* We don't have control over who points to theirmark, so sacrifice + ours. */ + theirmark->op_next = ourmark->op_next; + theirmark->op_flags = ourmark->op_flags; + ourlast->op_next = gvop ? gvop : (OP *) enter; + op_null(ourmark); + op_null(o); + enter->op_private |= OPpITER_REVERSED; + iter->op_private |= OPpITER_REVERSED; + + break; + } + default: o->op_opt = 1; break;