develooper Front page | perl.perl5.porters | Postings from March 2003

PROPOSAL: my $x if $false; and lexical initialisation

Thread Next
From:
Dave Mitchell
Date:
March 1, 2003 10:30
Subject:
PROPOSAL: my $x if $false; and lexical initialisation
Message ID:
20030301182714.B23347@fdgroup.com
There has been a long-standing bug of the form

    my $x if $false;

which causes odd things to happen. The problem lies in the fact
that 'my $x' is compiled into the op

	padsv(targ=N, OPpLVAL_INTRO),

which has the run-time effect of

    SAVECLEARSV(PAD_SVl(PL_op->op_targ)

ie make a note to free the lexical on scope exit. When the condition is
false, the padsv() op is skipped, the lexical isn't freed on scope exit,
and its old value is still there on the next call to the sub or loop.

My proposal is to move all the SAVECLEARSV() calls from the pad* ops
to the nearest preceeding cop, ie nextstate or dbstate.

I believe this will remove the bug and may also make things faster.

I have written some cobbled-together proof-of-concept test code, the
patch for which I include below.

The idea is that when peep() sees a pad* op, it removes the OPpLVAL_INTRO
flag from the pad op, and appends the op's target index to a list
stored in the last COP seen by peep().

Questions:

1) Is this idea sound in principle, or am I overlooking some semantics
that could do nasty things? (my trial patch passes all tests except for
Storable and some B::*'s, which gives me some hope... :-)

2) Is the best place to do this in peep()?

3) What's the best way to store a list of integers in a COP? I'm assuming
I'll add an int* pointer and len to the struct cop, then malloc (and if
necessary grow) an int array.

4) How can the unneeded pad* ops be optimised away for a bare 'my $x;' or
'my (...);', since they are not needed if they're not part of an
expression?

Even better, how would I optimise away both the padsv ops and the
intervening nextstate op in 'my $x; my $y;' ?

5) Since peep() sometimes sets PL_curcop to point to ops that have been
optimised away, I found I needed a separate global var that gets updated
by peep() similar to PL_curcop, but which doesn't get updated for null-ed
cops. is there a better way of doing this?

6) What is the average air-speed velocity of a swallow?

As you may be able to tell, ops and the optimiser aren't really my thing!

Dave.

-- 
To collect all the latest movies, simply place an unprotected ftp server
on the Internet, and wait for the disk to fill....


diff -up '18793.ORIG/cop.h' '18793/cop.h'
Index: ./cop.h
--- ./cop.h	Sat Mar  1 12:38:51 2003
+++ ./cop.h	Sat Mar  1 15:42:34 2003
@@ -27,6 +27,8 @@ struct cop {
     line_t      cop_line;       /* line # of this command */
     SV *	cop_warnings;	/* lexical warnings bitmask */
     SV *	cop_io;		/* lexical IO defaults */
+    int		cop_targ_count;	/* XXX */
+    int		cop_targs[100];	/* XXX */
 };
 
 #define Nullcop Null(COP*)
diff -up '18793.ORIG/intrpvar.h' '18793/intrpvar.h'
Index: ./intrpvar.h
--- ./intrpvar.h	Sat Mar  1 12:38:51 2003
+++ ./intrpvar.h	Sat Mar  1 17:31:32 2003
@@ -499,6 +499,7 @@ PERLVARI(Iin_load_module, int, 0)	/* to 
 PERLVAR(Iunicode, U32)	/* Unicode features: $ENV{PERL_UNICODE} or -C */
 
 PERLVAR(Isignals, U32)	/* Using which pre-5.8 signals */
+PERLVAR(IXXXpadcop, COP*)	/* cop for storing pad targets */
 
 /* New variables must be added to the very end, before this comment,
  * for binary compatibility (the offsets of the old members must not change).
diff -up '18793.ORIG/op.c' '18793/op.c'
Index: ./op.c
--- ./op.c	Sat Mar  1 12:38:51 2003
+++ ./op.c	Sat Mar  1 17:50:22 2003
@@ -21,7 +21,7 @@
 #include "perl.h"
 #include "keywords.h"
 
-#define CALL_PEEP(o) CALL_FPTR(PL_peepp)(aTHX_ o)
+#define CALL_PEEP(o) PL_XXXpadcop = 0; CALL_FPTR(PL_peepp)(aTHX_ o)
 
 #if defined(PL_OP_SLAB_ALLOC)
 
@@ -6060,9 +6060,23 @@ Perl_peep(pTHX_ register OP *o)
 	case OP_NEXTSTATE:
 	case OP_DBSTATE:
 	    PL_curcop = ((COP*)o);		/* for warnings */
+	    PL_XXXpadcop = (COP*)o;		/* for pad targets */
 	    o->op_seq = PL_op_seqmax++;
+	    ((COP*)o)->cop_targ_count = 0;
 	    break;
 
+	case OP_PADSV:
+	    /* XXX do for AV etc too */
+	    if (o->op_flags & OPf_MOD && o->op_private & OPpLVAL_INTRO) {
+		assert(PL_XXXpadcop);
+		assert(PL_XXXpadcop->cop_targ_count < 100);
+		PL_XXXpadcop->cop_targs[PL_XXXpadcop->cop_targ_count++]
+		    = o->op_targ;
+		o->op_flags &= ~OPf_MOD;
+		o->op_private &= ~OPpLVAL_INTRO;
+		/* XXX optimise away this op if not part of expr */
+	    }
+	    break;
 	case OP_CONST:
 	    if (cSVOPo->op_private & OPpCONST_STRICT)
 		no_bareword_allowed(o);
diff -up '18793.ORIG/pp_ctl.c' '18793/pp_ctl.c'
Index: ./pp_ctl.c
--- ./pp_ctl.c	Sat Mar  1 12:38:52 2003
+++ ./pp_ctl.c	Sat Mar  1 17:53:29 2003
@@ -1657,10 +1657,13 @@ PP(pp_lineseq)
 
 PP(pp_dbstate)
 {
+    int i;
     PL_curcop = (COP*)PL_op;
     TAINT_NOT;		/* Each statement is presumed innocent */
     PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
     FREETMPS;
+    for (i=0; i<PL_curcop->cop_targ_count; i++)
+	SAVECLEARSV(PAD_SVl(PL_curcop->cop_targs[i]));
 
     if (PL_op->op_flags & OPf_SPECIAL /* breakpoint */
 	    || SvIV(PL_DBsingle) || SvIV(PL_DBsignal) || SvIV(PL_DBtrace))
diff -up '18793.ORIG/pp_hot.c' '18793/pp_hot.c'
Index: ./pp_hot.c
--- ./pp_hot.c	Sat Mar  1 12:38:52 2003
+++ ./pp_hot.c	Sat Mar  1 17:53:12 2003
@@ -30,10 +30,13 @@ PP(pp_const)
 
 PP(pp_nextstate)
 {
+    int i;
     PL_curcop = (COP*)PL_op;
     TAINT_NOT;		/* Each statement is presumed innocent */
     PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
     FREETMPS;
+    for (i=0; i<PL_curcop->cop_targ_count; i++)
+	SAVECLEARSV(PAD_SVl(PL_curcop->cop_targs[i]));
     return NORMAL;
 }
 
@@ -194,14 +197,10 @@ PP(pp_padsv)
 {
     dSP; dTARGET;
     XPUSHs(TARG);
-    if (PL_op->op_flags & OPf_MOD) {
-	if (PL_op->op_private & OPpLVAL_INTRO)
-	    SAVECLEARSV(PAD_SVl(PL_op->op_targ));
-        else if (PL_op->op_private & OPpDEREF) {
-	    PUTBACK;
-	    vivify_ref(PAD_SVl(PL_op->op_targ), PL_op->op_private & OPpDEREF);
-	    SPAGAIN;
-	}
+    if (PL_op->op_flags & OPf_MOD && PL_op->op_private & OPpDEREF) {
+	PUTBACK;
+	vivify_ref(PAD_SVl(PL_op->op_targ), PL_op->op_private & OPpDEREF);
+	SPAGAIN;
     }
     RETURN;
 }

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About