Skip to content

Commit e890894

Browse files
committed
Replace calls to in_array() with constant array by IN_ARRAY instruction after SCCP.
1 parent 4e8fa2c commit e890894

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

ext/opcache/Optimizer/dfa_pass.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,122 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
579579
}
580580
}
581581

582+
if (ZEND_FUNC_INFO(op_array)) {
583+
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
584+
585+
if (func_info->callee_info) {
586+
zend_call_info *call_info = func_info->callee_info;
587+
static zend_function *in_array_function = NULL;
588+
589+
if (!in_array_function) {
590+
in_array_function = zend_hash_str_find_ptr(CG(function_table), "in_array", sizeof("in_array")-1);
591+
}
592+
do {
593+
if (call_info->callee_func == in_array_function
594+
&& (call_info->caller_init_opline->extended_value == 2
595+
|| (call_info->caller_init_opline->extended_value == 3
596+
&& (call_info->caller_call_opline - 1)->opcode == ZEND_SEND_VAL
597+
&& (call_info->caller_call_opline - 1)->op1_type == IS_CONST))) {
598+
599+
zend_op *send_array;
600+
zend_op *send_needly;
601+
zend_bool strict = 0;
602+
603+
if (call_info->caller_init_opline->extended_value == 2) {
604+
send_array = call_info->caller_call_opline - 1;
605+
send_needly = call_info->caller_call_opline - 2;
606+
} else {
607+
if (zend_is_true(CT_CONSTANT_EX(op_array, (call_info->caller_call_opline - 1)->op1.constant))) {
608+
strict = 1;
609+
}
610+
send_array = call_info->caller_call_opline - 2;
611+
send_needly = call_info->caller_call_opline - 3;
612+
}
613+
614+
if (send_array->opcode == ZEND_SEND_VAL
615+
&& send_array->op1_type == IS_CONST
616+
&& Z_TYPE_P(CT_CONSTANT_EX(op_array, send_array->op1.constant)) == IS_ARRAY
617+
&& (send_needly->opcode == ZEND_SEND_VAL
618+
|| send_needly->opcode == ZEND_SEND_VAR)
619+
) {
620+
int ok = 1;
621+
622+
HashTable *src = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, send_array->op1.constant));
623+
HashTable *dst;
624+
zval *val, tmp;
625+
zend_ulong idx;
626+
627+
ZVAL_TRUE(&tmp);
628+
dst = emalloc(sizeof(HashTable));
629+
zend_hash_init(dst, zend_hash_num_elements(src), NULL, ZVAL_PTR_DTOR, 0);
630+
if (strict) {
631+
ZEND_HASH_FOREACH_VAL(src, val) {
632+
if (Z_TYPE_P(val) == IS_STRING) {
633+
zend_hash_add(dst, Z_STR_P(val), &tmp);
634+
} else if (Z_TYPE_P(val) == IS_LONG) {
635+
zend_hash_index_add(dst, Z_LVAL_P(val), &tmp);
636+
} else {
637+
zend_array_destroy(dst);
638+
ok = 0;
639+
break;
640+
}
641+
} ZEND_HASH_FOREACH_END();
642+
} else {
643+
ZEND_HASH_FOREACH_VAL(src, val) {
644+
if (Z_TYPE_P(val) != IS_STRING || ZEND_HANDLE_NUMERIC(Z_STR_P(val), idx)) {
645+
zend_array_destroy(dst);
646+
ok = 0;
647+
break;
648+
}
649+
zend_hash_add(dst, Z_STR_P(val), &tmp);
650+
} ZEND_HASH_FOREACH_END();
651+
}
652+
653+
if (ok) {
654+
uint32_t op_num = send_needly - op_array->opcodes;
655+
zend_ssa_op *ssa_op = ssa->ops + op_num;
656+
657+
if (ssa_op->op1_use >= 0) {
658+
/* Reconstruct SSA */
659+
int var_num = ssa_op->op1_use;
660+
zend_ssa_var *var = ssa->vars + var_num;
661+
662+
ZEND_ASSERT(ssa_op->op1_def < 0);
663+
zend_ssa_unlink_use_chain(ssa, op_num, ssa_op->op1_use);
664+
ssa_op->op1_use = -1;
665+
ssa_op->op1_use_chain = -1;
666+
op_num = call_info->caller_call_opline - op_array->opcodes;
667+
ssa_op = ssa->ops + op_num;
668+
ssa_op->op1_use = var_num;
669+
ssa_op->op1_use_chain = var->use_chain;
670+
var->use_chain = op_num;
671+
}
672+
673+
ZVAL_ARR(&tmp, dst);
674+
675+
/* Update opcode */
676+
call_info->caller_call_opline->opcode = ZEND_IN_ARRAY;
677+
call_info->caller_call_opline->extended_value = strict;
678+
call_info->caller_call_opline->op1_type = send_needly->op1_type;
679+
call_info->caller_call_opline->op1.num = send_needly->op1.num;
680+
call_info->caller_call_opline->op2_type = IS_CONST;
681+
call_info->caller_call_opline->op2.constant = zend_optimizer_add_literal(op_array, &tmp);
682+
if (call_info->caller_init_opline->extended_value == 3) {
683+
MAKE_NOP(call_info->caller_call_opline - 1);
684+
}
685+
MAKE_NOP(call_info->caller_init_opline);
686+
MAKE_NOP(send_needly);
687+
MAKE_NOP(send_array);
688+
remove_nops = 1;
689+
690+
}
691+
}
692+
}
693+
call_info = call_info->next_callee;
694+
} while (call_info);
695+
}
696+
}
697+
582698
if (remove_nops) {
583699
zend_ssa_remove_nops(op_array, ssa);
584700
}

0 commit comments

Comments
 (0)