develooper Front page | perl.perl5.porters | Postings from January 2001

Re: [PATCH] lvalue hash and array elements

Thread Previous | Thread Next
From:
Simon Cozens
Date:
January 3, 2001 15:41
Subject:
Re: [PATCH] lvalue hash and array elements
Message ID:
20010103234103.A27521@deep-dark-truthful-mirror.perlhacker.org
On Wed, Jan 03, 2001 at 03:15:14PM -0800, Stephen McCamant wrote:
> Lvalue subs are a neat feature, but it would be nice if they could be
> implemented without a big performance hit for programs that don't use
> them. (The `fast' in the name of that function, and the `hot' in the
> name of the file, are meant as sort of a hint :-)). 

I've coded the test to be as quickly eliminative of non-lv cases as possible.

> In a case like this, the important thing to think about is what decisions
> can be made at compile time (i.e. in op.c) rather than at run time (pp*.c).
> Your LVRET mixes up static compile time decisions (based on op_next and
> op_next->op_type) and dynamic runtime ones (the stuff with
> op_next->cxstack). 

I've thought long and hard about this, and spent quite a few days on it. You
CANNOT tell at compile time whether an op (say, aelem) would be used as a
return value. You really can't do it. Believe me. I have pictures of op trees
papered all over my walls. There's nothing that distinguishes a return value
op from something that can't be used as a return value. Try it. Try finding a
way to programmatically find out what will be the return value from this, at
compile time:

sub foo :lvalue { if (time) { return $x } else { ; time ? $z = $y{$x} : $z } }

Even finding the *possible* return values just by looking at the tree is
highly non-trivial, and I haven't even used goto yet. And *that*'s a
simple subroutine. 

You *have* to do this at runtime. And at runtime, something is being used
as a return value if i) its next op is "return" or ii) its next op is 
"leavesub" or (in the case we're interested in) "leavesublv". And that's
exactly what I'm catching.

> If I'm reading the grouping right, you might also
> have correctness problems -- it looks like you only do the runtime
> check before a OP_RETURN, and not before an OP_LEAVESUBLV
> but this means that every call to a sub with an lvalue attribute treats its
> last expression in an lvalue context, even if the sub isn't called in one,
> which could lead for instance to unintended hash vivifications. 

So you're saying the code should be:

#define LVRET (PL_op->op_next && (PL_op->op_next->op_type == OP_LEAVESUBLV || \
            (PL_op->op_next->op_type == OP_RETURN) && ( \
            (&cxstack[cxstack_ix])->blk_sub.lval && \
            CvLVALUE((&cxstack[cxstack_ix])->blk_sub.cv))))

?

I think I could believe that.

Could you provide an example of a test failure which that would fix?

> All that you can do at compile time is figure out which ops might be the
> return values of lvalue subs

That is *all* you can do. And you can only tell which *might* be return
values. And usually not even that. *Any* op might be the return value. Trying
to figure it out at compile time *will not work*.

> , but you if only look at the context stack for them, the
> overhead for non-lvalue programs would be at most a single flag check
> (or zero, if you made separate pp functions).

Are you sure you mean this? I *am* looking at the context stack for them.

-- 
>Almost any animal is capable learning a stimulus/response association,
>given enough repetition.
Experimental observation suggests that this isn't true if double-clicking
is involved. - Lionel, Malcolm Ray, asr.

Thread Previous | 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