From: Dmitry Stogov Date: Mon, 7 Feb 2005 16:09:54 +0000 (+0000) Subject: foreash($a as $key => $val) optimization X-Git-Tag: RELEASE_0_2~27 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fc96c7f7fa18b0fc9216bcc9f94e72a753da7689;p=php foreash($a as $key => $val) optimization Removed temorary array creation on each iteration. --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b893b12fb1..ca4171e8b8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3343,7 +3343,7 @@ void zend_do_instanceof(znode *result, znode *expr, znode *class_znode, int type } -void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable TSRMLS_DC) +void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, int variable TSRMLS_DC) { zend_op *opline; zend_bool is_variable; @@ -3398,21 +3398,27 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FE_FETCH; - opline->result.op_type = IS_TMP_VAR; + opline->result.op_type = IS_VAR; opline->result.u.var = get_temporary_variable(CG(active_op_array)); opline->op1 = *open_brackets_token; opline->extended_value = 0; SET_UNUSED(opline->op2); - *as_token = opline->result; + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_OP_DATA; + opline->op1.op_type = IS_UNUSED; + opline->op2.op_type = IS_UNUSED; + opline->result.op_type = IS_UNUSED; } -void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC) +void zend_do_foreach_cont(znode *value, znode *key, znode *foreach_token TSRMLS_DC) { zend_op *opline; - znode result_value, result_key, dummy; + znode dummy; zend_bool assign_by_ref=0; + opline = &CG(active_op_array)->opcodes[foreach_token->u.opline_num]; if (key->op_type != IS_UNUSED) { znode *tmp; @@ -3422,66 +3428,38 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore value = tmp; /* Mark extended_value in case both key and value are being used */ - CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_FETCH_WITH_KEY; + opline->extended_value |= ZEND_FE_FETCH_WITH_KEY; } if ((key->op_type != IS_UNUSED) && (key->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE)) { zend_error(E_COMPILE_ERROR, "Key element cannot be a reference"); } - + if (value->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE) { assign_by_ref = 1; - if (!CG(active_op_array)->opcodes[foreach_token->u.opline_num-1].extended_value) { + if (!(opline-1)->extended_value) { zend_error(E_COMPILE_ERROR, "Cannot create references to elements of a temporary array expression"); } /* Mark extended_value for assign-by-reference */ - CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_FETCH_BYREF; - } - - if (key->op_type != IS_UNUSED) { - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_FETCH_DIM_TMP_VAR; - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.opline_num = get_temporary_variable(CG(active_op_array)); - opline->op1 = *as_token; - opline->op2.op_type = IS_CONST; - opline->op2.u.constant.type = IS_LONG; - opline->op2.u.constant.value.lval = 0; - opline->extended_value = ZEND_FETCH_STANDARD; /* ignored in fetch_dim_tmp_var, but what the hell. */ - result_value = opline->result; - - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_FETCH_DIM_TMP_VAR; - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.opline_num = get_temporary_variable(CG(active_op_array)); - opline->op1 = *as_token; - opline->op2.op_type = IS_CONST; - opline->op2.u.constant.type = IS_LONG; - opline->op2.u.constant.value.lval = 1; - opline->extended_value = ZEND_FETCH_STANDARD; /* ignored in fetch_dim_tmp_var, but what the hell. */ - result_key = opline->result; - } else { - result_value = CG(active_op_array)->opcodes[foreach_token->u.opline_num].result; + opline->extended_value |= ZEND_FE_FETCH_BYREF; } if (assign_by_ref) { - if (key->op_type == IS_UNUSED) { - /* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */ - CG(active_op_array)->opcodes[foreach_token->u.opline_num].result.op_type = IS_VAR; - zend_do_assign_ref(NULL, value, &CG(active_op_array)->opcodes[foreach_token->u.opline_num].result TSRMLS_CC); - } else { - zend_do_assign_ref(NULL, value, &result_value TSRMLS_CC); - } + /* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */ + zend_do_assign_ref(NULL, value, &opline->result TSRMLS_CC); } else { - zend_do_assign(&dummy, value, &result_value TSRMLS_CC); + zend_do_assign(&dummy, value, &opline->result TSRMLS_CC); + zend_do_free(&dummy TSRMLS_CC); } - CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED; + if (key->op_type != IS_UNUSED) { - zend_do_assign(&dummy, key, &result_key TSRMLS_CC); - CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED; - zend_do_free(as_token TSRMLS_CC); + ++opline; + opline->result.op_type = IS_TMP_VAR; + opline->result.u.EA.type = 0; + opline->result.u.opline_num = get_temporary_variable(CG(active_op_array)); + + zend_do_assign(&dummy, key, &opline->result TSRMLS_CC); + zend_do_free(&dummy TSRMLS_CC); } do_begin_loop(TSRMLS_C); @@ -3489,7 +3467,7 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore } -void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token TSRMLS_DC) +void zend_do_foreach_end(znode *foreach_token TSRMLS_DC) { zend_op *container_ptr; zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 825ffca758..2bf075317d 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -461,9 +461,9 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC void zend_do_instanceof(znode *result, znode *expr, znode *class_znode, int type TSRMLS_DC); -void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable TSRMLS_DC); -void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC); -void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token TSRMLS_DC); +void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, int variable TSRMLS_DC); +void zend_do_foreach_cont(znode *value, znode *key, znode *foreach_token TSRMLS_DC); +void zend_do_foreach_end(znode *foreach_token TSRMLS_DC); void zend_do_declare_begin(TSRMLS_D); void zend_do_declare_stmt(znode *var, znode *val TSRMLS_DC); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 7dd066fb0a..353d712eda 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -209,8 +209,8 @@ unticked_statement: | expr ';' { zend_do_free(&$1 TSRMLS_CC); } | T_USE use_filename ';' { zend_error(E_COMPILE_ERROR,"use: Not yet supported. Please use include_once() or require_once()"); zval_dtor(&$2.u.constant); } | T_UNSET '(' unset_variables ')' ';' - | T_FOREACH '(' variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 1 TSRMLS_CC); } foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); } - | T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 TSRMLS_CC); } w_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); } + | T_FOREACH '(' variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, 1 TSRMLS_CC); } foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1 TSRMLS_CC); } + | T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, 0 TSRMLS_CC); } w_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1 TSRMLS_CC); } | T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); } | ';' /* empty statement */ | T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}' diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index eb1becd4d1..31c41658ba 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2930,7 +2930,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) zend_op *opline = EX(opline); zend_free_op free_op1; zval *array = GET_OP1_ZVAL_PTR(BP_VAR_R); - zval **value, *key; + zval **value; char *str_key; uint str_key_len; ulong int_key; @@ -3018,29 +3018,17 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) if (opline->extended_value & ZEND_FE_FETCH_BYREF) { SEPARATE_ZVAL_IF_NOT_REF(value); (*value)->is_ref = 1; - } - - if (!use_key) { - if (opline->extended_value & ZEND_FE_FETCH_BYREF) { - EX_T(opline->result.u.var).var.ptr_ptr = value; - (*value)->refcount++; - } else { - zval *result = &EX_T(opline->result.u.var).tmp_var; - - *result = **value; - zval_copy_ctor(result); - } - } else { - zval *result = &EX_T(opline->result.u.var).tmp_var; - + EX_T(opline->result.u.var).var.ptr_ptr = value; (*value)->refcount++; + } else { + EX_T(opline->result.u.var).var.ptr_ptr = value; + PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr); + AI_USE_PTR(EX_T(opline->result.u.var).var); + } - array_init(result); - - zend_hash_index_update(result->value.ht, 0, value, sizeof(zval *), NULL); - - ALLOC_ZVAL(key); - INIT_PZVAL(key); + if (use_key) { + zend_op *op_data = opline+1; + zval *key = &EX_T(op_data->result.u.var).tmp_var; switch (key_type) { case HASH_KEY_IS_STRING: @@ -3054,9 +3042,9 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) break; EMPTY_SWITCH_DEFAULT_CASE() } - zend_hash_index_update(result->value.ht, 1, &key, sizeof(zval *), NULL); } + ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 08e0611cc8..29d5101c0a 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7550,7 +7550,7 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zend_free_op free_op1; zval *array = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); - zval **value, *key; + zval **value; char *str_key; uint str_key_len; ulong int_key; @@ -7638,29 +7638,17 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (opline->extended_value & ZEND_FE_FETCH_BYREF) { SEPARATE_ZVAL_IF_NOT_REF(value); (*value)->is_ref = 1; - } - - if (!use_key) { - if (opline->extended_value & ZEND_FE_FETCH_BYREF) { - EX_T(opline->result.u.var).var.ptr_ptr = value; - (*value)->refcount++; - } else { - zval *result = &EX_T(opline->result.u.var).tmp_var; - - *result = **value; - zval_copy_ctor(result); - } - } else { - zval *result = &EX_T(opline->result.u.var).tmp_var; - + EX_T(opline->result.u.var).var.ptr_ptr = value; (*value)->refcount++; + } else { + EX_T(opline->result.u.var).var.ptr_ptr = value; + PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr); + AI_USE_PTR(EX_T(opline->result.u.var).var); + } - array_init(result); - - zend_hash_index_update(result->value.ht, 0, value, sizeof(zval *), NULL); - - ALLOC_ZVAL(key); - INIT_PZVAL(key); + if (use_key) { + zend_op *op_data = opline+1; + zval *key = &EX_T(op_data->result.u.var).tmp_var; switch (key_type) { case HASH_KEY_IS_STRING: @@ -7674,9 +7662,9 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) break; EMPTY_SWITCH_DEFAULT_CASE() } - zend_hash_index_update(result->value.ht, 1, &key, sizeof(zval *), NULL); } + ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); } @@ -30655,7 +30643,7 @@ static int ZEND_FE_FETCH_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zend_free_op free_op1; zval *array = get_zval_ptr(&opline->op1, EX(Ts), &free_op1, BP_VAR_R); - zval **value, *key; + zval **value; char *str_key; uint str_key_len; ulong int_key; @@ -30743,29 +30731,17 @@ static int ZEND_FE_FETCH_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (opline->extended_value & ZEND_FE_FETCH_BYREF) { SEPARATE_ZVAL_IF_NOT_REF(value); (*value)->is_ref = 1; - } - - if (!use_key) { - if (opline->extended_value & ZEND_FE_FETCH_BYREF) { - EX_T(opline->result.u.var).var.ptr_ptr = value; - (*value)->refcount++; - } else { - zval *result = &EX_T(opline->result.u.var).tmp_var; - - *result = **value; - zval_copy_ctor(result); - } - } else { - zval *result = &EX_T(opline->result.u.var).tmp_var; - + EX_T(opline->result.u.var).var.ptr_ptr = value; (*value)->refcount++; + } else { + EX_T(opline->result.u.var).var.ptr_ptr = value; + PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr); + AI_USE_PTR(EX_T(opline->result.u.var).var); + } - array_init(result); - - zend_hash_index_update(result->value.ht, 0, value, sizeof(zval *), NULL); - - ALLOC_ZVAL(key); - INIT_PZVAL(key); + if (use_key) { + zend_op *op_data = opline+1; + zval *key = &EX_T(op_data->result.u.var).tmp_var; switch (key_type) { case HASH_KEY_IS_STRING: @@ -30779,9 +30755,9 @@ static int ZEND_FE_FETCH_HANDLER(ZEND_OPCODE_HANDLER_ARGS) break; EMPTY_SWITCH_DEFAULT_CASE() } - zend_hash_index_update(result->value.ht, 1, &key, sizeof(zval *), NULL); } + ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); }