cvs commit: ponie/perl op.c

[email protected] (Nicholas Clark) 27 Apr 2004 20:47:02 -0000
Newsgroups perl.ponie.changes
Message-ID <[email protected]>
cvsuser     04/04/27 13:47:02

  Modified:    perl     op.c
  Log:
  Integrate patch from blead which fixes read of free memory:
  http://public.activestate.com/cgi-bin/perlbrowse?patch=22716
  
  Revision  Changes    Path
  1.2       +283 -87   ponie/perl/op.c
  
  Index: op.c
  ===================================================================
  RCS file: /cvs/public/ponie/perl/op.c,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -w -r1.1 -r1.2
  --- op.c	9 Sep 2003 11:58:51 -0000	1.1
  +++ op.c	27 Apr 2004 20:47:02 -0000	1.2
  @@ -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.
  @@ -155,11 +155,11 @@
   {
       PADOFFSET off;
   
  -    /* complain about "my $_" etc etc */
  +    /* complain about "my $<special_var>" etc etc */
       if (!(PL_in_my == KEY_our ||
   	  isALPHA(name[1]) ||
   	  (USE_UTF8_IN_NAMES && UTF8_IS_START(name[1])) ||
  -	  (name[1] == '_' && (int)strlen(name) > 2)))
  +	  (name[1] == '_' && (*name == '$' || (int)strlen(name) > 2))))
       {
   	if (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1])) {
   	    /* 1999-02-27 [email protected] */
  @@ -216,7 +216,7 @@
       register OP *kid, *nextkid;
       OPCODE type;
   
  -    if (!o || o->op_seq == (U16)-1)
  +    if (!o || o->op_static)
   	return;
   
       if (o->op_private & OPpREFCOUNTED) {
  @@ -275,6 +275,8 @@
       case OP_GVSV:
       case OP_GV:
       case OP_AELEMFAST:
  +	if (! (o->op_type == OP_AELEMFAST && o->op_flags & OPf_SPECIAL)) {
  +	    /* not an OP_PADAV replacement */
   #ifdef USE_ITHREADS
   	if (cPADOPo->op_padix > 0) {
   	    /* No GvIN_PAD_off(cGVOPo_gv) here, because other references
  @@ -286,6 +288,7 @@
   	SvREFCNT_dec(cSVOPo->op_sv);
   	cSVOPo->op_sv = Nullsv;
   #endif
  +	}
   	break;
       case OP_METHOD_NAMED:
       case OP_CONST:
  @@ -294,7 +297,7 @@
   #ifdef USE_ITHREADS
   	/** Bug #15654
   	  Even if op_clear does a pad_free for the target of the op,
  -	  pad_free doesn't actually remove the sv that exists in the bad
  +	  pad_free doesn't actually remove the sv that exists in the pad;
   	  instead it lives on. This results in that it could be reused as 
   	  a target later on when the pad was reallocated.
   	**/
  @@ -674,10 +677,14 @@
   	else {
   	    if (ckWARN(WARN_VOID)) {
   		useless = "a constant";
  +		/* don't warn on optimised away booleans, eg 
  +		 * use constant Foo, 5; Foo || print; */
  +		if (cSVOPo->op_private & OPpCONST_SHORTCIRCUIT)
  +		    useless = 0;
   		/* the constants 0 and 1 are permitted as they are
   		   conventionally used as dummies in constructs like
   		        1 while some_condition_with_side_effects;  */
  -		if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0))
  +		else if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0))
   		    useless = 0;
   		else if (SvPOK(sv)) {
                     /* perl4's way of mixing documentation and code
  @@ -1108,7 +1115,7 @@
   	break;
   
       case OP_AELEMFAST:
  -	localize = 1;
  +	localize = -1;
   	PL_modcount++;
   	break;
   
  @@ -1673,6 +1680,7 @@
   Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
   {
       OP *o;
  +    bool ismatchop = 0;
   
       if (ckWARN(WARN_MISC) &&
         (left->op_type == OP_RV2AV ||
  @@ -1697,10 +1705,14 @@
   	no_bareword_allowed(right);
       }
   
  -    if (!(right->op_flags & OPf_STACKED) &&
  -       (right->op_type == OP_MATCH ||
  +    ismatchop = right->op_type == OP_MATCH ||
   	right->op_type == OP_SUBST ||
  -	right->op_type == OP_TRANS)) {
  +		right->op_type == OP_TRANS;
  +    if (ismatchop && right->op_private & OPpTARGET_MY) {
  +	right->op_targ = 0;
  +	right->op_private &= ~OPpTARGET_MY;
  +    }
  +    if (!(right->op_flags & OPf_STACKED) && ismatchop) {
   	right->op_flags |= OPf_STACKED;
   	if (right->op_type != OP_MATCH &&
               ! (right->op_type == OP_TRANS &&
  @@ -1764,9 +1776,6 @@
   Perl_block_start(pTHX_ int full)
   {
       int retval = PL_savestack_ix;
  -    /* If there were syntax errors, don't try to start a block */
  -    if (PL_yynerrs) return retval;
  -
       pad_block_start(full);
       SAVEHINTS();
       PL_hints &= ~HINT_BLOCK_SCOPE;
  @@ -1788,8 +1797,6 @@
   {
       int needblockscope = PL_hints & HINT_BLOCK_SCOPE;
       OP* retval = scalarseq(seq);
  -    /* If there were syntax errors, don't try to close a block */
  -    if (PL_yynerrs) return retval;
       LEAVE_SCOPE(floor);
       PL_compiling.op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
       if (needblockscope)
  @@ -1801,8 +1808,16 @@
   STATIC OP *
   S_newDEFSVOP(pTHX)
   {
  +    I32 offset = pad_findmy("$_");
  +    if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
       return newSVREF(newGVOP(OP_GV, 0, PL_defgv));
   }
  +    else {
  +	OP *o = newOP(OP_PADSV, 0);
  +	o->op_targ = offset;
  +	return o;
  +    }
  +}
   
   void
   Perl_newPROG(pTHX_ OP *o)
  @@ -1823,6 +1838,7 @@
   	if (o->op_type == OP_STUB) {
   	    PL_comppad_name = 0;
   	    PL_compcv = 0;
  +	    FreeOp(o);
   	    return;
   	}
   	PL_main_root = scope(sawparens(scalarvoid(o)));
  @@ -1864,18 +1880,26 @@
   	    && PL_bufptr > PL_oldbufptr && PL_bufptr[-1] == ',')
   	{
   	    char *s = PL_bufptr;
  -	    int sigil = 0;
  +	    bool sigil = FALSE;
   
   	    /* some heuristics to detect a potential error */
  -	    while (*s && (strchr(", \t\n", *s)
  -			|| (strchr("@$%*", *s) && ++sigil) ))
  -		s++;
  -	    if (sigil) {
  -		while (*s && (isALNUM(*s) || UTF8_IS_CONTINUED(*s)
  -			    || strchr("@$%*, \t\n", *s)))
  +	    while (*s && (strchr(", \t\n", *s)))
   		    s++;
   
  -		if (*s == ';' || *s == '=')
  +	    while (1) {
  +		if (*s && strchr("@$%*", *s) && *++s
  +		       && (isALNUM(*s) || UTF8_IS_CONTINUED(*s))) {
  +		    s++;
  +		    sigil = TRUE;
  +		    while (*s && (isALNUM(*s) || UTF8_IS_CONTINUED(*s)))
  +			s++;
  +		    while (*s && (strchr(", \t\n", *s)))
  +			s++;
  +		}
  +		else
  +		    break;
  +	    }
  +	    if (sigil && (*s == ';' || *s == '=')) {
   		    Perl_warner(aTHX_ packWARN(WARN_PARENTHESIS),
   				"Parentheses missing around \"%s\" list",
   				lex ? (PL_in_my == KEY_our ? "our" : "my")
  @@ -2005,7 +2029,7 @@
       o->op_ppaddr = PL_ppaddr[OP_RV2AV];
       o->op_flags &= ~OPf_REF;	/* treat \(1..2) like an ordinary list */
       o->op_flags |= OPf_PARENS;	/* and flatten \(1..2,3) */
  -    o->op_seq = 0;		/* needs to be revisited in peep() */
  +    o->op_opt = 0;		/* needs to be revisited in peep() */
       curop = ((UNOP*)o)->op_first;
       ((UNOP*)o)->op_first = newSVOP(OP_CONST, 0, SvREFCNT_inc(*PL_stack_sp--));
       op_free(curop);
  @@ -3334,24 +3358,43 @@
   	}
       }
       if (first->op_type == OP_CONST) {
  -	if (ckWARN(WARN_BAREWORD) && (first->op_private & OPpCONST_BARE)) {
   	    if (first->op_private & OPpCONST_STRICT)
   		no_bareword_allowed(first);
  -	    else
  +	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))) {
   	    op_free(first);
   	    *firstp = Nullop;
  +	    other->op_private |= OPpCONST_SHORTCIRCUIT;
   	    return other;
   	}
   	else {
  +	    /* check for C<my $x if 0>, or C<my($x,$y) if 0> */
  +	    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;
   	    return first;
   	}
       }
  -    else if (ckWARN(WARN_MISC) && (first->op_flags & OPf_KIDS)) {
  +    else if (ckWARN(WARN_MISC) && (first->op_flags & OPf_KIDS) &&
  +             type != OP_DOR) /* [#24076] Don't warn for <FH> err FOO. */
  +    {
   	OP *k1 = ((UNOP*)first)->op_first;
   	OP *k2 = k1->op_sibling;
   	OPCODE warnop = 0;
  @@ -3555,6 +3598,10 @@
   	}
       }
   
  +    /* if block is null, the next append_elem() would put UNSTACK, a scalar
  +     * op, in listop. This is wrong. [perl #27024] */
  +    if (!block)
  +	block = newOP(OP_NULL, 0);
       listop = append_elem(OP_LINESEQ, block, newOP(OP_UNSTACK, 0));
       o = new_logop(OP_AND, 0, &expr, &listop);
   
  @@ -3699,8 +3746,14 @@
   	    Perl_croak(aTHX_ "Can't use %s for loop variable", PL_op_desc[sv->op_type]);
       }
       else {
  +	I32 offset = pad_findmy("$_");
  +	if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
   	sv = newGVOP(OP_GV, 0, PL_defgv);
       }
  +	else {
  +	    padoff = offset;
  +	}
  +    }
       if (expr->op_type == OP_RV2AV || expr->op_type == OP_PADAV) {
   	expr = mod(force_list(scalar(ref(expr, OP_ITER))), OP_GREPSTART);
   	iterflags |= OPf_STACKED;
  @@ -3779,7 +3832,9 @@
   	op_free(label);
       }
       else {
  -	if (label->op_type == OP_ENTERSUB)
  +	/* Check whether it's going to be a goto &function */
  +	if (label->op_type == OP_ENTERSUB
  +		&& !(label->op_flags & OPf_STACKED))
   	    label = newUNOP(OP_REFGEN, 0, mod(label, OP_REFGEN));
   	o = newUNOP(type, OPf_STACKED, label);
       }
  @@ -3856,6 +3911,8 @@
   	    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);
  @@ -4154,6 +4211,8 @@
   	/* transfer PL_compcv to cv */
   	cv_undef(cv);
   	CvFLAGS(cv) = CvFLAGS(PL_compcv);
  +	if (!CvWEAKOUTSIDE(cv))
  +	    SvREFCNT_dec(CvOUTSIDE(cv));
   	CvOUTSIDE(cv) = CvOUTSIDE(PL_compcv);
   	CvOUTSIDE_SEQ(cv) = CvOUTSIDE_SEQ(PL_compcv);
   	CvOUTSIDE(PL_compcv) = 0;
  @@ -4209,6 +4268,11 @@
   			     mod(scalarseq(block), OP_LEAVESUBLV));
       }
       else {
  +	/* This makes sub {}; work as expected.  */
  +	if (block->op_type == OP_STUB) {
  +	    op_free(block);
  +	    block = newSTATEOP(0, Nullch, 0);
  +	}
   	CvROOT(cv) = newUNOP(OP_LEAVESUB, 0, scalarseq(block));
       }
       CvROOT(cv)->op_private |= OPpREFCOUNTED;
  @@ -4705,7 +4769,8 @@
   Perl_ck_concat(pTHX_ OP *o)
   {
       OP *kid = cUNOPo->op_first;
  -    if (kid->op_type == OP_CONCAT && !(kUNOP->op_first->op_flags & OPf_MOD))
  +    if (kid->op_type == OP_CONCAT && !(kid->op_private & OPpTARGET_MY) &&
  +	    !(kUNOP->op_first->op_flags & OPf_MOD))
           o->op_flags |= OPf_STACKED;
       return o;
   }
  @@ -5013,12 +5078,16 @@
   		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) &&
   	      OP_IS_FILETEST_ACCESS(o))
   	    o->op_private |= OPpFT_ACCESS;
   	}
  +	if (PL_check[kid->op_type] == MEMBER_TO_FPTR(Perl_ck_ftst)
  +		&& kid->op_type != OP_STAT && kid->op_type != OP_LSTAT)
  +	    o->op_private |= OPpFT_STACKED;
       }
       else {
   	op_free(o);
  @@ -5226,8 +5295,7 @@
   					   
   				      }
   				      if (tmpstr) {
  -					   name = savepv(SvPVX(tmpstr));
  -					   len = strlen(name);
  +					   name = SvPV(tmpstr, len);
   					   sv_2mortal(tmpstr);
   				      }
   				 }
  @@ -5322,6 +5390,7 @@
   	o->op_ppaddr = PL_ppaddr[OP_LIST];
   	cLISTOPo->op_first->op_type = OP_PUSHMARK;
   	cLISTOPo->op_first->op_ppaddr = PL_ppaddr[OP_PUSHMARK];
  +	cLISTOPo->op_first->op_targ = 0;
   	o = newUNOP(OP_ENTERSUB, OPf_STACKED,
   		    append_elem(OP_LIST, o,
   				scalar(newUNOP(OP_RV2CV, 0,
  @@ -5343,6 +5412,7 @@
       LOGOP *gwop;
       OP *kid;
       OPCODE type = o->op_type == OP_GREPSTART ? OP_GREPWHILE : OP_MAPWHILE;
  +    I32 offset;
   
       o->op_ppaddr = PL_ppaddr[OP_GREPSTART];
       NewOp(1101, gwop, 1, LOGOP);
  @@ -5374,10 +5444,17 @@
       gwop->op_ppaddr = PL_ppaddr[type];
       gwop->op_first = listkids(o);
       gwop->op_flags |= OPf_KIDS;
  -    gwop->op_private = 1;
       gwop->op_other = LINKLIST(kid);
  -    gwop->op_targ = pad_alloc(type, SVs_PADTMP);
       kid->op_next = (OP*)gwop;
  +    offset = pad_findmy("$_");
  +    if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
  +	o->op_private = gwop->op_private = 0;
  +	gwop->op_targ = pad_alloc(type, SVs_PADTMP);
  +    }
  +    else {
  +	o->op_private = gwop->op_private = OPpGREP_LEX;
  +	gwop->op_targ = o->op_targ = offset;
  +    }
   
       kid = cLISTOPo->op_first->op_sibling;
       if (!kid || !kid->op_sibling)
  @@ -5523,6 +5600,14 @@
   OP *
   Perl_ck_match(pTHX_ OP *o)
   {
  +    if (o->op_type != OP_QR) {
  +	I32 offset = pad_findmy("$_");
  +	if (offset != NOT_IN_PAD && !(PAD_COMPNAME_FLAGS(offset) & SVpad_OUR)) {
  +	    o->op_targ = offset;
  +	    o->op_private |= OPpTARGET_MY;
  +	}
  +    }
  +    if (o->op_type == OP_MATCH || o->op_type == OP_QR)
       o->op_private |= OPpRUNTIME;
       return o;
   }
  @@ -6181,6 +6266,18 @@
   }
   
   OP *
  +Perl_ck_unpack(pTHX_ OP *o)
  +{
  +    OP *kid = cLISTOPo->op_first;
  +    if (kid->op_sibling) {
  +	kid = kid->op_sibling;
  +	if (!kid->op_sibling)
  +	    kid->op_sibling = newDEFSVOP();
  +    }
  +    return ck_fun(o);
  +}
  +
  +OP *
   Perl_ck_substr(pTHX_ OP *o)
   {
       o = ck_fun(o);
  @@ -6203,25 +6300,21 @@
   {
       register OP* oldop = 0;
   
  -    if (!o || o->op_seq)
  +    if (!o || o->op_opt)
   	return;
       ENTER;
       SAVEOP();
       SAVEVPTR(PL_curcop);
       for (; o; o = o->op_next) {
  -	if (o->op_seq)
  +	if (o->op_opt)
   	    break;
  -        /* The special value -1 is used by the B::C compiler backend to indicate
  -         * that an op is statically defined and should not be freed */
  -	if (!PL_op_seqmax || PL_op_seqmax == (U16)-1)
  -	    PL_op_seqmax = 1;
   	PL_op = o;
   	switch (o->op_type) {
   	case OP_SETSTATE:
   	case OP_NEXTSTATE:
   	case OP_DBSTATE:
   	    PL_curcop = ((COP*)o);		/* for warnings */
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    break;
   
   	case OP_CONST:
  @@ -6252,7 +6345,7 @@
   		o->op_targ = ix;
   	    }
   #endif
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    break;
   
   	case OP_CONCAT:
  @@ -6270,11 +6363,11 @@
   		op_null(o->op_next);
   	    }
   	  ignore_optimization:
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    break;
   	case OP_STUB:
   	    if ((o->op_flags & OPf_WANT) != OPf_WANT_LIST) {
  -		o->op_seq = PL_op_seqmax++;
  +		o->op_opt = 1;
   		break; /* Scalar stub must produce undef.  List stub is noop */
   	    }
   	    goto nothin;
  @@ -6289,6 +6382,7 @@
   	       to peep() from mistakenly concluding that optimisation
   	       has already occurred. This doesn't fix the real problem,
   	       though (See 20010220.007). AMS 20010719 */
  +	    /* op_seq functionality is now replaced by op_opt */
   	    if (oldop && o->op_next) {
   		oldop->op_next = o->op_next;
   		continue;
  @@ -6302,25 +6396,17 @@
   		oldop->op_next = o->op_next;
   		continue;
   	    }
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    break;
   
  +	case OP_PADAV:
   	case OP_GV:
  -	    if (o->op_next->op_type == OP_RV2SV) {
  -		if (!(o->op_next->op_private & OPpDEREF)) {
  -		    op_null(o->op_next);
  -		    o->op_private |= o->op_next->op_private & (OPpLVAL_INTRO
  -							       | OPpOUR_INTRO);
  -		    o->op_next = o->op_next->op_next;
  -		    o->op_type = OP_GVSV;
  -		    o->op_ppaddr = PL_ppaddr[OP_GVSV];
  -		}
  -	    }
  -	    else if (o->op_next->op_type == OP_RV2AV) {
  -		OP* pop = o->op_next->op_next;
  +	    if (o->op_type == OP_PADAV || o->op_next->op_type == OP_RV2AV) {
  +		OP* pop = (o->op_type == OP_PADAV) ?
  +			    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)) &&
  @@ -6329,17 +6415,37 @@
   		    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);
   		    op_null(pop);
   		    o->op_flags |= pop->op_next->op_flags & OPf_MOD;
   		    o->op_next = pop->op_next->op_next;
  -		    o->op_type = OP_AELEMFAST;
   		    o->op_ppaddr = PL_ppaddr[OP_AELEMFAST];
   		    o->op_private = (U8)i;
  +		    if (o->op_type == OP_GV) {
   		    gv = cGVOPo_gv;
   		    GvAVn(gv);
   		}
  +		    else
  +			o->op_flags |= OPf_SPECIAL;
  +		    o->op_type = OP_AELEMFAST;
  +		}
  +    		o->op_opt = 1;
  +		break;
  +	    }
  +
  +	    if (o->op_next->op_type == OP_RV2SV) {
  +		if (!(o->op_next->op_private & OPpDEREF)) {
  +		    op_null(o->op_next);
  +		    o->op_private |= o->op_next->op_private & (OPpLVAL_INTRO
  +							       | OPpOUR_INTRO);
  +		    o->op_next = o->op_next->op_next;
  +		    o->op_type = OP_GVSV;
  +		    o->op_ppaddr = PL_ppaddr[OP_GVSV];
  +		}
   	    }
   	    else if ((o->op_private & OPpEARLY_CV) && ckWARN(WARN_PROTOTYPE)) {
   		GV *gv = cGVOPo_gv;
  @@ -6364,7 +6470,7 @@
   		op_null(o->op_next);
   	    }
   
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    break;
   
   	case OP_MAPWHILE:
  @@ -6377,7 +6483,7 @@
   	case OP_DORASSIGN:
   	case OP_COND_EXPR:
   	case OP_RANGE:
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    while (cLOGOP->op_other->op_type == OP_NULL)
   		cLOGOP->op_other = cLOGOP->op_other->op_next;
   	    peep(cLOGOP->op_other); /* Recursive calls are not replaced by fptr calls */
  @@ -6385,7 +6491,7 @@
   
   	case OP_ENTERLOOP:
   	case OP_ENTERITER:
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    while (cLOOP->op_redoop->op_type == OP_NULL)
   		cLOOP->op_redoop = cLOOP->op_redoop->op_next;
   	    peep(cLOOP->op_redoop);
  @@ -6400,7 +6506,7 @@
   	case OP_QR:
   	case OP_MATCH:
   	case OP_SUBST:
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    while (cPMOP->op_pmreplstart &&
   		   cPMOP->op_pmreplstart->op_type == OP_NULL)
   		cPMOP->op_pmreplstart = cPMOP->op_pmreplstart->op_next;
  @@ -6408,7 +6514,7 @@
   	    break;
   
   	case OP_EXEC:
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    if (ckWARN(WARN_SYNTAX) && o->op_next
   		&& o->op_next->op_type == OP_NEXTSTATE) {
   		if (o->op_next->op_sibling &&
  @@ -6433,7 +6539,7 @@
   	    char *key = NULL;
   	    STRLEN keylen;
   
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   
   	    if (((BINOP*)o)->op_last->op_type != OP_CONST)
   		break;
  @@ -6451,8 +6557,98 @@
               break;
           }
   
  +	case OP_SORT: {
  +	    /* make @a = sort @a act in-place */
  +
  +	    /* 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;
  +	    oright = cUNOPx(oright)->op_sibling;
  +	    if (!oright)
  +		break;
  +	    if (oright->op_type == OP_NULL) { /* skip sort block/sub */
  +		oright = cUNOPx(oright)->op_sibling;
  +	    }
  +
  +	    if (!oright ||
  +		(oright->op_type != OP_RV2AV && oright->op_type != OP_PADAV)
  +		|| oright->op_next != o
  +		|| (oright->op_private & OPpLVAL_INTRO)
  +	    )
  +		break;
  +
  +	    /* o2 follows the chain of op_nexts through the LHS of the
  +	     * assign (if any) to the aassign op itself */
  +	    o2 = o->op_next;
  +	    if (!o2 || o2->op_type != OP_NULL)
  +		break;
  +	    o2 = o2->op_next;
  +	    if (!o2 || o2->op_type != OP_PUSHMARK)
  +		break;
  +	    o2 = o2->op_next;
  +	    if (o2 && o2->op_type == OP_GV)
  +		o2 = o2->op_next;
  +	    if (!o2
  +		|| (o2->op_type != OP_PADAV && o2->op_type != OP_RV2AV)
  +		|| (o2->op_private & OPpLVAL_INTRO)
  +	    )
  +		break;
  +	    oleft = o2;
  +	    o2 = o2->op_next;
  +	    if (!o2 || o2->op_type != OP_NULL)
  +		break;
  +	    o2 = o2->op_next;
  +	    if (!o2 || o2->op_type != OP_AASSIGN
  +		    || (o2->op_flags & OPf_WANT) != OPf_WANT_VOID)
  +		break;
  +
  +	    /* check the array is the same on both sides */
  +	    if (oleft->op_type == OP_RV2AV) {
  +		if (oright->op_type != OP_RV2AV
  +		    || !cUNOPx(oright)->op_first
  +		    || cUNOPx(oright)->op_first->op_type != OP_GV
  +		    ||  cGVOPx_gv(cUNOPx(oleft)->op_first) !=
  +		       	cGVOPx_gv(cUNOPx(oright)->op_first)
  +		)
  +		    break;
  +	    }
  +	    else if (oright->op_type != OP_PADAV
  +		|| oright->op_targ != oleft->op_targ
  +	    )
  +		break;
  +
  +	    /* transfer MODishness etc from LHS arg to RHS arg */
  +	    oright->op_flags = oleft->op_flags;
  +	    o->op_private |= OPpSORT_INPLACE;
  +
  +	    /* excise push->gv->rv2av->null->aassign */
  +	    o2 = o->op_next->op_next;
  +	    op_null(o2); /* PUSHMARK */
  +	    o2 = o2->op_next;
  +	    if (o2->op_type == OP_GV) {
  +		op_null(o2); /* GV */
  +		o2 = o2->op_next;
  +	    }
  +	    op_null(o2); /* RV2AV or PADAV */
  +	    o2 = o2->op_next->op_next;
  +	    op_null(o2); /* AASSIGN */
  +
  +	    o->op_next = o2->op_next;
  +
  +	    break;
  +	}
  +	
  +
  +
   	default:
  -	    o->op_seq = PL_op_seqmax++;
  +	    o->op_opt = 1;
   	    break;
   	}
   	oldop = o;