From 4638f7b91407c48710007af82a68da0007c820f2 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 28 Jan 2015 07:43:28 +0300 Subject: Change "foreach" statement behavior (this is just a PoC yet) - "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented) --- Zend/zend_compile.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'Zend/zend_compile.c') diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 7476d475de..e37fdd778c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3396,30 +3396,22 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ } opnum_reset = get_next_op_number(CG(active_op_array)); - opline = zend_emit_op(&reset_node, ZEND_FE_RESET, &expr_node, NULL); - if (by_ref && is_variable) { - opline->extended_value = ZEND_FE_FETCH_BYREF; - } + opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL); zend_stack_push(&CG(loop_var_stack), &reset_node); opnum_fetch = get_next_op_number(CG(active_op_array)); - opline = zend_emit_op(&value_node, ZEND_FE_FETCH, &reset_node, NULL); - if (by_ref) { - opline->extended_value |= ZEND_FE_FETCH_BYREF; - } + opline = zend_emit_op(&value_node, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL); if (key_ast) { - opline->extended_value |= ZEND_FE_FETCH_WITH_KEY; + opline->extended_value = 1; } opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL); - /* Allocate enough space to keep HashPointer on VM stack */ - opline->op1_type = IS_TMP_VAR; - opline->op1.var = get_temporary_variable(CG(active_op_array)); - if (sizeof(HashPointer) > sizeof(zval)) { - /* Make sure 1 zval is enough for HashPointer (2 must be enough) */ - get_temporary_variable(CG(active_op_array)); + if (by_ref) { + /* Allocate temporary variable to keep HashTable value */ + opline->op1_type = IS_TMP_VAR; + opline->op1.var = get_temporary_variable(CG(active_op_array)); } if (key_ast) { -- cgit v1.2.1 From 15a23b1218b3e38630d677751a975907daa2cd54 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 29 Jan 2015 21:05:02 +0300 Subject: Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details) --- Zend/zend_compile.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'Zend/zend_compile.c') diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e37fdd778c..080b31562a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -829,7 +829,7 @@ static int generate_free_loop_var(znode *var) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array)); - opline->opcode = ZEND_FREE; + opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE; SET_NODE(opline->op1, var); SET_UNUSED(opline->op2); } @@ -3398,6 +3398,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ opnum_reset = get_next_op_number(CG(active_op_array)); opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL); + reset_node.flag = by_ref; zend_stack_push(&CG(loop_var_stack), &reset_node); opnum_fetch = get_next_op_number(CG(active_op_array)); @@ -3408,12 +3409,6 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL); - if (by_ref) { - /* Allocate temporary variable to keep HashTable value */ - opline->op1_type = IS_TMP_VAR; - opline->op1.var = get_temporary_variable(CG(active_op_array)); - } - if (key_ast) { zend_make_tmp_result(&key_node, opline); } @@ -3504,6 +3499,7 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ zend_compile_expr(&expr_node, expr_ast); + expr_node.flag = 0; zend_stack_push(&CG(loop_var_stack), &expr_node); zend_begin_loop(); -- cgit v1.2.1 From 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 30 Jan 2015 09:49:35 +0300 Subject: Implement consistent behavior for foreach by value over plain object --- Zend/zend_compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zend/zend_compile.c') diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 080b31562a..79293971e8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3398,7 +3398,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ opnum_reset = get_next_op_number(CG(active_op_array)); opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL); - reset_node.flag = by_ref; + reset_node.flag = 1; /* generate FE_FREE */ zend_stack_push(&CG(loop_var_stack), &reset_node); opnum_fetch = get_next_op_number(CG(active_op_array)); -- cgit v1.2.1