X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/152e8a12bd1ba6c9b17f3da2f81f37518f992ad2..a310a8f2bf41061e1bf6feadf7d6758f96b481c5:/op.c diff --git a/op.c b/op.c index acea933..1406ffc 100644 --- a/op.c +++ b/op.c @@ -261,18 +261,13 @@ Perl_Slab_to_ro(pTHX_ OPSLAB *slab) } } -STATIC void -S_Slab_to_rw(pTHX_ void *op) +void +Perl_Slab_to_rw(pTHX_ OPSLAB *const slab) { - OP * const o = (OP *)op; - OPSLAB *slab; OPSLAB *slab2; PERL_ARGS_ASSERT_SLAB_TO_RW; - if (!o->op_slabbed) return; - - slab = OpSLAB(o); if (!slab->opslab_readonly) return; slab2 = slab; for (; slab2; slab2 = slab2->opslab_next) { @@ -406,8 +401,14 @@ OP * Perl_op_refcnt_inc(pTHX_ OP *o) { if(o) { - Slab_to_rw(o); - ++o->op_targ; + OPSLAB *const slab = o->op_slabbed ? OpSLAB(o) : NULL; + if (slab && slab->opslab_readonly) { + Slab_to_rw(slab); + ++o->op_targ; + Slab_to_ro(slab); + } else { + ++o->op_targ; + } } return o; @@ -416,9 +417,19 @@ Perl_op_refcnt_inc(pTHX_ OP *o) PADOFFSET Perl_op_refcnt_dec(pTHX_ OP *o) { + PADOFFSET result; + OPSLAB *const slab = o->op_slabbed ? OpSLAB(o) : NULL; + PERL_ARGS_ASSERT_OP_REFCNT_DEC; - Slab_to_rw(o); - return --o->op_targ; + + if (slab && slab->opslab_readonly) { + Slab_to_rw(slab); + result = --o->op_targ; + Slab_to_ro(slab); + } else { + result = --o->op_targ; + } + return result; } #endif /* @@ -631,10 +642,6 @@ Perl_alloccopstash(pTHX_ HV *hv) static void S_op_destroy(pTHX_ OP *o) { - if (o->op_latefree) { - o->op_latefreed = 1; - return; - } FreeOp(o); } @@ -659,11 +666,6 @@ Perl_op_free(pTHX_ OP *o) may be freed before their parents. */ if (!o || o->op_type == OP_FREED) return; - if (o->op_latefreed) { - if (o->op_latefree) - return; - goto do_free; - } type = o->op_type; if (o->op_private & OPpREFCOUNTED) { @@ -698,33 +700,26 @@ Perl_op_free(pTHX_ OP *o) CALL_OPFREEHOOK(o); if (o->op_flags & OPf_KIDS) { - register OP *kid, *nextkid; + OP *kid, *nextkid; for (kid = cUNOPo->op_first; kid; kid = nextkid) { nextkid = kid->op_sibling; /* Get before next freeing kid */ op_free(kid); } } + if (type == OP_NULL) + type = (OPCODE)o->op_targ; - Slab_to_rw(o); + if (o->op_slabbed) { + Slab_to_rw(OpSLAB(o)); + } /* COP* is not cleared by op_clear() so that we may track line * numbers etc even after null() */ - if (type == OP_NEXTSTATE || type == OP_DBSTATE - || (type == OP_NULL /* the COP might have been null'ed */ - && ((OPCODE)o->op_targ == OP_NEXTSTATE - || (OPCODE)o->op_targ == OP_DBSTATE))) { + if (type == OP_NEXTSTATE || type == OP_DBSTATE) { cop_free((COP*)o); } - if (type == OP_NULL) - type = (OPCODE)o->op_targ; - op_clear(o); - if (o->op_latefree) { - o->op_latefreed = 1; - return; - } - do_free: FreeOp(o); #ifdef DEBUG_LEAKING_SCALARS if (PL_op == o) @@ -826,6 +821,7 @@ Perl_op_clear(pTHX_ OP *o) } #endif break; + case OP_DUMP: case OP_GOTO: case OP_NEXT: case OP_LAST: @@ -836,6 +832,7 @@ Perl_op_clear(pTHX_ OP *o) case OP_TRANS: case OP_TRANSR: if (o->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)) { + assert(o->op_type == OP_TRANS || o->op_type == OP_TRANSR); #ifdef USE_ITHREADS if (cPADOPo->op_padix > 0) { pad_swipe(cPADOPo->op_padix, TRUE); @@ -1059,7 +1056,7 @@ Perl_op_linklist(pTHX_ OP *o) /* establish postfix order */ first = cUNOPo->op_first; if (first) { - register OP *kid; + OP *kid; o->op_next = LINKLIST(first); kid = first; for (;;) { @@ -1101,8 +1098,11 @@ S_scalarboolean(pTHX_ OP *o) if (ckWARN(WARN_SYNTAX)) { const line_t oldline = CopLINE(PL_curcop); - if (PL_parser && PL_parser->copline != NOLINE) + if (PL_parser && PL_parser->copline != NOLINE) { + /* This ensures that warnings are reported at the first line + of the conditional, not the last. */ CopLINE_set(PL_curcop, PL_parser->copline); + } Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Found = in conditional, should be =="); CopLINE_set(PL_curcop, oldline); } @@ -1181,8 +1181,8 @@ Perl_scalarvoid(pTHX_ OP *o) { dVAR; OP *kid; + SV *useless_sv = NULL; const char* useless = NULL; - U32 useless_is_utf8 = 0; SV* sv; U8 want; @@ -1383,19 +1383,19 @@ Perl_scalarvoid(pTHX_ OP *o) useless = NULL; else { SV * const dsv = newSVpvs(""); - SV* msv = sv_2mortal(Perl_newSVpvf(aTHX_ - "a constant (%s)", - pv_pretty(dsv, maybe_macro, SvCUR(sv), 32, NULL, NULL, - PERL_PV_PRETTY_DUMP | PERL_PV_ESCAPE_NOCLEAR | PERL_PV_ESCAPE_UNI_DETECT ))); + useless_sv + = Perl_newSVpvf(aTHX_ + "a constant (%s)", + pv_pretty(dsv, maybe_macro, + SvCUR(sv), 32, NULL, NULL, + PERL_PV_PRETTY_DUMP + | PERL_PV_ESCAPE_NOCLEAR + | PERL_PV_ESCAPE_UNI_DETECT)); SvREFCNT_dec(dsv); - useless = SvPV_nolen(msv); - useless_is_utf8 = SvUTF8(msv); } } else if (SvOK(sv)) { - SV* msv = sv_2mortal(Perl_newSVpvf(aTHX_ - "a constant (%"SVf")", sv)); - useless = SvPV_nolen(msv); + useless_sv = Perl_newSVpvf(aTHX_ "a constant (%"SVf")", sv); } else useless = "a constant (undef)"; @@ -1522,10 +1522,18 @@ Perl_scalarvoid(pTHX_ OP *o) case OP_SCALAR: return scalar(o); } - if (useless) - Perl_ck_warner(aTHX_ packWARN(WARN_VOID), "Useless use of %"SVf" in void context", - newSVpvn_flags(useless, strlen(useless), - SVs_TEMP | ( useless_is_utf8 ? SVf_UTF8 : 0 ))); + + if (useless_sv) { + /* mortalise it, in case warnings are fatal. */ + Perl_ck_warner(aTHX_ packWARN(WARN_VOID), + "Useless use of %"SVf" in void context", + sv_2mortal(useless_sv)); + } + else if (useless) { + Perl_ck_warner(aTHX_ packWARN(WARN_VOID), + "Useless use of %s in void context", + useless); + } return o; } @@ -2442,31 +2450,20 @@ S_dup_attrlist(pTHX_ OP *o) } STATIC void -S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs, bool for_my) +S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs) { dVAR; - SV *stashsv; + SV * const stashsv = stash ? newSVhek(HvNAME_HEK(stash)) : &PL_sv_no; PERL_ARGS_ASSERT_APPLY_ATTRS; /* fake up C */ ENTER; /* need to protect against side-effects of 'use' */ - stashsv = stash ? newSVhek(HvNAME_HEK(stash)) : &PL_sv_no; #define ATTRSMODULE "attributes" #define ATTRSMODULE_PM "attributes.pm" - if (for_my) { - /* Don't force the C if we don't need it. */ - SV * const * const svp = hv_fetchs(GvHVn(PL_incgv), ATTRSMODULE_PM, FALSE); - if (svp && *svp != &PL_sv_undef) - NOOP; /* already in %INC */ - else - Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, - newSVpvs(ATTRSMODULE), NULL); - } - else { - Perl_load_module(aTHX_ PERL_LOADMOD_IMPORT_OPS, + Perl_load_module(aTHX_ PERL_LOADMOD_IMPORT_OPS, newSVpvs(ATTRSMODULE), NULL, op_prepend_elem(OP_LIST, @@ -2475,7 +2472,6 @@ S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs, bool for_my) newSVOP(OP_CONST, 0, newRV(target)), dup_attrlist(attrs)))); - } LEAVE; } @@ -2484,7 +2480,7 @@ S_apply_attrs_my(pTHX_ HV *stash, OP *target, OP *attrs, OP **imopsp) { dVAR; OP *pack, *imop, *arg; - SV *meth, *stashsv; + SV *meth, *stashsv, **svp; PERL_ARGS_ASSERT_APPLY_ATTRS_MY; @@ -2496,7 +2492,15 @@ S_apply_attrs_my(pTHX_ HV *stash, OP *target, OP *attrs, OP **imopsp) target->op_type == OP_PADAV); /* Ensure that attributes.pm is loaded. */ - apply_attrs(stash, PAD_SV(target->op_targ), attrs, TRUE); + ENTER; /* need to protect against side-effects of 'use' */ + /* Don't force the C if we don't need it. */ + svp = hv_fetchs(GvHVn(PL_incgv), ATTRSMODULE_PM, FALSE); + if (svp && *svp != &PL_sv_undef) + NOOP; /* already in %INC */ + else + Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, + newSVpvs(ATTRSMODULE), NULL); + LEAVE; /* Need package name for method call. */ pack = newSVOP(OP_CONST, 0, newSVpvs(ATTRSMODULE)); @@ -2616,7 +2620,7 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp) (type == OP_RV2SV ? GvSV(gv) : type == OP_RV2AV ? MUTABLE_SV(GvAV(gv)) : type == OP_RV2HV ? MUTABLE_SV(GvHV(gv)) : MUTABLE_SV(gv)), - attrs, FALSE); + attrs); } o->op_private |= OPpOUR_INTRO; return o; @@ -2851,6 +2855,18 @@ Perl_op_scope(pTHX_ OP *o) return o; } +OP * +Perl_op_unscope(pTHX_ OP *o) +{ + if (o && o->op_type == OP_LINESEQ) { + OP *kid = cLISTOPo->op_first; + for(; kid; kid = kid->op_sibling) + if (kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) + op_null(kid); + } + return o; +} + int Perl_block_start(pTHX_ int full) { @@ -2874,6 +2890,7 @@ Perl_block_end(pTHX_ I32 floor, OP *seq) dVAR; const int needblockscope = PL_hints & HINT_BLOCK_SCOPE; OP* retval = scalarseq(seq); + OP *o; CALL_BLOCK_HOOKS(bhk_pre_end, &retval); @@ -2881,7 +2898,66 @@ Perl_block_end(pTHX_ I32 floor, OP *seq) CopHINTS_set(&PL_compiling, PL_hints); if (needblockscope) PL_hints |= HINT_BLOCK_SCOPE; /* propagate out */ - pad_leavemy(); + o = pad_leavemy(); + + if (o) { + /* pad_leavemy has created a sequence of introcv ops for all my + subs declared in the block. We have to replicate that list with + clonecv ops, to deal with this situation: + + sub { + my sub s1; + my sub s2; + sub s1 { state sub foo { \&s2 } } + }->() + + Originally, I was going to have introcv clone the CV and turn + off the stale flag. Since &s1 is declared before &s2, the + introcv op for &s1 is executed (on sub entry) before the one for + &s2. But the &foo sub inside &s1 (which is cloned when &s1 is + cloned, since it is a state sub) closes over &s2 and expects + to see it in its outer CV’s pad. If the introcv op clones &s1, + then &s2 is still marked stale. Since &s1 is not active, and + &foo closes over &s1’s implicit entry for &s2, we get a ‘Varia- + ble will not stay shared’ warning. Because it is the same stub + that will be used when the introcv op for &s2 is executed, clos- + ing over it is safe. Hence, we have to turn off the stale flag + on all lexical subs in the block before we clone any of them. + Hence, having introcv clone the sub cannot work. So we create a + list of ops like this: + + lineseq + | + +-- introcv + | + +-- introcv + | + +-- introcv + | + . + . + . + | + +-- clonecv + | + +-- clonecv + | + +-- clonecv + | + . + . + . + */ + OP *kid = o->op_flags & OPf_KIDS ? cLISTOPo->op_first : o; + OP * const last = o->op_flags & OPf_KIDS ? cLISTOPo->op_last : o; + for (;; kid = kid->op_sibling) { + OP *newkid = newOP(OP_CLONECV, 0); + newkid->op_targ = kid->op_targ; + o = op_append_elem(OP_LINESEQ, o, newkid); + if (kid == last) break; + } + retval = op_prepend_elem(OP_LINESEQ, o, retval); + } CALL_BLOCK_HOOKS(bhk_post_end, &retval); @@ -2962,6 +3038,32 @@ Perl_newPROG(pTHX_ OP *o) } else { if (o->op_type == OP_STUB) { + /* This block is entered if nothing is compiled for the main + program. This will be the case for an genuinely empty main + program, or one which only has BEGIN blocks etc, so already + run and freed. + + Historically (5.000) the guard above was !o. However, commit + f8a08f7b8bd67b28 (Jun 2001), integrated to blead as + c71fccf11fde0068, changed perly.y so that newPROG() is now + called with the output of block_end(), which returns a new + OP_STUB for the case of an empty optree. ByteLoader (and + maybe other things) also take this path, because they set up + PL_main_start and PL_main_root directly, without generating an + optree. + + If the parsing the main program aborts (due to parse errors, + or due to BEGIN or similar calling exit), then newPROG() + isn't even called, and hence this code path and its cleanups + are skipped. This shouldn't make a make a difference: + * a non-zero return from perl_parse is a failure, and + perl_destruct() should be called immediately. + * however, if exit(0) is called during the parse, then + perl_parse() returns 0, and perl_run() is called. As + PL_main_start will be NULL, perl_run() will return + promptly, and the exit code will remain 0. + */ + PL_comppad_name = 0; PL_compcv = 0; S_op_destroy(aTHX_ o); @@ -3107,7 +3209,7 @@ static OP * S_fold_constants(pTHX_ register OP *o) { dVAR; - register OP * VOL curop; + OP * VOL curop; OP *newop; VOL I32 type = o->op_type; SV * VOL sv = NULL; @@ -3257,7 +3359,7 @@ static OP * S_gen_constant_list(pTHX_ register OP *o) { dVAR; - register OP *curop; + OP *curop; const I32 oldtmps_floor = PL_tmps_floor; list(o); @@ -3816,9 +3918,6 @@ Perl_newOP(pTHX_ I32 type, I32 flags) o->op_type = (OPCODE)type; o->op_ppaddr = PL_ppaddr[type]; o->op_flags = (U8)flags; - o->op_latefree = 0; - o->op_latefreed = 0; - o->op_attached = 0; o->op_next = o; o->op_private = (U8)(0 | (flags >> 8)); @@ -3962,10 +4061,10 @@ S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl) STRLEN rlen; const U8 *t = (U8*)SvPV_const(tstr, tlen); const U8 *r = (U8*)SvPV_const(rstr, rlen); - register I32 i; - register I32 j; + I32 i; + I32 j; I32 grows = 0; - register short *tbl; + short *tbl; const I32 complement = o->op_private & OPpTRANS_COMPLEMENT; const I32 squash = o->op_private & OPpTRANS_SQUASH; @@ -5566,7 +5665,7 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o) dVAR; const U32 seq = intro_my(); const U32 utf8 = flags & SVf_UTF8; - register COP *cop; + COP *cop; flags &= ~SVf_UTF8; @@ -5604,8 +5703,7 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o) CopLINE_set(cop, CopLINE(PL_curcop)); else { CopLINE_set(cop, PL_parser->copline); - if (PL_parser) - PL_parser->copline = NOLINE; + PL_parser->copline = NOLINE; } #ifdef USE_ITHREADS CopFILE_set(cop, CopFILE(PL_curcop)); /* XXX share in a pvtable? */ @@ -5831,6 +5929,8 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp) } if (warnop) { const line_t oldline = CopLINE(PL_curcop); + /* This ensures that warnings are reported at the first line + of the construction, not the last. */ CopLINE_set(PL_curcop, PL_parser->copline); Perl_warner(aTHX_ packWARN(WARN_MISC), "Value of %s%s can be \"0\"; test with defined()", @@ -6387,7 +6487,7 @@ Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont) Constructs, checks, and returns a loop-exiting op (such as C or C). I is the opcode. I