diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 0c6ab6c5cbc8c..cc22e7375a8c1 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2576,7 +2576,34 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } /* THROW and EXIT may be used in the middle of BB */ /* don't generate code for the rest of BB */ - i = end; + + /* Skip current opline for call_level computation + * Don't include last opline because end of loop already checks call level of last opline */ + i++; + for (; i < end; i++) { + opline = op_array->opcodes + i; + switch (opline->opcode) { + case ZEND_INIT_FCALL: + case ZEND_INIT_FCALL_BY_NAME: + case ZEND_INIT_NS_FCALL_BY_NAME: + case ZEND_INIT_METHOD_CALL: + case ZEND_INIT_DYNAMIC_CALL: + case ZEND_INIT_STATIC_METHOD_CALL: + case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL: + case ZEND_INIT_USER_CALL: + case ZEND_NEW: + call_level++; + break; + case ZEND_DO_FCALL: + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: + case ZEND_CALLABLE_CONVERT: + call_level--; + break; + } + } + opline = op_array->opcodes + i; break; /* stackless execution */ case ZEND_INCLUDE_OR_EVAL: diff --git a/ext/opcache/tests/jit/gh16879.phpt b/ext/opcache/tests/jit/gh16879.phpt new file mode 100644 index 0000000000000..7a17fd34135b2 --- /dev/null +++ b/ext/opcache/tests/jit/gh16879.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-16879 (JIT dead code skipping does not update call_level) +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=32M +opcache.jit=1235 +opcache.jit_hot_func=1 +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught UnhandledMatchError: Unhandled match case 0 in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d