diff options
author | Gerard Goossen <gerard@ggoossen.net> | 2011-06-15 11:32:53 +0200 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2011-07-28 14:50:19 -0700 |
commit | d164302a58430157957e90a71e7a08de7eabbc94 (patch) | |
tree | ef2c4e6757d48ab0322715c9515be6118dcd39e0 /op.c | |
parent | 9feb131675d04c74cc7462275ae5b70055f1c4ba (diff) | |
download | perl-d164302a58430157957e90a71e7a08de7eabbc94.tar.gz |
Add finalize_optree function which can take over all the compile time checking/finalization now being done by the peephole optimizer.
This function takes the optree after it is finished building. It
takes over some of the checking and final conversions which are currently being
done by the peephole optimizer.
Add the moment this is an unnecessary extra step after the peephole optimizer, but with
a separate code generation step, the current peephole optimizer can't exists and
this function will take over all its essential compile time functions.
Diffstat (limited to 'op.c')
-rw-r--r-- | op.c | 457 |
1 files changed, 243 insertions, 214 deletions
@@ -1396,6 +1396,247 @@ S_modkids(pTHX_ OP *o, I32 type) } /* +=for apidoc finalize_optree + +This function finalizes the optree. Should be called directly after +the complete optree is built. It does some additional +checking which can't be done in the normal ck_xxx functions and makes +the tree thread-safe. + +=cut +*/ +void +Perl_finalize_optree(pTHX_ OP* o) +{ + PERL_ARGS_ASSERT_FINALIZE_OPTREE; + + ENTER; + SAVEVPTR(PL_curcop); + + finalize_op(o); + + LEAVE; +} + +void +S_finalize_op(pTHX_ OP* o) +{ + PERL_ARGS_ASSERT_FINALIZE_OP; + +#if defined(PERL_MAD) && defined(USE_ITHREADS) + { + /* Make sure mad ops are also thread-safe */ + MADPROP *mp = o->op_madprop; + while (mp) { + if (mp->mad_type == MAD_OP && mp->mad_vlen) { + OP *prop_op = (OP *) mp->mad_val; + /* We only need "Relocate sv to the pad for thread safety.", but this + easiest way to make sure it traverses everything */ + finalize_op(prop_op); + } + mp = mp->mad_next; + } + } +#endif + + switch (o->op_type) { + case OP_NEXTSTATE: + case OP_DBSTATE: + PL_curcop = ((COP*)o); /* for warnings */ + break; + case OP_EXEC: + if (o->op_next && o->op_next->op_type == OP_NEXTSTATE + && ckWARN(WARN_SYNTAX)) + { + if (o->op_next->op_sibling) { + const OPCODE type = o->op_next->op_sibling->op_type; + if (type != OP_EXIT && type != OP_WARN && type != OP_DIE) { + const line_t oldline = CopLINE(PL_curcop); + CopLINE_set(PL_curcop, CopLINE((COP*)o->op_next)); + Perl_warner(aTHX_ packWARN(WARN_EXEC), + "Statement unlikely to be reached"); + Perl_warner(aTHX_ packWARN(WARN_EXEC), + "\t(Maybe you meant system() when you said exec()?)\n"); + CopLINE_set(PL_curcop, oldline); + } + } + } + break; + + case OP_GV: + if ((o->op_private & OPpEARLY_CV) && ckWARN(WARN_PROTOTYPE)) { + GV * const gv = cGVOPo_gv; + if (SvTYPE(gv) == SVt_PVGV && GvCV(gv) && SvPVX_const(GvCV(gv))) { + /* XXX could check prototype here instead of just carping */ + SV * const sv = sv_newmortal(); + gv_efullname3(sv, gv, NULL); + Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE), + "%"SVf"() called too early to check prototype", + SVfARG(sv)); + } + } + break; + + case OP_CONST: +#ifdef USE_ITHREADS + case OP_HINTSEVAL: + case OP_METHOD_NAMED: + /* Relocate sv to the pad for thread safety. + * Despite being a "constant", the SV is written to, + * for reference counts, sv_upgrade() etc. */ + if (cSVOPo->op_sv) { + const PADOFFSET ix = pad_alloc(OP_CONST, SVs_PADTMP); + if (o->op_type != OP_METHOD_NAMED && + (SvPADTMP(cSVOPo->op_sv) || SvPADMY(cSVOPo->op_sv))) + { + /* If op_sv is already a PADTMP/MY then it is being used by + * some pad, so make a copy. */ + sv_setsv(PAD_SVl(ix),cSVOPo->op_sv); + SvREADONLY_on(PAD_SVl(ix)); + SvREFCNT_dec(cSVOPo->op_sv); + } + else if (o->op_type != OP_METHOD_NAMED + && cSVOPo->op_sv == &PL_sv_undef) { + /* PL_sv_undef is hack - it's unsafe to store it in the + AV that is the pad, because av_fetch treats values of + PL_sv_undef as a "free" AV entry and will merrily + replace them with a new SV, causing pad_alloc to think + that this pad slot is free. (When, clearly, it is not) + */ + SvOK_off(PAD_SVl(ix)); + SvPADTMP_on(PAD_SVl(ix)); + SvREADONLY_on(PAD_SVl(ix)); + } + else { + SvREFCNT_dec(PAD_SVl(ix)); + SvPADTMP_on(cSVOPo->op_sv); + PAD_SETSV(ix, cSVOPo->op_sv); + /* XXX I don't know how this isn't readonly already. */ + SvREADONLY_on(PAD_SVl(ix)); + } + cSVOPo->op_sv = NULL; + o->op_targ = ix; + } +#endif + break; + + case OP_HELEM: { + UNOP *rop; + SV *lexname; + GV **fields; + SV **svp, *sv; + const char *key = NULL; + STRLEN keylen; + + if (((BINOP*)o)->op_last->op_type != OP_CONST) + break; + + /* Make the CONST have a shared SV */ + svp = cSVOPx_svp(((BINOP*)o)->op_last); + if ((!SvFAKE(sv = *svp) || !SvREADONLY(sv)) + && SvTYPE(sv) < SVt_PVMG && !SvROK(sv)) { + key = SvPV_const(sv, keylen); + lexname = newSVpvn_share(key, + SvUTF8(sv) ? -(I32)keylen : (I32)keylen, + 0); + 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 (!SvPAD_TYPED(lexname)) + break; + fields = (GV**)hv_fetchs(SvSTASH(lexname), "FIELDS", FALSE); + if (!fields || !GvHV(*fields)) + break; + key = SvPV_const(*svp, keylen); + if (!hv_fetch(GvHV(*fields), key, + SvUTF8(*svp) ? -(I32)keylen : (I32)keylen, FALSE)) { + Perl_croak(aTHX_ "No such class field \"%s\" " + "in variable %s of type %s", + key, SvPV_nolen_const(lexname), HvNAME_get(SvSTASH(lexname))); + } + break; + } + + case OP_HSLICE: { + UNOP *rop; + SV *lexname; + GV **fields; + SV **svp; + const 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 (!SvPAD_TYPED(lexname)) + break; + fields = (GV**)hv_fetchs(SvSTASH(lexname), "FIELDS", 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_const(*svp, keylen); + if (!hv_fetch(GvHV(*fields), key, + SvUTF8(*svp) ? -(I32)keylen : (I32)keylen, FALSE)) { + Perl_croak(aTHX_ "No such class field \"%s\" " + "in variable %s of type %s", + key, SvPV_nolen(lexname), HvNAME_get(SvSTASH(lexname))); + } + } + break; + } + case OP_SUBST: { + if (cPMOPo->op_pmreplrootu.op_pmreplroot) + finalize_op(cPMOPo->op_pmreplrootu.op_pmreplroot); + break; + } + default: + break; + } + + if (o->op_flags & OPf_KIDS) { + OP *kid; + for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) + finalize_op(kid); + } +} + +/* =for apidoc Amx|OP *|op_lvalue|OP *o|I32 type Propagate lvalue ("modifiable") context to an op and its children. @@ -2498,6 +2739,7 @@ Perl_newPROG(pTHX_ OP *o) OpREFCNT_set(PL_main_root, 1); PL_main_root->op_next = 0; CALL_PEEP(PL_main_start); + finalize_optree(PL_main_root); PL_compcv = 0; /* Register with debugger */ @@ -6400,6 +6642,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block) CvSTART(cv) = LINKLIST(CvROOT(cv)); CvROOT(cv)->op_next = 0; CALL_PEEP(CvSTART(cv)); + finalize_optree(CvROOT(cv)); /* now that optimizer has done its work, adjust pad values */ @@ -9341,47 +9584,6 @@ Perl_rpeep(pTHX_ register OP *o) break; } -#if defined(PERL_MAD) && defined(USE_ITHREADS) - MADPROP *mp = o->op_madprop; - while (mp) { - if (mp->mad_type == MAD_OP && mp->mad_vlen) { - OP *prop_op = (OP *) mp->mad_val; - /* I *think* that this is roughly the right thing to do. It - seems that sometimes the optree hooked into the madprops - doesn't have its next pointers set, so it's not possible to - use them to locate all the OPs needing a fixup. Possibly - it's a bit overkill calling LINKLIST to do this, when we - could instead iterate over the OPs (without changing them) - the way op_linklist does internally. However, I'm not sure - if there are corner cases where we have a chain of partially - linked OPs. Or even if we do, does that matter? Or should - we always iterate on op_first,op_next? */ - LINKLIST(prop_op); - do { - if (prop_op->op_opt) - break; - prop_op->op_opt = 1; - switch (prop_op->op_type) { - case OP_CONST: - case OP_HINTSEVAL: - case OP_METHOD_NAMED: - /* Duplicate the "relocate sv to the pad for thread - safety" code, as otherwise an opfree of this madprop - in the wrong thread will free the SV to the wrong - interpreter. */ - if (((SVOP *)prop_op)->op_sv) { - const PADOFFSET ix = pad_alloc(OP_CONST, SVs_PADTMP); - sv_setsv(PAD_SVl(ix),((SVOP *)prop_op)->op_sv); - SvREFCNT_dec(((SVOP *)prop_op)->op_sv); - ((SVOP *)prop_op)->op_sv = NULL; - } - break; - } - } while ((prop_op = prop_op->op_next)); - } - mp = mp->mad_next; - } -#endif /* By default, this op has now been optimised. A couple of cases below clear this again. */ o->op_opt = 1; @@ -9447,46 +9649,6 @@ Perl_rpeep(pTHX_ register OP *o) case OP_CONST: if (cSVOPo->op_private & OPpCONST_STRICT) no_bareword_allowed(o); -#ifdef USE_ITHREADS - case OP_HINTSEVAL: - case OP_METHOD_NAMED: - /* Relocate sv to the pad for thread safety. - * Despite being a "constant", the SV is written to, - * for reference counts, sv_upgrade() etc. */ - if (cSVOP->op_sv) { - const PADOFFSET ix = pad_alloc(OP_CONST, SVs_PADTMP); - if (o->op_type != OP_METHOD_NAMED && - (SvPADTMP(cSVOPo->op_sv) || SvPADMY(cSVOPo->op_sv))) - { - /* If op_sv is already a PADTMP/MY then it is being used by - * some pad, so make a copy. */ - sv_setsv(PAD_SVl(ix),cSVOPo->op_sv); - SvREADONLY_on(PAD_SVl(ix)); - SvREFCNT_dec(cSVOPo->op_sv); - } - else if (o->op_type != OP_METHOD_NAMED - && cSVOPo->op_sv == &PL_sv_undef) { - /* PL_sv_undef is hack - it's unsafe to store it in the - AV that is the pad, because av_fetch treats values of - PL_sv_undef as a "free" AV entry and will merrily - replace them with a new SV, causing pad_alloc to think - that this pad slot is free. (When, clearly, it is not) - */ - SvOK_off(PAD_SVl(ix)); - SvPADTMP_on(PAD_SVl(ix)); - SvREADONLY_on(PAD_SVl(ix)); - } - else { - SvREFCNT_dec(PAD_SVl(ix)); - SvPADTMP_on(cSVOPo->op_sv); - PAD_SETSV(ix, cSVOPo->op_sv); - /* XXX I don't know how this isn't readonly already. */ - SvREADONLY_on(PAD_SVl(ix)); - } - cSVOPo->op_sv = NULL; - o->op_targ = ix; - } -#endif break; case OP_CONCAT: @@ -9580,17 +9742,6 @@ Perl_rpeep(pTHX_ register OP *o) o->op_ppaddr = PL_ppaddr[OP_GVSV]; } } - else if ((o->op_private & OPpEARLY_CV) && ckWARN(WARN_PROTOTYPE)) { - GV * const gv = cGVOPo_gv; - if (SvTYPE(gv) == SVt_PVGV && GvCV(gv) && SvPVX_const(GvCV(gv))) { - /* XXX could check prototype here instead of just carping */ - SV * const sv = sv_newmortal(); - gv_efullname3(sv, gv, NULL); - Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE), - "%"SVf"() called too early to check prototype", - SVfARG(sv)); - } - } else if (o->op_next->op_type == OP_READLINE && o->op_next->op_next->op_type == OP_CONCAT && (o->op_next->op_next->op_flags & OPf_STACKED)) @@ -9702,128 +9853,6 @@ Perl_rpeep(pTHX_ register OP *o) DEFER(cPMOP->op_pmstashstartu.op_pmreplstart); break; - case OP_EXEC: - if (o->op_next && o->op_next->op_type == OP_NEXTSTATE - && ckWARN(WARN_SYNTAX)) - { - if (o->op_next->op_sibling) { - const OPCODE type = o->op_next->op_sibling->op_type; - if (type != OP_EXIT && type != OP_WARN && type != OP_DIE) { - const line_t oldline = CopLINE(PL_curcop); - CopLINE_set(PL_curcop, CopLINE((COP*)o->op_next)); - Perl_warner(aTHX_ packWARN(WARN_EXEC), - "Statement unlikely to be reached"); - Perl_warner(aTHX_ packWARN(WARN_EXEC), - "\t(Maybe you meant system() when you said exec()?)\n"); - CopLINE_set(PL_curcop, oldline); - } - } - } - break; - - case OP_HELEM: { - UNOP *rop; - SV *lexname; - GV **fields; - SV **svp, *sv; - const char *key = NULL; - STRLEN keylen; - - if (((BINOP*)o)->op_last->op_type != OP_CONST) - break; - - /* Make the CONST have a shared SV */ - svp = cSVOPx_svp(((BINOP*)o)->op_last); - if ((!SvFAKE(sv = *svp) || !SvREADONLY(sv)) - && SvTYPE(sv) < SVt_PVMG && !SvROK(sv)) { - key = SvPV_const(sv, keylen); - lexname = newSVpvn_share(key, - SvUTF8(sv) ? -(I32)keylen : (I32)keylen, - 0); - 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 (!SvPAD_TYPED(lexname)) - break; - fields = (GV**)hv_fetchs(SvSTASH(lexname), "FIELDS", FALSE); - if (!fields || !GvHV(*fields)) - break; - key = SvPV_const(*svp, keylen); - if (!hv_fetch(GvHV(*fields), key, - SvUTF8(*svp) ? -(I32)keylen : (I32)keylen, FALSE)) - { - Perl_croak(aTHX_ "No such class field \"%s\" " - "in variable %s of type %s", - key, SvPV_nolen_const(lexname), HvNAME_get(SvSTASH(lexname))); - } - - break; - } - - case OP_HSLICE: { - UNOP *rop; - SV *lexname; - GV **fields; - SV **svp; - const 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 (!SvPAD_TYPED(lexname)) - break; - fields = (GV**)hv_fetchs(SvSTASH(lexname), "FIELDS", 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_const(*svp, keylen); - if (!hv_fetch(GvHV(*fields), key, - SvUTF8(*svp) ? -(I32)keylen : (I32)keylen, FALSE)) - { - Perl_croak(aTHX_ "No such class field \"%s\" " - "in variable %s of type %s", - key, SvPV_nolen(lexname), HvNAME_get(SvSTASH(lexname))); - } - } - break; - } case OP_RV2SV: case OP_RV2AV: case OP_RV2HV: |