This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
make calling of /(?{}) code blocks correct
authorDavid Mitchell <davem@iabyn.com>
Fri, 4 May 2012 15:34:01 +0000 (16:34 +0100)
committerDavid Mitchell <davem@iabyn.com>
Wed, 13 Jun 2012 12:32:52 +0000 (13:32 +0100)
commit81ed78b25c4b95fc36897169c53a46cae7104064
tree3d91e44f0977ef97b177109aaef474d53f0fec5e
parent76ac488f33062fb6944511be1ac932b9bbb66144
make calling of /(?{}) code blocks correct

Formerly, it just updated PL_comppad, set PL_op to the first op of the
code block, and did CALLRUNOPS().

This had a lot of problems, e.g. depth of recursion, and not having
anything on the context stack for die/caller/next/goto etc to see, usually
leading to segfaults.

Make it so that it uses the MULTICALL API instead. This makes it push a
new stack and a CxSUB context stack frame; it also makes us share code
rather than rolling our own.

MULTICALL had to be extended in two ways to make this work; but these have
not yet been made part of the public API. First, it had to allow changing
of the current CV while leaving the current CxSUB frame in place, and
secondly it had to allow pushing a CV with a zero increment of CvDEPTH.
This latter is to handle direct literal blocks:

    /(?{...})/

which are compiled into the same CV as the surrounding scope; therefore we
need to push the same sub twice at the same depth (usually 1), i.e.

    $ ./perl -Dstv -e'sub f { /(?{$x})/ } f'
    ...
    (29912:-e:1) gvsv(main::x)

    STACK 0: MAIN
      CX 0: BLOCK  =>
      CX 1: SUB    =>           <=== the same sub ...
      retop=leave
    STACK 1: SORT
      CX 0: SUB    => UNDEF     <==== ... as this
      retop=(null)

(note that stack 1 is misidentified as SORT; this is a bug in MULTICALl
to be fixed later).

One has to be very careful with the save stack; /(?{})/ is designed
not to introduce a new scope, so that the effects of 'local' etc
accumulate across multiple block invocations (but get popped on
backtracking). This is why we couldn't just do a POP_MULTICALL/PUSH_MULTICALL
pair to change the current CV; the former would pop the save stack too.

Note that in the current implementation, after calling out to the first
code block, we leave the CxSUB and PL_comppad value in place, on the
assumption that it may be soon re-used, and only pop the CxSUB at the end
of S_regmatch(). However, when popping the savestack on backtracking, this
will restore PL_comppad to its original value; so when calling a new code
block with the same CV, we can't rely on PL_comppad still being correct.

Also, this means that outside of a code block call, the context stack and
PL_comppad are wrong; I can't think of anything within the regex code
that could be using these; but it if it turns out not to be the case,
then we'd have to change it so that after each code block call, we pop the
CxSUB off the stack and restore PL_comppad, but without popping the save
stack.
cop.h
pp_ctl.c
regexec.c
t/re/pat_re_eval.t
t/re/reg_eval_scope.t