Re: Line numbers for "finally"
| From: | Xinchen Hui | Date: | Sat, 02 Jan 2016 14:12:01 +0000 |
| Subject: | Re: Line numbers for "finally" | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-89965@lists.php.net to get a copy of this message | ||
Hey:
On Sat, Jan 2, 2016 at 7:59 PM, Derick Rethans <derick@php.net> wrote:
> On Thu, 31 Dec 2015, Nikita Popov wrote:
>
> > On Thu, Dec 31, 2015 at 1:09 AM, Derick Rethans <derick@php.net> wrote:
> >
> > > On Thu, 31 Dec 2015, Nikita Popov wrote:
> > >
> > > > For PHP 7 only: FAST_CALL always jumps to op1. op2 is not a jmp
> > > > addr, it's a try_catch_array offset. For FAST_RET there are no
> > > > jump addresses encoded in the opline. It will either jump back to
> > > > one past the invoking FAST_CALL (of which there may be multiple),
> > > > or (if finally is executed due to an uncaught exception) it will
> > > > jump back to the next applicable catch or finally or leave the
> > > > function.
> > >
> > > Hmm, that's more complicated than I thought. How would I fix that
> > > code? (PR welcome :D )
> >
> > I don't know what you need this for, but maybe you can use the same
> > "good enough" approximation we use for our internal control flow
> > analysis, namely simply say that FAST_CALL either jumps to op1 or to
> > the next instruction, while FAST_RET is treated as a terminator
> > instruction (like RETURN). This does not accurately model control
> > flow, but it may be sufficient for your purposes.
>
> I need to analyse every possible branch, and path through the code in
> order to do dead code analysis (for which I think your simplified
> option works), but also for path coverage, for which I don't think your
> algorithm works. Xinchen alluded on IRC:
>
> 15:21 <@laruence> Derick, it used for calling "finally block"
> 15:22 <@laruence> it has the entry opline of finally block as opline->op1
> 15:22 <@laruence> and in the end of finally block ,there always be a
> ZEND_FAST_RET opline, which will return to proper address
> after finally block codes is executed
>
> To me that indicates that the FAST_RET can jump back to any location
> where FAST_CALL was *called* from (+1)?
>
> In any case, I think my current code does what you describe, except for
> FAST_RET, as that does not act like a RETURN - is there any reason why
> my approach wouldn't work?
>
> Some more observations and questions:
>
> FAST_CALL:
> *jmp1 = XDEBUG_ZNODE_JMP_LINE(opcode.op1, position, base_address);
>
> - But what do do for *jmp2 - if extended_value is set?
if extended_value is set(FROM_FINALLY) that means this finally block is
inside another finally block
I am not sure what *jmp2 means here? ZEND_FAST_CALL always jmp to one
place. but in case FROM_FINALLY it has outer FAST_CALL's opline in op2 .
> - I can't come up with PHP code that sets extended_value though. Can you?
>
try {
} finally {
try {
} finally /* this fast_call will set with FROM_FINALLY*/
{}
}
>
> FAST_RET:
> *jmp1 = position + 1;
>
> - But you indicate that that really should be *jmp1 = XDEBUG_JMP_EXIT?
>
> - Or, it should jump back to something else?
> - But how do I know to which possible opline(s) it is going to jump back
> to?
- Is there a list of these somewhere?
I am afarid there is not, let me try to summary it(I will try to make it
clean, but mine poor english :<):
ZEND_FAST_CALL opcode is used for set a proper return address for
ZEND_FAST_RET.
there are two ways can entry a finally block, ZEND_FAST_CALL and
ZEND_HANDLE_EXCEPTION:
1) ZEND_FAST_CALL: it set the return address to it's self (it will always
follow by a JMP, which will JMP to end of finall block).
2) ZEND_HANDLE_EXCEPTION, if there is catch block then jmp to it(in the end
of the catch block there will be a JMP to finally block), if no catch block
is matched and there is a finally block, then set fast_call_var->u2.lineno
== -1, and stash the EG(exception) into Z_OBJ_P(fast_call_var), then jmp to
the finally block.
for FAST_RET:
in fast_ret, if fast_call_var->u2.lineno != -1, then it means a jmp
address, simply jmp to it.
if fast_call->u2.lineno == -1, then there must be a un-handle
exception(stored in Z_OBJ_P(fast_call_var)), so:
if RET_TO_FINALLY(see blow), means there is another finally block needs
to be run, jmp to the ZEND_FAST_CALL opline of that finally block, in
which opline handle, if opline->extended_value
== ZEND_FAST_CALL_FROM_FINALLY(see below) and obviously current
Z_OBJ_P(fast_call_var) is set, then goes into the finally block behavior
like the way ZEND_HANDLE_EXCEPTION did, which is set the
fast_call->u2.lineno to -1, and jmp into the finally block.
otherwise, restore the exception, then goes like a new exception is
throw(jmp to a CATCH block or leave current function which will result
ZEND_HANDLE_EXCEPTION again).
- I can't come up with PHP code that sets extended_value here either.
>
try {
try {
} finally {
} /* this fast_ret will set to RET_TO_CATCH */
} catch () {
}
try {
try {
} finally {
} /* this fast_ret will set to RET_TO_FINALLY */
} finally {
}
thanks
> Can you?
thanks
>
> cheers,
> Derick
>
--
Xinchen Hui
@Laruence
http://www.laruence.com/