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

Re: [PATCH] lvalue hash and array elements

Thread Previous | Thread Next
From:
Stephen McCamant
Date:
January 3, 2001 15:15
Subject:
Re: [PATCH] lvalue hash and array elements
Message ID:
14931.40662.783428.499090@soda.csua.berkeley.edu
>>>>> "SC" == Simon Cozens <simon@cozens.net> writes:

SC> Continuing the lvalue implementation blitz:
[ patch excerpts ]
SC> --- pp.h~	Tue Jan  2 19:56:39 2001
SC> +++ pp.h	Tue Jan  2 20:04:17 2001
SC> +#define LVRET (PL_op->op_next &&
                    (PL_op->op_next->op_type == OP_LEAVESUBLV || \
SC> +            (PL_op->op_next->op_type == OP_RETURN && ( \
SC> +            (&cxstack[cxstack_ix])->blk_sub.lval && \
SC> +            CvLVALUE((&cxstack[cxstack_ix])->blk_sub.cv)))))
SC> --- pp_hot.c~	Tue Jan  2 19:46:30 2001
SC> +++ pp_hot.c	Tue Jan  2 22:23:12 2001
SC>  PP(pp_aelemfast)
SC>  {
SC>      djSP;
SC>      AV *av = GvAV(cGVOP_gv);
SC> -    U32 lval = PL_op->op_flags & OPf_MOD;
SC> +    U32 lval = (PL_op->op_flags & OPf_MOD) || LVRET;
SC>      SV** svp = av_fetch(av, PL_op->op_private, lval);
SC>      SV *sv = (svp ? *svp : &PL_sv_undef);
SC>      EXTEND(SP, 1);
...

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 :-)). 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). 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, presumably
since there's no OP_RETURNLV, 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. All that you can do at
compile time is figure out which ops might be the return values of
lvalue subs, 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). It would be pretty easy, 
I'd say, to move the compile-time checks from LVRET into peep() cases
for OP_*ELEM, though in the long term it would probably be cleaner to
use mod() with (say) type == OP_LEAVESUBLV (called from newATTRSUB()
and a not-yet-present ck_return). In the case of OP_AELEMFAST you can
also just change the check in peep() so that lookups that could be an
lvalue return value are always just regular OP_AELEMs.

 -- Stephen `waiting for (func)[5,6] = (func)[6,5]' McCamant


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