diff options
-rw-r--r-- | Zend/Makefile.am | 2 | ||||
-rw-r--r-- | Zend/Zend.dsp | 4 | ||||
-rw-r--r-- | Zend/ZendTS.dsp | 4 | ||||
-rw-r--r-- | Zend/tests/list_destructuring_to_special_variables.phpt | 49 | ||||
-rw-r--r-- | Zend/zend_compile.c | 31 | ||||
-rw-r--r-- | Zend/zend_dynamic_array.c | 72 | ||||
-rw-r--r-- | Zend/zend_dynamic_array.h | 47 | ||||
-rw-r--r-- | Zend/zend_execute.c | 49 | ||||
-rw-r--r-- | Zend/zend_static_allocator.c | 84 | ||||
-rw-r--r-- | Zend/zend_static_allocator.h | 55 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 87 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 1138 | ||||
-rw-r--r-- | Zend/zend_vm_gen.php | 24 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | ext/opcache/Optimizer/block_pass.c | 2 | ||||
-rw-r--r-- | ext/standard/basic_functions.h | 4 | ||||
-rw-r--r-- | ext/standard/php_var.h | 109 | ||||
-rw-r--r-- | ext/standard/var.c | 92 | ||||
-rw-r--r-- | win32/build/config.w32 | 2 | ||||
-rw-r--r-- | win32/build/projectgen.js | 1 |
20 files changed, 716 insertions, 1142 deletions
diff --git a/Zend/Makefile.am b/Zend/Makefile.am index 65c4113497..2a76db36b1 100644 --- a/Zend/Makefile.am +++ b/Zend/Makefile.am @@ -8,7 +8,7 @@ noinst_LTLIBRARIES=libZend.la libZend_la_SOURCES=\ zend_language_parser.y zend_language_scanner.l \ zend_ini_parser.y zend_ini_scanner.l \ - zend_alloc.c zend_compile.c zend_constants.c zend_dynamic_array.c \ + zend_alloc.c zend_compile.c zend_constants.c \ zend_execute.c zend_execute_API.c zend_highlight.c zend_llist.c \ zend_vm_opcodes.c zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ diff --git a/Zend/Zend.dsp b/Zend/Zend.dsp index c1b3f2a9f7..717580c5a3 100644 --- a/Zend/Zend.dsp +++ b/Zend/Zend.dsp @@ -143,10 +143,6 @@ SOURCE=.\zend_default_classes.c # End Source File
# Begin Source File
-SOURCE=.\zend_dynamic_array.c
-# End Source File
-# Begin Source File
-
SOURCE=.\zend_execute.c
# End Source File
# Begin Source File
diff --git a/Zend/ZendTS.dsp b/Zend/ZendTS.dsp index 4c6ef92465..d452221d3a 100644 --- a/Zend/ZendTS.dsp +++ b/Zend/ZendTS.dsp @@ -168,10 +168,6 @@ SOURCE=.\zend_default_classes.c # End Source File
# Begin Source File
-SOURCE=.\zend_dynamic_array.c
-# End Source File
-# Begin Source File
-
SOURCE=.\zend_exceptions.c
# End Source File
# Begin Source File
diff --git a/Zend/tests/list_destructuring_to_special_variables.phpt b/Zend/tests/list_destructuring_to_special_variables.phpt new file mode 100644 index 0000000000..4418c967c2 --- /dev/null +++ b/Zend/tests/list_destructuring_to_special_variables.phpt @@ -0,0 +1,49 @@ +--TEST-- +list() can be used to destructure to string offsets, __set and ArrayAccess::offsetSet +--FILE-- +<?php + +class Obj { + public $values = []; + public function __set($name, $value) { + $this->values[$name] = $value; + } +} + +class Arr implements ArrayAccess { + public $values = []; + public function offsetSet($name, $value) { + $this->values[$name] = $value; + } + public function offsetGet($name) {} + public function offsetExists($name) {} + public function offsetUnset($name) {} +} + +$str = 'ab'; +list($str[0], $str[1]) = ['x', 'y']; +var_dump($str); + +$obj = new Obj; +list($obj->foo, $obj->bar) = ['foo', 'bar']; +var_dump($obj->values); + +$arr = new Arr; +list($arr['foo'], $arr['bar']) = ['foo', 'bar']; +var_dump($arr->values); + +?> +--EXPECT-- +string(2) "xy" +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b88f329eaf..439ae83547 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2067,6 +2067,17 @@ static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t /* }}} */ void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC); +void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC); + +static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */ +{ + znode dummy_node; + zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast, + zend_ast_create_znode(value_node)); + zend_compile_assign(&dummy_node, assign_ast TSRMLS_CC); + zend_do_free(&dummy_node TSRMLS_CC); +} +/* }}} */ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */ { @@ -2227,7 +2238,7 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n for (i = 0; i < list->children; ++i) { zend_ast *var_ast = list->child[i]; - znode fetch_result, dim_node, var_node, assign_result; + znode fetch_result, dim_node; zend_op *opline; if (var_ast == NULL) { @@ -2246,13 +2257,9 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n opline->extended_value |= ZEND_FETCH_ADD_LOCK; if (var_ast->kind != ZEND_AST_LIST) { - if (is_this_fetch(var_ast)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); - } - zend_compile_var(&var_node, var_ast, BP_VAR_W TSRMLS_CC); - zend_emit_op(&assign_result, ZEND_ASSIGN, &var_node, &fetch_result TSRMLS_CC); - zend_do_free(&assign_result TSRMLS_CC); + zend_emit_assign_znode(var_ast, &fetch_result TSRMLS_CC); } else { + znode assign_result; zend_compile_list_assign(&assign_result, var_ast, &fetch_result TSRMLS_CC); zend_do_free(&assign_result TSRMLS_CC); } @@ -2357,16 +2364,6 @@ void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ } /* }}} */ -static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */ -{ - znode dummy_node; - zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast, - zend_ast_create_znode(value_node)); - zend_compile_assign(&dummy_node, assign_ast TSRMLS_CC); - zend_do_free(&dummy_node TSRMLS_CC); -} -/* }}} */ - void zend_compile_assign_ref(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ { zend_ast *target_ast = ast->child[0]; diff --git a/Zend/zend_dynamic_array.c b/Zend/zend_dynamic_array.c deleted file mode 100644 index db81b00a73..0000000000 --- a/Zend/zend_dynamic_array.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend Engine | - +----------------------------------------------------------------------+ - | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) | - +----------------------------------------------------------------------+ - | This source file is subject to version 2.00 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.zend.com/license/2_00.txt. | - | If you did not receive a copy of the Zend license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@zend.com so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Andi Gutmans <andi@zend.com> | - | Zeev Suraski <zeev@zend.com> | - +----------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "zend.h" - -typedef struct _dynamic_array { - char *array; - unsigned int element_size; - unsigned int current; - unsigned int allocated; -} dynamic_array; - -ZEND_API int zend_dynamic_array_init(dynamic_array *da, unsigned int element_size, unsigned int size) -{ - da->element_size = element_size; - da->allocated = size; - da->current = 0; - da->array = (char *) emalloc(size*element_size); - if (da->array == NULL) { - return 1; - } - return 0; -} - -ZEND_API void *zend_dynamic_array_push(dynamic_array *da) -{ - if (da->current == da->allocated) { - da->allocated *= 2; - da->array = (char *) erealloc(da->array, da->allocated*da->element_size); - } - return (void *)(da->array+(da->current++)*da->element_size); -} - -ZEND_API void *zend_dynamic_array_pop(dynamic_array *da) -{ - return (void *)(da->array+(--(da->current))*da->element_size); - -} - -ZEND_API void *zend_dynamic_array_get_element(dynamic_array *da, unsigned int index) -{ - if (index >= da->current) { - return NULL; - } - return (void *)(da->array+index*da->element_size); -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/Zend/zend_dynamic_array.h b/Zend/zend_dynamic_array.h deleted file mode 100644 index e69eb18768..0000000000 --- a/Zend/zend_dynamic_array.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend Engine | - +----------------------------------------------------------------------+ - | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) | - +----------------------------------------------------------------------+ - | This source file is subject to version 2.00 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.zend.com/license/2_00.txt. | - | If you did not receive a copy of the Zend license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@zend.com so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Andi Gutmans <andi@zend.com> | - | Zeev Suraski <zeev@zend.com> | - +----------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef ZEND_DYNAMIC_ARRAY_H -#define ZEND_DYNAMIC_ARRAY_H - -typedef struct _dynamic_array { - char *array; - unsigned int element_size; - unsigned int last_used; - unsigned int allocated; -} dynamic_array; - -BEGIN_EXTERN_C() -ZEND_API int zend_dynamic_array_init(dynamic_array *da, unsigned int element_size, unsigned int size); -ZEND_API void *zend_dynamic_array_push(dynamic_array *da); -ZEND_API void *zend_dynamic_array_pop(dynamic_array *da); -ZEND_API void *zend_dynamic_array_get_element(dynamic_array *da, unsigned int index); -END_EXTERN_C() - -#endif /* ZEND_DYNAMIC_ARRAY_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 700b986d61..031ba54d69 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -667,17 +667,17 @@ static inline void zend_assign_to_object(zval *retval, zval *object_ptr, zval *p zval *object = object_ptr; ZVAL_DEREF(object); - if (Z_TYPE_P(object) != IS_OBJECT) { - if (object == &EG(error_zval)) { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(object == &EG(error_zval))) { if (retval) { ZVAL_NULL(retval); } FREE_OP(free_value); return; } - if (Z_TYPE_P(object) == IS_NULL || + if (EXPECTED(Z_TYPE_P(object) == IS_NULL || Z_TYPE_P(object) == IS_FALSE || - (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) { + (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) { zend_object *obj; zval_ptr_dtor(object); @@ -1021,7 +1021,7 @@ static zend_always_inline zval *zend_fetch_dimension_address(zval *result, zval fetch_from_array: if (dim == NULL) { retval = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); - if (retval == NULL) { + if (UNEXPECTED(retval == NULL)) { zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied"); retval = &EG(error_zval); } @@ -1030,11 +1030,8 @@ fetch_from_array: } if (is_ref) { ZVAL_MAKE_REF(retval); - Z_ADDREF_P(retval); - ZVAL_REF(result, Z_REF_P(retval)); - } else { - ZVAL_INDIRECT(result, retval); } + ZVAL_INDIRECT(result, retval); } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_long offset; @@ -1100,7 +1097,7 @@ convert_to_array: ZVAL_NULL(result); zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ce->name->val); - } else if (retval && Z_TYPE_P(retval) != IS_UNDEF) { + } else if (EXPECTED(retval && Z_TYPE_P(retval) != IS_UNDEF)) { if (!Z_ISREF_P(retval)) { if (Z_REFCOUNTED_P(retval) && Z_REFCOUNT_P(retval) > 1) { @@ -1121,18 +1118,15 @@ convert_to_array: if (result != retval) { if (is_ref) { ZVAL_MAKE_REF(retval); - Z_ADDREF_P(retval); - ZVAL_REF(result, Z_REF_P(retval)); - } else { - ZVAL_INDIRECT(result, retval); } + ZVAL_INDIRECT(result, retval); } } else { ZVAL_INDIRECT(result, &EG(error_zval)); } } } else if (EXPECTED(Z_TYPE_P(container) == IS_NULL)) { - if (container == &EG(error_zval)) { + if (UNEXPECTED(container == &EG(error_zval))) { ZVAL_INDIRECT(result, &EG(error_zval)); } else if (type != BP_VAR_UNSET) { goto convert_to_array; @@ -1276,15 +1270,15 @@ static void zend_fetch_property_address(zval *result, zval *container_ptr, zval zval *container = container_ptr; ZVAL_DEREF(container); - if (Z_TYPE_P(container) != IS_OBJECT) { - if (container == &EG(error_zval)) { + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { + if (UNEXPECTED(container == &EG(error_zval))) { ZVAL_INDIRECT(result, &EG(error_zval)); return; } /* this should modify object only if it's empty */ if (type != BP_VAR_UNSET && - ((Z_TYPE_P(container) == IS_NULL || + EXPECTED((Z_TYPE_P(container) == IS_NULL || Z_TYPE_P(container) == IS_FALSE || (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0)))) { zval_ptr_dtor_nogc(container); @@ -1296,7 +1290,7 @@ static void zend_fetch_property_address(zval *result, zval *container_ptr, zval } } - if (Z_OBJ_HT_P(container)->get_property_ptr_ptr) { + if (EXPECTED(Z_OBJ_HT_P(container)->get_property_ptr_ptr)) { zval *ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr, type, cache_slot TSRMLS_CC); if (NULL == ptr) { if (Z_OBJ_HT_P(container)->read_property && @@ -1304,11 +1298,8 @@ static void zend_fetch_property_address(zval *result, zval *container_ptr, zval if (ptr != result) { if (is_ref && ptr != &EG(uninitialized_zval)) { ZVAL_MAKE_REF(ptr); - Z_ADDREF_P(ptr); - ZVAL_REF(result, Z_REF_P(ptr)); - } else { - ZVAL_INDIRECT(result, ptr); } + ZVAL_INDIRECT(result, ptr); } } else { zend_error_noreturn(E_ERROR, "Cannot access undefined property for object with overloaded property access"); @@ -1316,22 +1307,16 @@ static void zend_fetch_property_address(zval *result, zval *container_ptr, zval } else { if (is_ref) { ZVAL_MAKE_REF(ptr); - Z_ADDREF_P(ptr); - ZVAL_REF(result, Z_REF_P(ptr)); - } else { - ZVAL_INDIRECT(result, ptr); } + ZVAL_INDIRECT(result, ptr); } - } else if (Z_OBJ_HT_P(container)->read_property) { + } else if (EXPECTED(Z_OBJ_HT_P(container)->read_property)) { zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result TSRMLS_CC); if (ptr != result) { if (is_ref && ptr != &EG(uninitialized_zval)) { ZVAL_MAKE_REF(ptr); - Z_ADDREF_P(ptr); - ZVAL_REF(result, Z_REF_P(ptr)); - } else { - ZVAL_INDIRECT(result, ptr); } + ZVAL_INDIRECT(result, ptr); } } else { zend_error(E_WARNING, "This object doesn't support property references"); diff --git a/Zend/zend_static_allocator.c b/Zend/zend_static_allocator.c deleted file mode 100644 index 049d29f6a2..0000000000 --- a/Zend/zend_static_allocator.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend Engine | - +----------------------------------------------------------------------+ - | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) | - +----------------------------------------------------------------------+ - | This source file is subject to version 2.00 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.zend.com/license/2_00.txt. | - | If you did not receive a copy of the Zend license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@zend.com so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Andi Gutmans <andi@zend.com> | - +----------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "zend_static_allocator.h" - -/* Not checking emalloc() and erealloc() return values as they are supposed to bailout */ - -inline static void block_init(Block *block, uint32_t block_size) -{ - block->pos = block->bp = (char *) emalloc(block_size); - block->end = block->bp + block_size; -} - -inline static char *block_allocate(Block *block, uint32_t size) -{ - char *retval = block->pos; - if ((block->pos += size) >= block->end) { - return (char *)NULL; - } - return retval; -} - -inline static void block_destroy(Block *block) -{ - efree(block->bp); -} - -void static_allocator_init(StaticAllocator *sa) -{ - sa->Blocks = (Block *) emalloc(sizeof(Block)); - block_init(sa->Blocks, ALLOCATOR_BLOCK_SIZE); - sa->num_blocks = 1; - sa->current_block = 0; -} - -char *static_allocator_allocate(StaticAllocator *sa, uint32_t size) -{ - char *retval; - - retval = block_allocate(&sa->Blocks[sa->current_block], size); - if (retval) { - return retval; - } - sa->Blocks = (Block *) erealloc(sa->Blocks, ++sa->num_blocks); - sa->current_block++; - block_init(&sa->Blocks[sa->current_block], (size > ALLOCATOR_BLOCK_SIZE) ? size : ALLOCATOR_BLOCK_SIZE); - retval = block_allocate(&sa->Blocks[sa->current_block], size); - return retval; -} - -void static_allocator_destroy(StaticAllocator *sa) -{ - uint32_t i; - - for (i=0; i<sa->num_blocks; i++) { - block_free(&sa->Blocks[i]); - } - efree(sa->Blocks); -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/Zend/zend_static_allocator.h b/Zend/zend_static_allocator.h deleted file mode 100644 index cd9b0ff583..0000000000 --- a/Zend/zend_static_allocator.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend Engine | - +----------------------------------------------------------------------+ - | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) | - +----------------------------------------------------------------------+ - | This source file is subject to version 2.00 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.zend.com/license/2_00.txt. | - | If you did not receive a copy of the Zend license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@zend.com so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Andi Gutmans <andi@zend.com> | - +----------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef ZEND_STATIC_ALLOCATOR_H -#define ZEND_STATIC_ALLOCATOR_H - -#define ALLOCATOR_BLOCK_SIZE 400000 - -/* Temporary */ -typedef unsigned int uint32_t; -#define emalloc(s) malloc(s) -#define efree(p) free(p) - -typedef struct _Block { - char *bp; - char *pos; - char *end; -} Block; - -typedef struct _StaticAllocator { - Block *Blocks; - uint32_t num_blocks; - uint32_t current_block; -} StaticAllocator; - -void static_allocator_init(StaticAllocator *sa); -char *static_allocator_allocate(StaticAllocator *sa, uint32_t size); -void static_allocator_destroy(StaticAllocator *sa); - -#endif /* ZEND_STATIC_ALLOCATOR_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index cc16072c5b..b25ab4e8be 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1683,7 +1683,7 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV) variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_OP2_TMP_FREE()) { + if (OP2_TYPE == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -2826,7 +2826,7 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) zval_copy_ctor_func(EX(return_value)); } } - } else if (Z_ISREF_P(retval_ptr)) { + } else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(retval_ptr)) { ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); FREE_OP1_IF_VAR(); } else { @@ -2879,9 +2879,8 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY) } else { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { - zval tmp; - ZVAL_DUP(&tmp, retval_ptr); - ZVAL_NEW_REF(EX(return_value), &tmp); + ZVAL_NEW_REF(EX(return_value), retval_ptr); + if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); } break; } @@ -3040,7 +3039,7 @@ ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, ANY) varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); arg = ZEND_CALL_ARG(EX(call), opline->op2.num); EX(call)->num_args = opline->op2.num; - if (Z_ISREF_P(varptr)) { + if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(varptr)) { ZVAL_COPY(arg, Z_REFVAL_P(varptr)); FREE_OP1(); } else { @@ -3145,7 +3144,7 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, ANY) varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); arg = ZEND_CALL_ARG(EX(call), opline->op2.num); EX(call)->num_args = opline->op2.num; - if (Z_ISREF_P(varptr)) { + if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(varptr)) { ZVAL_COPY(arg, Z_REFVAL_P(varptr)); FREE_OP1(); } else { @@ -3911,7 +3910,7 @@ ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMP|VAR|UNUS FREE_OP1_VAR_PTR(); } else { expr_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R); - if (IS_OP1_TMP_FREE()) { /* temporary variable */ + if (OP1_TYPE == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (OP1_TYPE == IS_CONST) { @@ -3919,9 +3918,9 @@ ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMP|VAR|UNUS ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); FREE_OP1_IF_VAR(); } else if (OP1_TYPE == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -4085,7 +4084,7 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY) } } else { ZVAL_COPY_VALUE(result, expr); - if (!IS_OP1_TMP_FREE()) { + if (OP1_TYPE != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_array(result); @@ -4105,7 +4104,7 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY) } } else { ZVAL_COPY_VALUE(result, expr); - if (!IS_OP1_TMP_FREE()) { + if (OP1_TYPE != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_object(result); @@ -4251,29 +4250,37 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) zval tmp, *varname; HashTable *target_symbol_table; zend_free_op free_op1; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (OP1_TYPE == IS_CV && OP2_TYPE == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = GET_OP1_ZVAL_PTR(BP_VAR_R); + ZVAL_UNDEF(&tmp); if (OP1_TYPE != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (OP2_TYPE != IS_UNUSED) { @@ -4285,10 +4292,8 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (OP1_TYPE != IS_CONST && tmp_is_dup) { + if (OP1_TYPE != IS_CONST) { zval_dtor(&tmp); - } else if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) { - zval_ptr_dtor(&tmp); } FREE_OP1(); HANDLE_EXCEPTION(); @@ -4307,10 +4312,8 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (OP1_TYPE != IS_CONST && tmp_is_dup) { + if (OP1_TYPE != IS_CONST) { zval_dtor(&tmp); - } else if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) { - zval_ptr_dtor(&tmp); } FREE_OP1(); CHECK_EXCEPTION(); @@ -4351,12 +4354,9 @@ ZEND_VM_C_LABEL(num_index_dim): zend_hash_index_del(ht, hval); break; case IS_STRING: - if (OP2_TYPE == IS_CV || OP2_TYPE == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (OP2_TYPE != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - ZEND_VM_C_GOTO(numeric_index_dim); + ZEND_VM_C_GOTO(num_index_dim); } } if (ht == &EG(symbol_table).ht) { @@ -4364,15 +4364,6 @@ ZEND_VM_C_LABEL(num_index_dim): } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (OP2_TYPE == IS_CV || OP2_TYPE == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -ZEND_VM_C_LABEL(numeric_index_dim): - zend_hash_index_del(ht, hval); - if (OP2_TYPE == IS_CV || OP2_TYPE == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -4487,7 +4478,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) } else { array_ptr = array_ref = GET_OP1_ZVAL_PTR(BP_VAR_R); ZVAL_DEREF(array_ptr); - if (IS_OP1_TMP_FREE()) { /* IS_TMP_VAR */ + if (OP1_TYPE == IS_TMP_VAR) { ZVAL_COPY_VALUE(&tmp, array_ptr); array_ptr = &tmp; if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -5695,7 +5686,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!IS_OP1_TMP_FREE()) { + if (OP1_TYPE != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -5726,14 +5717,14 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE ZVAL_DUP(&generator->value, value); } else if (OP1_TYPE == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); FREE_OP1_IF_VAR(); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (OP1_TYPE == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -5751,14 +5742,14 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE ZVAL_DUP(&generator->key, key); } else if (OP2_TYPE == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((OP2_TYPE == IS_VAR || OP2_TYPE == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); FREE_OP2_IF_VAR(); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (OP2_TYPE == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 84fc8f9b23..467dd4f168 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2610,7 +2610,7 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG zval_copy_ctor_func(EX(return_value)); } } - } else if (Z_ISREF_P(retval_ptr)) { + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(retval_ptr)) { ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); } else { @@ -2663,9 +2663,8 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND } else { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { - zval tmp; - ZVAL_DUP(&tmp, retval_ptr); - ZVAL_NEW_REF(EX(return_value), &tmp); + ZVAL_NEW_REF(EX(return_value), retval_ptr); + if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); } break; } @@ -2893,7 +2892,7 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { ZVAL_COPY_VALUE(result, expr); - if (!0) { + if (IS_CONST != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_array(result); @@ -2913,7 +2912,7 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { ZVAL_COPY_VALUE(result, expr); - if (!0) { + if (IS_CONST != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_object(result); @@ -3092,7 +3091,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A } else { array_ptr = array_ref = opline->op1.zv; ZVAL_DEREF(array_ptr); - if (0) { /* IS_TMP_VAR */ + if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&tmp, array_ptr); array_ptr = &tmp; if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -4333,7 +4332,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_O } else { expr_ptr = opline->op1.zv; - if (0) { /* temporary variable */ + if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CONST == IS_CONST) { @@ -4341,9 +4340,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_O ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -4440,29 +4439,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HA zval tmp, *varname; HashTable *target_symbol_table; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_CONST == IS_CV && IS_CONST == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = opline->op1.zv; + ZVAL_UNDEF(&tmp); if (IS_CONST != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_CONST != IS_UNUSED) { @@ -4474,10 +4481,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HA } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST && tmp_is_dup) { + if (IS_CONST != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - zval_ptr_dtor(&tmp); } HANDLE_EXCEPTION(); @@ -4496,10 +4501,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HA zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_CONST != IS_CONST && tmp_is_dup) { + if (IS_CONST != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - zval_ptr_dtor(&tmp); } CHECK_EXCEPTION(); @@ -4798,7 +4801,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CONST != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -4828,14 +4831,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE ZVAL_DUP(&generator->value, value); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -4853,14 +4856,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE ZVAL_DUP(&generator->key, key); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CONST == IS_VAR || IS_CONST == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -5546,7 +5549,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_TMP_HANDLER(ZEND_OPC } else { expr_ptr = opline->op1.zv; - if (0) { /* temporary variable */ + if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CONST == IS_CONST) { @@ -5554,9 +5557,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_TMP_HANDLER(ZEND_OPC ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -5828,7 +5831,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CONST != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -5858,14 +5861,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->value, value); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -5883,14 +5886,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->key, key); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -6727,7 +6730,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_VAR_HANDLER(ZEND_OPC } else { expr_ptr = opline->op1.zv; - if (0) { /* temporary variable */ + if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CONST == IS_CONST) { @@ -6735,9 +6738,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_VAR_HANDLER(ZEND_OPC ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -6834,29 +6837,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HAND zval tmp, *varname; HashTable *target_symbol_table; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_CONST == IS_CV && IS_VAR == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = opline->op1.zv; + ZVAL_UNDEF(&tmp); if (IS_CONST != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_VAR != IS_UNUSED) { @@ -6868,10 +6879,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HAND } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST && tmp_is_dup) { + if (IS_CONST != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - zval_ptr_dtor(&tmp); } HANDLE_EXCEPTION(); @@ -6890,10 +6899,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HAND zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_CONST != IS_CONST && tmp_is_dup) { + if (IS_CONST != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - zval_ptr_dtor(&tmp); } CHECK_EXCEPTION(); @@ -7161,7 +7168,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CONST != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -7191,14 +7198,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->value, value); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -7216,14 +7223,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->key, key); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_VAR == IS_VAR || IS_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); zval_ptr_dtor_nogc(free_op2.var); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -7592,7 +7599,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_UNUSED_HANDLER(ZEND_ } else { expr_ptr = opline->op1.zv; - if (0) { /* temporary variable */ + if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CONST == IS_CONST) { @@ -7600,9 +7607,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_UNUSED_HANDLER(ZEND_ ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -7699,29 +7706,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_H zval tmp, *varname; HashTable *target_symbol_table; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_CONST == IS_CV && IS_UNUSED == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = opline->op1.zv; + ZVAL_UNDEF(&tmp); if (IS_CONST != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_UNUSED != IS_UNUSED) { @@ -7733,10 +7748,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_H } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST && tmp_is_dup) { + if (IS_CONST != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - zval_ptr_dtor(&tmp); } HANDLE_EXCEPTION(); @@ -7755,10 +7768,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_H zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_CONST != IS_CONST && tmp_is_dup) { + if (IS_CONST != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CONST == IS_VAR || IS_CONST == IS_CV) { - zval_ptr_dtor(&tmp); } CHECK_EXCEPTION(); @@ -7904,7 +7915,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CONST != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -7934,14 +7945,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL ZVAL_DUP(&generator->value, value); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -7959,14 +7970,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL ZVAL_DUP(&generator->key, key); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_UNUSED == IS_VAR || IS_UNUSED == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -8686,7 +8697,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CV_HANDLER(ZEND_OPCO } else { expr_ptr = opline->op1.zv; - if (0) { /* temporary variable */ + if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CONST == IS_CONST) { @@ -8694,9 +8705,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CV_HANDLER(ZEND_OPCO ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -8966,7 +8977,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CONST != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -8996,14 +9007,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A ZVAL_DUP(&generator->value, value); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -9021,14 +9032,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A ZVAL_DUP(&generator->key, key); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CV == IS_VAR || IS_CV == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -9322,7 +9333,7 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval_copy_ctor_func(EX(return_value)); } } - } else if (Z_ISREF_P(retval_ptr)) { + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(retval_ptr)) { ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); } else { @@ -9375,9 +9386,8 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE } else { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { - zval tmp; - ZVAL_DUP(&tmp, retval_ptr); - ZVAL_NEW_REF(EX(return_value), &tmp); + ZVAL_NEW_REF(EX(return_value), retval_ptr); + if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); } break; } @@ -9607,7 +9617,7 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { ZVAL_COPY_VALUE(result, expr); - if (!1) { + if (IS_TMP_VAR != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_array(result); @@ -9627,7 +9637,7 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { ZVAL_COPY_VALUE(result, expr); - if (!1) { + if (IS_TMP_VAR != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_object(result); @@ -9806,7 +9816,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG } else { array_ptr = array_ref = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); ZVAL_DEREF(array_ptr); - if (1) { /* IS_TMP_VAR */ + if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&tmp, array_ptr); array_ptr = &tmp; if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -10921,7 +10931,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CONST_HANDLER(ZEND_OPC } else { expr_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (1) { /* temporary variable */ + if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_TMP_VAR == IS_CONST) { @@ -10929,9 +10939,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CONST_HANDLER(ZEND_OPC ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -11028,29 +11038,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HAND zval tmp, *varname; HashTable *target_symbol_table; zend_free_op free_op1; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_TMP_VAR == IS_CV && IS_CONST == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_TMP_VAR != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_CONST != IS_UNUSED) { @@ -11062,10 +11080,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HAND } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_TMP_VAR != IS_CONST && tmp_is_dup) { + if (IS_TMP_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_dtor(free_op1.var); HANDLE_EXCEPTION(); @@ -11084,10 +11100,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HAND zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_TMP_VAR != IS_CONST && tmp_is_dup) { + if (IS_TMP_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_dtor(free_op1.var); CHECK_EXCEPTION(); @@ -11353,7 +11367,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!1) { + if (IS_TMP_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -11383,14 +11397,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->value, value); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -11408,14 +11422,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->key, key); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CONST == IS_VAR || IS_CONST == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -12058,7 +12072,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_TMP_HANDLER(ZEND_OPCOD } else { expr_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (1) { /* temporary variable */ + if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_TMP_VAR == IS_CONST) { @@ -12066,9 +12080,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_TMP_HANDLER(ZEND_OPCOD ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -12340,7 +12354,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!1) { + if (IS_TMP_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -12370,14 +12384,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_DUP(&generator->value, value); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -12395,14 +12409,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_DUP(&generator->key, key); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -13196,7 +13210,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_VAR_HANDLER(ZEND_OPCOD } else { expr_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (1) { /* temporary variable */ + if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_TMP_VAR == IS_CONST) { @@ -13204,9 +13218,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_VAR_HANDLER(ZEND_OPCOD ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -13303,29 +13317,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLE zval tmp, *varname; HashTable *target_symbol_table; zend_free_op free_op1; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_TMP_VAR == IS_CV && IS_VAR == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_TMP_VAR != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_VAR != IS_UNUSED) { @@ -13337,10 +13359,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLE } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_TMP_VAR != IS_CONST && tmp_is_dup) { + if (IS_TMP_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_dtor(free_op1.var); HANDLE_EXCEPTION(); @@ -13359,10 +13379,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLE zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_TMP_VAR != IS_CONST && tmp_is_dup) { + if (IS_TMP_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_dtor(free_op1.var); CHECK_EXCEPTION(); @@ -13630,7 +13648,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!1) { + if (IS_TMP_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -13660,14 +13678,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_DUP(&generator->value, value); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -13685,14 +13703,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_DUP(&generator->key, key); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_VAR == IS_VAR || IS_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); zval_ptr_dtor_nogc(free_op2.var); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -13945,7 +13963,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_UNUSED_HANDLER(ZEND_OP } else { expr_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (1) { /* temporary variable */ + if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_TMP_VAR == IS_CONST) { @@ -13953,9 +13971,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_UNUSED_HANDLER(ZEND_OP ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -14052,29 +14070,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HAN zval tmp, *varname; HashTable *target_symbol_table; zend_free_op free_op1; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_TMP_VAR == IS_CV && IS_UNUSED == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_TMP_VAR != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_UNUSED != IS_UNUSED) { @@ -14086,10 +14112,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HAN } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_TMP_VAR != IS_CONST && tmp_is_dup) { + if (IS_TMP_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_dtor(free_op1.var); HANDLE_EXCEPTION(); @@ -14108,10 +14132,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HAN zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_TMP_VAR != IS_CONST && tmp_is_dup) { + if (IS_TMP_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_dtor(free_op1.var); CHECK_EXCEPTION(); @@ -14232,7 +14254,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!1) { + if (IS_TMP_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -14262,14 +14284,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER ZVAL_DUP(&generator->value, value); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -14287,14 +14309,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER ZVAL_DUP(&generator->key, key); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_UNUSED == IS_VAR || IS_UNUSED == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -14917,7 +14939,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CV_HANDLER(ZEND_OPCODE } else { expr_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (1) { /* temporary variable */ + if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_TMP_VAR == IS_CONST) { @@ -14925,9 +14947,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CV_HANDLER(ZEND_OPCODE ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -15197,7 +15219,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!1) { + if (IS_TMP_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -15227,14 +15249,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_DUP(&generator->value, value); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -15252,14 +15274,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_DUP(&generator->key, key); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CV == IS_VAR || IS_CV == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -15775,7 +15797,7 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval_copy_ctor_func(EX(return_value)); } } - } else if (Z_ISREF_P(retval_ptr)) { + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(retval_ptr)) { ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); zval_ptr_dtor_nogc(free_op1.var); } else { @@ -15828,9 +15850,8 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE } else { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { - zval tmp; - ZVAL_DUP(&tmp, retval_ptr); - ZVAL_NEW_REF(EX(return_value), &tmp); + ZVAL_NEW_REF(EX(return_value), retval_ptr); + if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); } break; } @@ -15883,7 +15904,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); arg = ZEND_CALL_ARG(EX(call), opline->op2.num); EX(call)->num_args = opline->op2.num; - if (Z_ISREF_P(varptr)) { + if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(varptr)) { ZVAL_COPY(arg, Z_REFVAL_P(varptr)); zval_ptr_dtor_nogc(free_op1.var); } else { @@ -15988,7 +16009,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); arg = ZEND_CALL_ARG(EX(call), opline->op2.num); EX(call)->num_args = opline->op2.num; - if (Z_ISREF_P(varptr)) { + if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(varptr)) { ZVAL_COPY(arg, Z_REFVAL_P(varptr)); zval_ptr_dtor_nogc(free_op1.var); } else { @@ -16235,7 +16256,7 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { ZVAL_COPY_VALUE(result, expr); - if (!0) { + if (IS_VAR != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_array(result); @@ -16255,7 +16276,7 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { ZVAL_COPY_VALUE(result, expr); - if (!0) { + if (IS_VAR != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_object(result); @@ -16435,7 +16456,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } else { array_ptr = array_ref = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); ZVAL_DEREF(array_ptr); - if (0) { /* IS_TMP_VAR */ + if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&tmp, array_ptr); array_ptr = &tmp; if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -18379,7 +18400,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (0) { + if (IS_CONST == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -18715,7 +18736,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CONST_HANDLER(ZEND_OPC if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; } else { expr_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_VAR == IS_CONST) { @@ -18723,9 +18744,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CONST_HANDLER(ZEND_OPC ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); zval_ptr_dtor_nogc(free_op1.var); } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -18822,29 +18843,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAND zval tmp, *varname; HashTable *target_symbol_table; zend_free_op free_op1; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_VAR == IS_CV && IS_CONST == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_VAR != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_CONST != IS_UNUSED) { @@ -18856,10 +18885,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAND } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_VAR != IS_CONST && tmp_is_dup) { + if (IS_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_ptr_dtor_nogc(free_op1.var); HANDLE_EXCEPTION(); @@ -18878,10 +18905,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAND zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_VAR != IS_CONST && tmp_is_dup) { + if (IS_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_ptr_dtor_nogc(free_op1.var); CHECK_EXCEPTION(); @@ -18922,12 +18947,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_CONST != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -18935,15 +18957,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -19277,7 +19290,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -19308,14 +19321,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->value, value); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); zval_ptr_dtor_nogc(free_op1.var); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -19333,14 +19346,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->key, key); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CONST == IS_VAR || IS_CONST == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -20607,7 +20620,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_A variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (1) { + if (IS_TMP_VAR == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -20849,7 +20862,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_TMP_HANDLER(ZEND_OPCOD if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; } else { expr_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_VAR == IS_CONST) { @@ -20857,9 +20870,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_TMP_HANDLER(ZEND_OPCOD ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); zval_ptr_dtor_nogc(free_op1.var); } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -20984,12 +20997,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_TMP_VAR != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -20997,15 +21007,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -21261,7 +21262,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -21292,14 +21293,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_DUP(&generator->value, value); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); zval_ptr_dtor_nogc(free_op1.var); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -21317,14 +21318,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_DUP(&generator->key, key); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -22742,7 +22743,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_A variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (0) { + if (IS_VAR == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -23048,7 +23049,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_VAR_HANDLER(ZEND_OPCOD if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; } else { expr_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_VAR == IS_CONST) { @@ -23056,9 +23057,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_VAR_HANDLER(ZEND_OPCOD ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); zval_ptr_dtor_nogc(free_op1.var); } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -23155,29 +23156,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLE zval tmp, *varname; HashTable *target_symbol_table; zend_free_op free_op1; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_VAR == IS_CV && IS_VAR == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_VAR != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_VAR != IS_UNUSED) { @@ -23189,10 +23198,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLE } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_VAR != IS_CONST && tmp_is_dup) { + if (IS_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_ptr_dtor_nogc(free_op1.var); HANDLE_EXCEPTION(); @@ -23211,10 +23218,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLE zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_VAR != IS_CONST && tmp_is_dup) { + if (IS_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_ptr_dtor_nogc(free_op1.var); CHECK_EXCEPTION(); @@ -23255,12 +23260,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_VAR != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -23268,15 +23270,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -23612,7 +23605,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -23643,14 +23636,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_DUP(&generator->value, value); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); zval_ptr_dtor_nogc(free_op1.var); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -23668,14 +23661,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_DUP(&generator->key, key); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_VAR == IS_VAR || IS_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); zval_ptr_dtor_nogc(free_op2.var); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -24507,7 +24500,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_UNUSED_HANDLER(ZEND_OP if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; } else { expr_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_VAR == IS_CONST) { @@ -24515,9 +24508,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_UNUSED_HANDLER(ZEND_OP ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); zval_ptr_dtor_nogc(free_op1.var); } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -24614,29 +24607,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAN zval tmp, *varname; HashTable *target_symbol_table; zend_free_op free_op1; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_VAR == IS_CV && IS_UNUSED == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_VAR != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_UNUSED != IS_UNUSED) { @@ -24648,10 +24649,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAN } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_VAR != IS_CONST && tmp_is_dup) { + if (IS_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_ptr_dtor_nogc(free_op1.var); HANDLE_EXCEPTION(); @@ -24670,10 +24669,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAN zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_VAR != IS_CONST && tmp_is_dup) { + if (IS_VAR != IS_CONST) { zval_dtor(&tmp); - } else if (IS_VAR == IS_VAR || IS_VAR == IS_CV) { - zval_ptr_dtor(&tmp); } zval_ptr_dtor_nogc(free_op1.var); CHECK_EXCEPTION(); @@ -24812,7 +24809,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -24843,14 +24840,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER ZVAL_DUP(&generator->value, value); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); zval_ptr_dtor_nogc(free_op1.var); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -24868,14 +24865,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER ZVAL_DUP(&generator->key, key); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_UNUSED == IS_VAR || IS_UNUSED == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -26122,7 +26119,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_AR variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (0) { + if (IS_CV == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -26424,7 +26421,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CV_HANDLER(ZEND_OPCODE if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; } else { expr_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_VAR == IS_CONST) { @@ -26432,9 +26429,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CV_HANDLER(ZEND_OPCODE ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); zval_ptr_dtor_nogc(free_op1.var); } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -26559,12 +26556,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_CV != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -26572,15 +26566,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -26834,7 +26819,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_VAR != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -26865,14 +26850,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_DUP(&generator->value, value); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); zval_ptr_dtor_nogc(free_op1.var); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -26890,14 +26875,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_DUP(&generator->key, key); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CV == IS_VAR || IS_CV == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -28024,12 +28009,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_CONST != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -28037,15 +28019,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -28299,7 +28272,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_UNUSED != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -28329,14 +28302,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL ZVAL_DUP(&generator->value, value); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -28354,14 +28327,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL ZVAL_DUP(&generator->key, key); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CONST == IS_VAR || IS_CONST == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -29309,12 +29282,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_TMP_VAR != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -29322,15 +29292,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -29586,7 +29547,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_UNUSED != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -29616,14 +29577,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER ZVAL_DUP(&generator->value, value); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -29641,14 +29602,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER ZVAL_DUP(&generator->key, key); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -30596,12 +30557,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_VAR != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -30609,15 +30567,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -30873,7 +30822,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_UNUSED != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -30903,14 +30852,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER ZVAL_DUP(&generator->value, value); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -30928,14 +30877,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER ZVAL_DUP(&generator->key, key); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_VAR == IS_VAR || IS_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); zval_ptr_dtor_nogc(free_op2.var); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -31389,7 +31338,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_UNUSED != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -31419,14 +31368,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND ZVAL_DUP(&generator->value, value); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -31444,14 +31393,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND ZVAL_DUP(&generator->key, key); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_UNUSED == IS_VAR || IS_UNUSED == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -32392,12 +32341,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_CV != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -32405,15 +32351,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -32667,7 +32604,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_UNUSED != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -32697,14 +32634,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->value, value); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -32722,14 +32659,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->key, key); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CV == IS_VAR || IS_CV == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -33216,7 +33153,7 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval_copy_ctor_func(EX(return_value)); } } - } else if (Z_ISREF_P(retval_ptr)) { + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(retval_ptr)) { ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); } else { @@ -33269,9 +33206,8 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER } else { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { - zval tmp; - ZVAL_DUP(&tmp, retval_ptr); - ZVAL_NEW_REF(EX(return_value), &tmp); + ZVAL_NEW_REF(EX(return_value), retval_ptr); + if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); } break; } @@ -33323,7 +33259,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); arg = ZEND_CALL_ARG(EX(call), opline->op2.num); EX(call)->num_args = opline->op2.num; - if (Z_ISREF_P(varptr)) { + if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(varptr)) { ZVAL_COPY(arg, Z_REFVAL_P(varptr)); } else { @@ -33427,7 +33363,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); arg = ZEND_CALL_ARG(EX(call), opline->op2.num); EX(call)->num_args = opline->op2.num; - if (Z_ISREF_P(varptr)) { + if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(varptr)) { ZVAL_COPY(arg, Z_REFVAL_P(varptr)); } else { @@ -33660,7 +33596,7 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { ZVAL_COPY_VALUE(result, expr); - if (!0) { + if (IS_CV != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_array(result); @@ -33680,7 +33616,7 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { ZVAL_COPY_VALUE(result, expr); - if (!0) { + if (IS_CV != IS_TMP_VAR) { zval_opt_copy_ctor(result); } convert_to_object(result); @@ -33859,7 +33795,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS } else { array_ptr = array_ref = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); ZVAL_DEREF(array_ptr); - if (0) { /* IS_TMP_VAR */ + if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&tmp, array_ptr); array_ptr = &tmp; if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -35559,7 +35495,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (0) { + if (IS_CONST == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -35682,7 +35618,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CONST_HANDLER(ZEND_OPCO } else { expr_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CV == IS_CONST) { @@ -35690,9 +35626,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CONST_HANDLER(ZEND_OPCO ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -35789,29 +35725,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDL zval tmp, *varname; HashTable *target_symbol_table; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_CV == IS_CV && IS_CONST == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_CV != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_CONST != IS_UNUSED) { @@ -35823,10 +35767,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDL } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST && tmp_is_dup) { + if (IS_CV != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - zval_ptr_dtor(&tmp); } HANDLE_EXCEPTION(); @@ -35845,10 +35787,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDL zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_CV != IS_CONST && tmp_is_dup) { + if (IS_CV != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - zval_ptr_dtor(&tmp); } CHECK_EXCEPTION(); @@ -35889,12 +35829,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_CONST != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -35902,15 +35839,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -36244,7 +36172,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CV != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -36274,14 +36202,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ZVAL_DUP(&generator->value, value); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -36299,14 +36227,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ZVAL_DUP(&generator->key, key); } else if (IS_CONST == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CONST == IS_VAR || IS_CONST == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CONST == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -37629,7 +37557,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (1) { + if (IS_TMP_VAR == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -37754,7 +37682,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_TMP_HANDLER(ZEND_OPCODE } else { expr_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CV == IS_CONST) { @@ -37762,9 +37690,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_TMP_HANDLER(ZEND_OPCODE ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -37889,12 +37817,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_TMP_VAR != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -37902,15 +37827,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -38166,7 +38082,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CV != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -38196,14 +38112,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_DUP(&generator->value, value); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -38221,14 +38137,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_DUP(&generator->key, key); } else if (IS_TMP_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_TMP_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -39645,7 +39561,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (0) { + if (IS_VAR == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -39833,7 +39749,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_VAR_HANDLER(ZEND_OPCODE } else { expr_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CV == IS_CONST) { @@ -39841,9 +39757,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_VAR_HANDLER(ZEND_OPCODE ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -39940,29 +39856,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER zval tmp, *varname; HashTable *target_symbol_table; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_CV == IS_CV && IS_VAR == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_CV != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_VAR != IS_UNUSED) { @@ -39974,10 +39898,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST && tmp_is_dup) { + if (IS_CV != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - zval_ptr_dtor(&tmp); } HANDLE_EXCEPTION(); @@ -39996,10 +39918,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_CV != IS_CONST && tmp_is_dup) { + if (IS_CV != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - zval_ptr_dtor(&tmp); } CHECK_EXCEPTION(); @@ -40040,12 +39960,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_VAR != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -40053,15 +39970,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -40397,7 +40305,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CV != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -40427,14 +40335,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_DUP(&generator->value, value); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -40452,14 +40360,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_DUP(&generator->key, key); } else if (IS_VAR == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_VAR == IS_VAR || IS_VAR == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); zval_ptr_dtor_nogc(free_op2.var); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_VAR == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -41174,7 +41082,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_UNUSED_HANDLER(ZEND_OPC } else { expr_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CV == IS_CONST) { @@ -41182,9 +41090,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_UNUSED_HANDLER(ZEND_OPC ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -41281,29 +41189,37 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAND zval tmp, *varname; HashTable *target_symbol_table; - zend_bool tmp_is_dup = 0; SAVE_OPLINE(); if (IS_CV == IS_CV && IS_UNUSED == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { - ZVAL_COPY_VALUE(&tmp, EX_VAR(opline->op1.var)); - ZVAL_UNDEF(EX_VAR(opline->op1.var)); - zval_ptr_dtor(&tmp); + zval *var = EX_VAR(opline->op1.var); + + if (Z_REFCOUNTED_P(var)) { + zend_refcounted *garbage = Z_COUNTED_P(var); + + if (!--GC_REFCOUNT(garbage)) { + ZVAL_UNDEF(var); + _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(var); + ZVAL_UNDEF(var); + } + } else { + ZVAL_UNDEF(var); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); + ZVAL_UNDEF(&tmp); if (IS_CV != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { ZVAL_DUP(&tmp, varname); convert_to_string(&tmp); varname = &tmp; - tmp_is_dup = 1; - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - ZVAL_COPY(&tmp, varname); - varname = &tmp; } if (IS_UNUSED != IS_UNUSED) { @@ -41315,10 +41231,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAND } else { ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST && tmp_is_dup) { + if (IS_CV != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - zval_ptr_dtor(&tmp); } HANDLE_EXCEPTION(); @@ -41337,10 +41251,8 @@ static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAND zend_hash_del_ind(target_symbol_table, Z_STR_P(varname)); } - if (IS_CV != IS_CONST && tmp_is_dup) { + if (IS_CV != IS_CONST) { zval_dtor(&tmp); - } else if (IS_CV == IS_VAR || IS_CV == IS_CV) { - zval_ptr_dtor(&tmp); } CHECK_EXCEPTION(); @@ -41461,7 +41373,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CV != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -41491,14 +41403,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->value, value); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -41516,14 +41428,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_DUP(&generator->key, key); } else if (IS_UNUSED == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_UNUSED == IS_VAR || IS_UNUSED == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_UNUSED == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG @@ -42769,7 +42681,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (0) { + if (IS_CV == IS_TMP_VAR) { zval_dtor(value); } if (RETURN_VALUE_USED(opline)) { @@ -42953,7 +42865,7 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CV_HANDLER(ZEND_OPCODE_ } else { expr_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - if (0) { /* temporary variable */ + if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&new_expr, expr_ptr); expr_ptr = &new_expr; } else if (IS_CV == IS_CONST) { @@ -42961,9 +42873,9 @@ static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CV_HANDLER(ZEND_OPCODE_ ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if (Z_ISREF_P(expr_ptr)) { - ZVAL_DUP(&new_expr, Z_REFVAL_P(expr_ptr)); - expr_ptr = &new_expr; + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { + expr_ptr = Z_REFVAL_P(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { Z_ADDREF_P(expr_ptr); @@ -43088,12 +43000,9 @@ num_index_dim: zend_hash_index_del(ht, hval); break; case IS_STRING: - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - if (Z_REFCOUNTED_P(offset)) Z_ADDREF_P(offset); - } if (IS_CV != IS_CONST) { if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), hval)) { - goto numeric_index_dim; + goto num_index_dim; } } if (ht == &EG(symbol_table).ht) { @@ -43101,15 +43010,6 @@ num_index_dim: } else { zend_hash_del(ht, Z_STR_P(offset)); } - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - zval_ptr_dtor(offset); - } - break; -numeric_index_dim: - zend_hash_index_del(ht, hval); - if (IS_CV == IS_CV || IS_CV == IS_VAR) { - zval_ptr_dtor(offset); - } break; case IS_NULL: zend_hash_del(ht, STR_EMPTY_ALLOC()); @@ -43363,7 +43263,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1); /* Temporary variables don't need ctor copying */ - if (!0) { + if (IS_CV != IS_TMP_VAR) { zval_copy_ctor(&generator->value); } } else { @@ -43393,14 +43293,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS ZVAL_DUP(&generator->value, value); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->value, value); - } else if (Z_ISREF_P(value)) { + } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(value)) { ZVAL_DUP(&generator->value, Z_REFVAL_P(value)); } else { + ZVAL_COPY_VALUE(&generator->value, value); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } - ZVAL_COPY_VALUE(&generator->value, value); } } } else { @@ -43418,14 +43318,14 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS ZVAL_DUP(&generator->key, key); } else if (IS_CV == IS_TMP_VAR) { ZVAL_COPY_VALUE(&generator->key, key); - } else if (Z_ISREF_P(key)) { + } else if ((IS_CV == IS_VAR || IS_CV == IS_CV) && Z_ISREF_P(key)) { ZVAL_DUP(&generator->key, Z_REFVAL_P(key)); } else { + ZVAL_COPY_VALUE(&generator->key, key); if (IS_CV == IS_CV) { - if (Z_REFCOUNTED_P(key)) Z_ADDREF_P(key); + if (Z_OPT_REFCOUNTED_P(key)) Z_ADDREF_P(key); } - ZVAL_COPY_VALUE(&generator->key, key); } if (Z_TYPE(generator->key) == IS_LONG diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index df4ac12d3a..ac7a96ce61 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -243,24 +243,6 @@ $op2_get_obj_zval_ptr_ptr = array( "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var TSRMLS_CC)", ); -$op1_is_tmp_free = array( - "ANY" => "IS_TMP_FREE(free_op1)", - "TMP" => "1", - "VAR" => "0", - "CONST" => "0", - "UNUSED" => "0", - "CV" => "0", -); - -$op2_is_tmp_free = array( - "ANY" => "IS_TMP_FREE(free_op2)", - "TMP" => "1", - "VAR" => "0", - "CONST" => "0", - "UNUSED" => "0", - "CV" => "0", -); - $op1_free_op = array( "ANY" => "FREE_OP(free_op1)", "TMP" => "zval_dtor(free_op1.var)", @@ -366,7 +348,7 @@ function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) { $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr, $op1_get_obj_zval_ptr_deref, $op2_get_obj_zval_ptr_deref, $op1_get_obj_zval_ptr_ptr, $op2_get_obj_zval_ptr_ptr, - $op1_is_tmp_free, $op2_is_tmp_free, $op1_free, $op2_free, + $op1_free, $op2_free, $op1_free_op, $op2_free_op, $op1_free_op_if_var, $op2_free_op_if_var, $op1_free_op_var_ptr, $op2_free_op_var_ptr, $prefix; @@ -391,8 +373,6 @@ function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) { "/GET_OP2_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/", "/GET_OP1_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/", "/GET_OP2_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/", - "/IS_OP1_TMP_FREE\(\)/", - "/IS_OP2_TMP_FREE\(\)/", "/FREE_OP1\(\)/", "/FREE_OP2\(\)/", "/FREE_OP1_IF_VAR\(\)/", @@ -429,8 +409,6 @@ function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) { $op2_get_obj_zval_ptr_deref[$op2], $op1_get_obj_zval_ptr_ptr[$op1], $op2_get_obj_zval_ptr_ptr[$op2], - $op1_is_tmp_free[$op1], - $op2_is_tmp_free[$op2], $op1_free_op[$op1], $op2_free_op[$op2], $op1_free_op_if_var[$op1], diff --git a/configure.in b/configure.in index bcdd55a51c..697cc0225a 100644 --- a/configure.in +++ b/configure.in @@ -1483,7 +1483,7 @@ esac PHP_ADD_SOURCES(Zend, \ zend_language_parser.c zend_language_scanner.c \ zend_ini_parser.c zend_ini_scanner.c \ - zend_alloc.c zend_compile.c zend_constants.c zend_dynamic_array.c zend_dtrace.c \ + zend_alloc.c zend_compile.c zend_constants.c zend_dtrace.c \ zend_execute_API.c zend_highlight.c zend_llist.c \ zend_vm_opcodes.c zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 1f873912b4..31f76b6ca2 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1116,7 +1116,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, opline->opcode == ZEND_ADD_CHAR || opline->opcode == ZEND_ADD_VAR || opline->opcode == ZEND_CONCAT) && - ZEND_OP1_TYPE(opline) == (IS_TMP_VAR|IS_VAR) && + (ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) && VAR_SOURCE(opline->op1) && VAR_SOURCE(opline->op1)->opcode == ZEND_CAST && VAR_SOURCE(opline->op1)->extended_value == IS_STRING) { diff --git a/ext/standard/basic_functions.h b/ext/standard/basic_functions.h index 9490754b23..a6d8496d75 100644 --- a/ext/standard/basic_functions.h +++ b/ext/standard/basic_functions.h @@ -204,11 +204,11 @@ typedef struct _php_basic_globals { zend_class_entry *incomplete_class; unsigned serialize_lock; /* whether to use the locally supplied var_hash instead (__sleep/__wakeup) */ struct { - void *var_hash; + struct php_serialize_data *data; unsigned level; } serialize; struct { - void *var_hash; + struct php_unserialize_data *data; unsigned level; } unserialize; diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 90979159ab..23225cdc42 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -38,7 +38,10 @@ PHPAPI void php_var_export_ex(zval *struc, int level, smart_str *buf TSRMLS_DC); PHPAPI void php_debug_zval_dump(zval *struc, int level TSRMLS_DC); -typedef HashTable* php_serialize_data_t; +struct php_serialize_data { + HashTable ht; + uint32_t n; +}; struct php_unserialize_data { void *first; @@ -47,71 +50,67 @@ struct php_unserialize_data { void *last_dtor; }; -typedef struct php_unserialize_data* php_unserialize_data_t; +typedef struct php_serialize_data *php_serialize_data_t; +typedef struct php_unserialize_data *php_unserialize_data_t; -PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *var_hash TSRMLS_DC); +PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *data TSRMLS_DC); PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); PHPAPI int php_var_unserialize_ref(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); PHPAPI int php_var_unserialize_intern(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); -#define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ +#define PHP_VAR_SERIALIZE_INIT(d) \ do { \ /* fprintf(stderr, "SERIALIZE_INIT == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */ \ if (BG(serialize_lock) || !BG(serialize).level) { \ - ALLOC_HASHTABLE(var_hash_ptr); \ - zend_hash_init((var_hash_ptr), 16, NULL, NULL, 0); \ + (d) = (php_serialize_data_t) emalloc(sizeof(struct php_serialize_data)); \ + zend_hash_init(&(d)->ht, 16, NULL, ZVAL_PTR_DTOR, 0); \ + (d)->n = 0; \ if (!BG(serialize_lock)) { \ - BG(serialize).var_hash = (void *)(var_hash_ptr); \ + BG(serialize).data = d; \ BG(serialize).level = 1; \ } \ } else { \ - (var_hash_ptr) = (php_serialize_data_t)BG(serialize).var_hash; \ + (d) = BG(serialize).data; \ ++BG(serialize).level; \ } \ } while(0) -#define PHP_VAR_SERIALIZE_DESTROY(var_hash_ptr) \ +#define PHP_VAR_SERIALIZE_DESTROY(d) \ do { \ /* fprintf(stderr, "SERIALIZE_DESTROY == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */ \ - if (BG(serialize_lock) || !BG(serialize).level) { \ - zend_hash_destroy((var_hash_ptr)); \ - FREE_HASHTABLE(var_hash_ptr); \ - } else { \ - if (!--BG(serialize).level) { \ - zend_hash_destroy((php_serialize_data_t)BG(serialize).var_hash); \ - FREE_HASHTABLE((php_serialize_data_t)BG(serialize).var_hash); \ - BG(serialize).var_hash = NULL; \ - } \ + if (BG(serialize_lock) || BG(serialize).level == 1) { \ + zend_hash_destroy(&(d)->ht); \ + efree((d)); \ + } \ + if (!BG(serialize_lock) && !--BG(serialize).level) { \ + BG(serialize).data = NULL; \ } \ } while (0) -#define PHP_VAR_UNSERIALIZE_INIT(var_hash_ptr) \ +#define PHP_VAR_UNSERIALIZE_INIT(d) \ do { \ /* fprintf(stderr, "UNSERIALIZE_INIT == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */ \ if (BG(serialize_lock) || !BG(unserialize).level) { \ - (var_hash_ptr) = (php_unserialize_data_t)ecalloc(1, sizeof(struct php_unserialize_data)); \ + (d) = (php_unserialize_data_t)ecalloc(1, sizeof(struct php_unserialize_data)); \ if (!BG(serialize_lock)) { \ - BG(unserialize).var_hash = (void *)(var_hash_ptr); \ + BG(unserialize).data = (d); \ BG(unserialize).level = 1; \ } \ } else { \ - (var_hash_ptr) = (php_unserialize_data_t)BG(unserialize).var_hash; \ + (d) = BG(unserialize).data; \ ++BG(unserialize).level; \ } \ } while (0) -#define PHP_VAR_UNSERIALIZE_DESTROY(var_hash_ptr) \ +#define PHP_VAR_UNSERIALIZE_DESTROY(d) \ do { \ /* fprintf(stderr, "UNSERIALIZE_DESTROY == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */ \ - if (BG(serialize_lock) || !BG(unserialize).level) { \ - var_destroy(&(var_hash_ptr)); \ - efree(var_hash_ptr); \ - } else { \ - if (!--BG(unserialize).level) { \ - var_destroy(&(var_hash_ptr)); \ - efree((var_hash_ptr)); \ - BG(unserialize).var_hash = NULL; \ - } \ + if (BG(serialize_lock) || BG(unserialize).level == 1) { \ + var_destroy(&(d)); \ + efree((d)); \ + } \ + if (!BG(serialize_lock) && !--BG(unserialize).level) { \ + BG(unserialize).data = NULL; \ } \ } while (0) @@ -120,50 +119,4 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hash, zval *val); PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval *rval); PHPAPI void var_destroy(php_unserialize_data_t *var_hash); -PHPAPI zend_class_entry *php_create_empty_class(char *class_name, int len); - -static inline int php_varname_check(char *name, int name_len, zend_bool silent TSRMLS_DC) /* {{{ */ -{ - if (name_len == sizeof("GLOBALS") - 1 && !memcmp(name, "GLOBALS", sizeof("GLOBALS") - 1)) { - if (!silent) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted GLOBALS variable overwrite"); - } - return FAILURE; - } else if (name[0] == '_' && - ( - (name_len == sizeof("_GET") - 1 && !memcmp(name, "_GET", sizeof("_GET") - 1)) || - (name_len == sizeof("_POST") - 1 && !memcmp(name, "_POST", sizeof("_POST") - 1)) || - (name_len == sizeof("_COOKIE") - 1 && !memcmp(name, "_COOKIE", sizeof("_COOKIE") - 1)) || - (name_len == sizeof("_ENV") - 1 && !memcmp(name, "_ENV", sizeof("_ENV") - 1)) || - (name_len == sizeof("_SERVER") - 1 && !memcmp(name, "_SERVER", sizeof("_SERVER") - 1)) || - (name_len == sizeof("_SESSION") - 1 && !memcmp(name, "_SESSION", sizeof("_SESSION") - 1)) || - (name_len == sizeof("_FILES") - 1 && !memcmp(name, "_FILES", sizeof("_FILES") - 1)) || - (name_len == sizeof("_REQUEST") -1 && !memcmp(name, "_REQUEST", sizeof("_REQUEST") - 1)) - ) - ) { - if (!silent) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted super-global (%s) variable overwrite", name); - } - return FAILURE; - } else if (name[0] == 'H' && - ( - (name_len == sizeof("HTTP_POST_VARS") - 1 && !memcmp(name, "HTTP_POST_VARS", sizeof("HTTP_POST_VARS") - 1)) || - (name_len == sizeof("HTTP_GET_VARS") - 1 && !memcmp(name, "HTTP_GET_VARS", sizeof("HTTP_GET_VARS") - 1)) || - (name_len == sizeof("HTTP_COOKIE_VARS") - 1 && !memcmp(name, "HTTP_COOKIE_VARS", sizeof("HTTP_COOKIE_VARS") - 1)) || - (name_len == sizeof("HTTP_ENV_VARS") - 1 && !memcmp(name, "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS") - 1)) || - (name_len == sizeof("HTTP_SERVER_VARS") - 1 && !memcmp(name, "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS") - 1)) || - (name_len == sizeof("HTTP_SESSION_VARS") - 1 && !memcmp(name, "HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS") - 1)) || - (name_len == sizeof("HTTP_RAW_POST_DATA") - 1 && !memcmp(name, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA") - 1)) || - (name_len == sizeof("HTTP_POST_FILES") - 1 && !memcmp(name, "HTTP_POST_FILES", sizeof("HTTP_POST_FILES") - 1)) - ) - ) { - if (!silent) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted long input array (%s) overwrite", name); - } - return FAILURE; - } - return SUCCESS; -} -/* }}} */ - #endif /* PHP_VAR_H */ diff --git a/ext/standard/var.c b/ext/standard/var.c index f9d897a4ec..194715edf0 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -598,54 +598,45 @@ PHP_FUNCTION(var_export) } /* }}} */ -static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC); +static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash TSRMLS_DC); -static inline int php_add_var_hash(HashTable *var_hash, zval *var_ptr, zval *var_old TSRMLS_DC) /* {{{ */ +static inline uint32_t php_add_var_hash(php_serialize_data_t data, zval *var TSRMLS_DC) /* {{{ */ { - zval var_no, *zv; - char id[32], *p; - register int len; - zval *var = var_ptr; + zval *zv; + zend_ulong key; - if (Z_ISREF_P(var)) { - var = Z_REFVAL_P(var); - } - if ((Z_TYPE_P(var) == IS_OBJECT) && Z_OBJ_HT_P(var)->get_class_entry) { - p = zend_print_long_to_buf(id + sizeof(id) - 1, - (zend_long) Z_OBJ_P(var)); - *(--p) = 'O'; - len = id + sizeof(id) - 1 - p; - } else if (var_ptr != var) { - p = zend_print_long_to_buf(id + sizeof(id) - 1, - (zend_long) Z_REF_P(var_ptr)); - *(--p) = 'R'; - len = id + sizeof(id) - 1 - p; - } else { - p = zend_print_long_to_buf(id + sizeof(id) - 1, (zend_long) var); - len = id + sizeof(id) - 1 - p; + data->n += 1; + + if (Z_TYPE_P(var) != IS_OBJECT && Z_TYPE_P(var) != IS_REFERENCE) { + return 0; } - if ((zv = zend_hash_str_find(var_hash, p, len)) != NULL) { - ZVAL_COPY_VALUE(var_old, zv); - if (var == var_ptr) { - /* we still need to bump up the counter, since non-refs will - * be counted separately by unserializer */ - ZVAL_LONG(&var_no, -1); - zend_hash_next_index_insert(var_hash, &var_no); - } -#if 0 - fprintf(stderr, "- had var (%d): %lu\n", Z_TYPE_P(var), **(zend_ulong**)var_old); -#endif - return FAILURE; + /* References to objects are treated as if the reference didn't exist */ + if (Z_TYPE_P(var) == IS_REFERENCE && Z_TYPE_P(Z_REFVAL_P(var)) == IS_OBJECT) { + var = Z_REFVAL_P(var); } - /* +1 because otherwise hash will think we are trying to store NULL pointer */ - ZVAL_LONG(&var_no, zend_hash_num_elements(var_hash) + 1); - zend_hash_str_add(var_hash, p, len, &var_no); -#if 0 - fprintf(stderr, "+ add var (%d): %lu\n", Z_TYPE_P(var), Z_LVAL(var_no)); -#endif - return SUCCESS; + /* Index for the variable is stored using the numeric value of the pointer to + * the zend_refcounted struct */ + key = (zend_ulong) (zend_uintptr_t) Z_COUNTED_P(var); + zv = zend_hash_index_find(&data->ht, key); + + if (zv) { + return Z_LVAL_P(zv); + } else { + zval zv_n; + ZVAL_LONG(&zv_n, data->n); + zend_hash_index_add_new(&data->ht, key, &zv_n); + + /* Additionally to the index, we also store the variable, to ensure that it is + * not destroyed during serialization and its pointer reused. The variable is + * stored at the numeric value of the pointer + 1, which cannot be the location + * of another zend_refcounted structure. */ + zend_hash_index_add_new(&data->ht, key + 1, var); + Z_ADDREF_P(var); + + return 0; + } } /* }}} */ @@ -682,7 +673,7 @@ static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc } /* }}} */ -static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, HashTable *var_hash TSRMLS_DC) /* {{{ */ +static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ { uint32_t count; zend_bool incomplete_class; @@ -780,27 +771,24 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_pt } /* }}} */ -static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC) /* {{{ */ +static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ { - zval var_already; + uint32_t var_already; HashTable *myht; if (EG(exception)) { return; } - ZVAL_UNDEF(&var_already); - - if (var_hash && - php_add_var_hash(var_hash, struc, &var_already TSRMLS_CC) == FAILURE) { + if (var_hash && (var_already = php_add_var_hash(var_hash, struc TSRMLS_CC))) { if (Z_ISREF_P(struc)) { smart_str_appendl(buf, "R:", 2); - smart_str_append_long(buf, Z_LVAL(var_already)); + smart_str_append_long(buf, var_already); smart_str_appendc(buf, ';'); return; } else if (Z_TYPE_P(struc) == IS_OBJECT) { smart_str_appendl(buf, "r:", 2); - smart_str_append_long(buf, Z_LVAL(var_already)); + smart_str_append_long(buf, var_already); smart_str_appendc(buf, ';'); return; } @@ -971,9 +959,9 @@ again: } /* }}} */ -PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *var_hash TSRMLS_DC) /* {{{ */ +PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *data TSRMLS_DC) /* {{{ */ { - php_var_serialize_intern(buf, struc, *var_hash TSRMLS_CC); + php_var_serialize_intern(buf, struc, *data TSRMLS_CC); smart_str_0(buf); } /* }}} */ diff --git a/win32/build/config.w32 b/win32/build/config.w32 index a7b525075d..f0689c2792 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -354,7 +354,7 @@ STDOUT.WriteLine("PHP Core: " + get_define('PHPDLL') + " and " + get_define('PH ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ zend_ini_parser.c zend_ini_scanner.c zend_alloc.c zend_compile.c \ - zend_constants.c zend_dynamic_array.c zend_exceptions.c \ + zend_constants.c zend_exceptions.c \ zend_execute_API.c zend_highlight.c \ zend_llist.c zend_vm_opcodes.c zend_opcode.c zend_operators.c zend_ptr_stack.c \ zend_stack.c zend_variables.c zend.c zend_API.c zend_extensions.c \ diff --git a/win32/build/projectgen.js b/win32/build/projectgen.js index 8adb887786..0ed8cc404b 100644 --- a/win32/build/projectgen.js +++ b/win32/build/projectgen.js @@ -46,7 +46,6 @@ function write_src_file(fname, path, intpath, arr) if (arr[i].match('alloca.c') || arr[i].match(/internal_functions_(nw|win32)\.c/) || arr[i].match(/flock\.(c|h)/) || - arr[i].match(/zend_static_allocator\.(c|h)/) || arr[i].match(/zend_(ini|language)_scanner_defs\.h/)) { continue; } |