1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Replace calls to in_array() with constant array by IN_ARRAY instruction after SCCP.

This commit is contained in:
Dmitry Stogov
2017-07-05 13:17:30 +03:00
parent 4e8fa2c3dd
commit e8908946e5

View File

@@ -579,6 +579,122 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
}
}
if (ZEND_FUNC_INFO(op_array)) {
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
if (func_info->callee_info) {
zend_call_info *call_info = func_info->callee_info;
static zend_function *in_array_function = NULL;
if (!in_array_function) {
in_array_function = zend_hash_str_find_ptr(CG(function_table), "in_array", sizeof("in_array")-1);
}
do {
if (call_info->callee_func == in_array_function
&& (call_info->caller_init_opline->extended_value == 2
|| (call_info->caller_init_opline->extended_value == 3
&& (call_info->caller_call_opline - 1)->opcode == ZEND_SEND_VAL
&& (call_info->caller_call_opline - 1)->op1_type == IS_CONST))) {
zend_op *send_array;
zend_op *send_needly;
zend_bool strict = 0;
if (call_info->caller_init_opline->extended_value == 2) {
send_array = call_info->caller_call_opline - 1;
send_needly = call_info->caller_call_opline - 2;
} else {
if (zend_is_true(CT_CONSTANT_EX(op_array, (call_info->caller_call_opline - 1)->op1.constant))) {
strict = 1;
}
send_array = call_info->caller_call_opline - 2;
send_needly = call_info->caller_call_opline - 3;
}
if (send_array->opcode == ZEND_SEND_VAL
&& send_array->op1_type == IS_CONST
&& Z_TYPE_P(CT_CONSTANT_EX(op_array, send_array->op1.constant)) == IS_ARRAY
&& (send_needly->opcode == ZEND_SEND_VAL
|| send_needly->opcode == ZEND_SEND_VAR)
) {
int ok = 1;
HashTable *src = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, send_array->op1.constant));
HashTable *dst;
zval *val, tmp;
zend_ulong idx;
ZVAL_TRUE(&tmp);
dst = emalloc(sizeof(HashTable));
zend_hash_init(dst, zend_hash_num_elements(src), NULL, ZVAL_PTR_DTOR, 0);
if (strict) {
ZEND_HASH_FOREACH_VAL(src, val) {
if (Z_TYPE_P(val) == IS_STRING) {
zend_hash_add(dst, Z_STR_P(val), &tmp);
} else if (Z_TYPE_P(val) == IS_LONG) {
zend_hash_index_add(dst, Z_LVAL_P(val), &tmp);
} else {
zend_array_destroy(dst);
ok = 0;
break;
}
} ZEND_HASH_FOREACH_END();
} else {
ZEND_HASH_FOREACH_VAL(src, val) {
if (Z_TYPE_P(val) != IS_STRING || ZEND_HANDLE_NUMERIC(Z_STR_P(val), idx)) {
zend_array_destroy(dst);
ok = 0;
break;
}
zend_hash_add(dst, Z_STR_P(val), &tmp);
} ZEND_HASH_FOREACH_END();
}
if (ok) {
uint32_t op_num = send_needly - op_array->opcodes;
zend_ssa_op *ssa_op = ssa->ops + op_num;
if (ssa_op->op1_use >= 0) {
/* Reconstruct SSA */
int var_num = ssa_op->op1_use;
zend_ssa_var *var = ssa->vars + var_num;
ZEND_ASSERT(ssa_op->op1_def < 0);
zend_ssa_unlink_use_chain(ssa, op_num, ssa_op->op1_use);
ssa_op->op1_use = -1;
ssa_op->op1_use_chain = -1;
op_num = call_info->caller_call_opline - op_array->opcodes;
ssa_op = ssa->ops + op_num;
ssa_op->op1_use = var_num;
ssa_op->op1_use_chain = var->use_chain;
var->use_chain = op_num;
}
ZVAL_ARR(&tmp, dst);
/* Update opcode */
call_info->caller_call_opline->opcode = ZEND_IN_ARRAY;
call_info->caller_call_opline->extended_value = strict;
call_info->caller_call_opline->op1_type = send_needly->op1_type;
call_info->caller_call_opline->op1.num = send_needly->op1.num;
call_info->caller_call_opline->op2_type = IS_CONST;
call_info->caller_call_opline->op2.constant = zend_optimizer_add_literal(op_array, &tmp);
if (call_info->caller_init_opline->extended_value == 3) {
MAKE_NOP(call_info->caller_call_opline - 1);
}
MAKE_NOP(call_info->caller_init_opline);
MAKE_NOP(send_needly);
MAKE_NOP(send_array);
remove_nops = 1;
}
}
}
call_info = call_info->next_callee;
} while (call_info);
}
}
if (remove_nops) {
zend_ssa_remove_nops(op_array, ssa);
}