Hey:
On Sat, Jan 2, 2016 at 7:59 PM, Derick Rethans <der...@php.net> wrote: > On Thu, 31 Dec 2015, Nikita Popov wrote: > > > On Thu, Dec 31, 2015 at 1:09 AM, Derick Rethans <der...@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/