diff options
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r-- | Zend/zend_execute.c | 131 |
1 files changed, 60 insertions, 71 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 3bd1917539..da150e29ff 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1939,31 +1939,6 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } } -static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_offset, const zend_op_array *op_array, const zend_execute_data *execute_data) -{ - zend_brk_cont_element *jmp_to; - - do { - ZEND_ASSERT(array_offset != -1); - jmp_to = &op_array->brk_cont_array[array_offset]; - if (nest_levels > 1 && jmp_to->start >= 0) { - zend_op *brk_opline = &op_array->opcodes[jmp_to->brk]; - - if (brk_opline->opcode == ZEND_FREE) { - zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var)); - } else if (brk_opline->opcode == ZEND_FE_FREE) { - zval *var = EX_VAR(brk_opline->op1.var); - if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { - zend_hash_iterator_del(Z_FE_ITER_P(var)); - } - zval_ptr_dtor_nogc(var); - } - } - array_offset = jmp_to->parent; - } while (--nest_levels > 0); - return jmp_to; -} - #if ZEND_INTENSIVE_DEBUGGING #define CHECK_SYMBOL_TABLES() \ @@ -2384,7 +2359,66 @@ static zend_always_inline zend_generator *zend_get_running_generator(zend_execut static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */ { - int i; + if (EX(func)->op_array.T_liveliness + && op_num < EX(func)->op_array.last + && EX(func)->op_array.T_liveliness[op_num] != (uint32_t)-1) { + uint32_t *off = EX(func)->op_array.T_liveliness + EX(func)->op_array.T_liveliness[op_num]; + uint32_t *catch_off = NULL; + uint32_t var = *off; + + if (catch_op_num && EX(func)->op_array.T_liveliness[catch_op_num] != (uint32_t)-1) { + catch_off = EX(func)->op_array.T_liveliness + EX(func)->op_array.T_liveliness[catch_op_num]; + } + + do { + /* we should be safe to assume that all temporaries at catch_op_num will be present at op_num too, in same order */ + if (catch_off && *catch_off == var) { + catch_off++; + var = *(++off); + continue; + } + + if ((var & ZEND_LIVE_MASK) == ZEND_LIVE_ROPE) { + /* free incomplete rope */ + zend_string **rope; + zend_op *last; + + var = var & ~ZEND_LIVE_ROPE; + rope = (zend_string **) EX_VAR(var); + last = EX(func)->op_array.opcodes + op_num; + while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT) + || last->result.var != var) { + ZEND_ASSERT(last >= EX(func)->op_array.opcodes); + last--; + } + if (last->opcode == ZEND_ROPE_INIT) { + zend_string_release(*rope); + } else { + int j = last->extended_value; + do { + zend_string_release(rope[j]); + } while (j--); + } + } else if ((var & ZEND_LIVE_MASK) == ZEND_LIVE_SILENCE) { + /* restore previous error_reporting value */ + var = var & ~ZEND_LIVE_SILENCE; + if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(var)) != 0) { + EG(error_reporting) = Z_LVAL_P(EX_VAR(var)); + } + } else if ((var & ZEND_LIVE_MASK) == ZEND_LIVE_LOOP) { + /* free loop variables */ + var = var & ~ZEND_LIVE_LOOP; + if (Z_TYPE_P(EX_VAR(var)) != IS_ARRAY && Z_FE_ITER_P(EX_VAR(var)) != (uint32_t) -1) { + zend_hash_iterator_del(Z_FE_ITER_P(EX_VAR(var))); + } + zval_ptr_dtor_nogc(EX_VAR(var)); + } else { + zval_ptr_dtor_nogc(EX_VAR(var)); + } + var = *(++off); + } while (var != (uint32_t)-1); + } + if (UNEXPECTED(EX(call))) { zend_execute_data *call = EX(call); zend_op *opline = EX(func)->op_array.opcodes + op_num; @@ -2498,51 +2532,6 @@ static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data call = EX(call); } while (call); } - - for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) { - const zend_brk_cont_element *brk_cont = &EX(func)->op_array.brk_cont_array[i]; - if (brk_cont->start < 0) { - continue; - } else if (brk_cont->start > op_num) { - /* further blocks will not be relevant... */ - break; - } else if (op_num < brk_cont->brk) { - if (!catch_op_num || catch_op_num >= brk_cont->brk) { - zend_op *brk_opline = &EX(func)->op_array.opcodes[brk_cont->brk]; - - if (brk_opline->opcode == ZEND_FREE) { - zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var)); - } else if (brk_opline->opcode == ZEND_FE_FREE) { - zval *var = EX_VAR(brk_opline->op1.var); - if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { - zend_hash_iterator_del(Z_FE_ITER_P(var)); - } - zval_ptr_dtor_nogc(var); - } else if (brk_opline->opcode == ZEND_ROPE_END) { - zend_string **rope = (zend_string **) EX_VAR(brk_opline->op1.var); - zend_op *last = EX(func)->op_array.opcodes + op_num; - while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT) - || last->result.var != brk_opline->op1.var) { - ZEND_ASSERT(last >= EX(func)->op_array.opcodes); - last--; - } - if (last->opcode == ZEND_ROPE_INIT) { - zend_string_release(*rope); - } else { - int j = last->extended_value; - do { - zend_string_release(rope[j]); - } while (j--); - } - } else if (brk_opline->opcode == ZEND_END_SILENCE) { - /* restore previous error_reporting value */ - if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) { - EG(error_reporting) = Z_LVAL_P(EX_VAR(brk_opline->op1.var)); - } - } - } - } - } } /* }}} */ |