mirror of
https://github.com/php/php-src.git
synced 2026-04-03 14:12:38 +02:00
- Significantly improve performance of foreach($arr as $data). (Marcus)
This commit is contained in:
@@ -3340,7 +3340,7 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack
|
||||
|
||||
void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC)
|
||||
{
|
||||
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
zend_op *opline;
|
||||
znode result_value, result_key, dummy;
|
||||
zend_bool assign_by_ref=0;
|
||||
|
||||
@@ -3351,6 +3351,9 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore
|
||||
tmp = key;
|
||||
key = value;
|
||||
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 |= 2;
|
||||
}
|
||||
|
||||
if ((key->op_type != IS_UNUSED) && (key->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE)) {
|
||||
@@ -3362,21 +3365,23 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore
|
||||
if (!CG(active_op_array)->opcodes[foreach_token->u.opline_num-1].extended_value) {
|
||||
zend_error(E_COMPILE_ERROR, "Cannot create references to elements of a temporary array expression");
|
||||
}
|
||||
CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value = 1;
|
||||
/* Mark extended_value for assign-by-reference */
|
||||
CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
@@ -3388,10 +3393,18 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore
|
||||
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;
|
||||
}
|
||||
|
||||
if (assign_by_ref) {
|
||||
zend_do_assign_ref(&dummy, value, &result_value TSRMLS_CC);
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
zend_do_assign(&dummy, value, &result_value TSRMLS_CC);
|
||||
}
|
||||
@@ -3399,8 +3412,8 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore
|
||||
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);
|
||||
}
|
||||
zend_do_free(as_token TSRMLS_CC);
|
||||
|
||||
do_begin_loop(TSRMLS_C);
|
||||
INC_BPC(CG(active_op_array));
|
||||
|
||||
@@ -3772,7 +3772,6 @@ int zend_fe_reset_handler(ZEND_OPCODE_HANDLER_ARGS)
|
||||
int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
zval *array = get_zval_ptr(&opline->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
|
||||
zval *result = &EX_T(opline->result.u.var).tmp_var;
|
||||
zval **value, *key;
|
||||
char *str_key;
|
||||
uint str_key_len;
|
||||
@@ -3780,6 +3779,8 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
|
||||
HashTable *fe_ht;
|
||||
zend_object_iterator *iter = NULL;
|
||||
int key_type;
|
||||
/* extended_value & 2 means that the key is also needed */
|
||||
zend_bool use_key = opline->extended_value & 2;
|
||||
|
||||
PZVAL_LOCK(array);
|
||||
|
||||
@@ -3805,10 +3806,12 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
|
||||
|
||||
zend_hash_move_forward(fe_ht);
|
||||
} while (key_type != HASH_KEY_IS_STRING || zend_check_property_access(zobj, str_key TSRMLS_CC) != SUCCESS);
|
||||
zend_unmangle_property_name(str_key, &class_name, &prop_name);
|
||||
str_key_len = strlen(prop_name);
|
||||
str_key = estrndup(prop_name, str_key_len);
|
||||
str_key_len++;
|
||||
if (use_key) {
|
||||
zend_unmangle_property_name(str_key, &class_name, &prop_name);
|
||||
str_key_len = strlen(prop_name);
|
||||
str_key = estrndup(prop_name, str_key_len);
|
||||
str_key_len++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3819,7 +3822,9 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
|
||||
SET_OPCODE(op_array->opcodes+opline->op2.u.opline_num);
|
||||
return 0; /* CHECK_ME */
|
||||
}
|
||||
key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL);
|
||||
if (use_key) {
|
||||
key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL);
|
||||
}
|
||||
zend_hash_move_forward(fe_ht);
|
||||
break;
|
||||
|
||||
@@ -3841,41 +3846,59 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
|
||||
SET_OPCODE(op_array->opcodes+opline->op2.u.opline_num);
|
||||
return 0; /* CHECK_ME */
|
||||
}
|
||||
if (iter->funcs->get_current_key) {
|
||||
key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
|
||||
} else {
|
||||
key_type = HASH_KEY_IS_LONG;
|
||||
int_key = iter->index;
|
||||
if (use_key) {
|
||||
if (iter->funcs->get_current_key) {
|
||||
key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
|
||||
} else {
|
||||
key_type = HASH_KEY_IS_LONG;
|
||||
int_key = iter->index;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
array_init(result);
|
||||
|
||||
if (opline->extended_value) {
|
||||
if (opline->extended_value & 1) {
|
||||
SEPARATE_ZVAL_IF_NOT_REF(value);
|
||||
(*value)->is_ref = 1;
|
||||
}
|
||||
(*value)->refcount++;
|
||||
zend_hash_index_update(result->value.ht, 0, value, sizeof(zval *), NULL);
|
||||
|
||||
ALLOC_ZVAL(key);
|
||||
INIT_PZVAL(key);
|
||||
if (!use_key) {
|
||||
if (opline->extended_value & 1) {
|
||||
EX_T(opline->result.u.var).var.ptr_ptr = value;
|
||||
(*value)->refcount++;
|
||||
} else {
|
||||
zval *result = &EX_T(opline->result.u.var).tmp_var;
|
||||
|
||||
switch (key_type) {
|
||||
case HASH_KEY_IS_STRING:
|
||||
key->value.str.val = str_key;
|
||||
key->value.str.len = str_key_len-1;
|
||||
key->type = IS_STRING;
|
||||
break;
|
||||
case HASH_KEY_IS_LONG:
|
||||
key->value.lval = int_key;
|
||||
key->type = IS_LONG;
|
||||
break;
|
||||
EMPTY_SWITCH_DEFAULT_CASE()
|
||||
*result = **value;
|
||||
zval_copy_ctor(result);
|
||||
}
|
||||
} else {
|
||||
zval *result = &EX_T(opline->result.u.var).tmp_var;
|
||||
|
||||
(*value)->refcount++;
|
||||
|
||||
array_init(result);
|
||||
|
||||
zend_hash_index_update(result->value.ht, 0, value, sizeof(zval *), NULL);
|
||||
|
||||
ALLOC_ZVAL(key);
|
||||
INIT_PZVAL(key);
|
||||
|
||||
switch (key_type) {
|
||||
case HASH_KEY_IS_STRING:
|
||||
key->value.str.val = str_key;
|
||||
key->value.str.len = str_key_len-1;
|
||||
key->type = IS_STRING;
|
||||
break;
|
||||
case HASH_KEY_IS_LONG:
|
||||
key->value.lval = int_key;
|
||||
key->type = IS_LONG;
|
||||
break;
|
||||
EMPTY_SWITCH_DEFAULT_CASE()
|
||||
}
|
||||
zend_hash_index_update(result->value.ht, 1, &key, sizeof(zval *), NULL);
|
||||
}
|
||||
zend_hash_index_update(result->value.ht, 1, &key, sizeof(zval *), NULL);
|
||||
|
||||
NEXT_OPCODE();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user