Browse Source

Constant evaluation of in_array() (support for more cases).

pull/2637/head
Dmitry Stogov 9 years ago
parent
commit
3754272818
  1. 1
      ext/opcache/Optimizer/dce.c
  2. 52
      ext/opcache/Optimizer/sccp.c

1
ext/opcache/Optimizer/dce.c

@ -118,6 +118,7 @@ static inline zend_bool may_have_side_effects(
case ZEND_FETCH_DIM_IS:
case ZEND_ISSET_ISEMPTY_VAR:
case ZEND_FETCH_IS:
case ZEND_IN_ARRAY:
/* No side effects */
return 0;
case ZEND_JMP:

52
ext/opcache/Optimizer/sccp.c

@ -461,6 +461,42 @@ static inline void ct_eval_type_check(zval *result, uint32_t type, zval *op1) {
}
}
static inline int ct_eval_in_array(zval *result, uint32_t extended_value, zval *op1, zval *op2) {
HashTable *ht;
zend_bool res;
if (Z_TYPE_P(op2) != IS_ARRAY) {
return FAILURE;
}
ht = Z_ARRVAL_P(op2);
if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
res = zend_hash_exists(ht, Z_STR_P(op1));
} else if (extended_value) {
if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
res = zend_hash_index_exists(ht, Z_LVAL_P(op1));
} else {
res = 0;
}
} else if (Z_TYPE_P(op1) <= IS_FALSE) {
res = zend_hash_exists(ht, ZSTR_EMPTY_ALLOC());
} else {
zend_string *key;
zval tmp;
res = 0;
ZEND_HASH_FOREACH_STR_KEY(ht, key) {
ZVAL_STR(&tmp, key);
compare_function(&tmp, op1, &tmp);
if (Z_LVAL(tmp) == 0) {
res = 1;
break;
}
} ZEND_HASH_FOREACH_END();
}
ZVAL_BOOL(result, res);
return SUCCESS;
}
/* The functions chosen here are simple to implement and either likely to affect a branch,
* or just happened to be commonly used with constant operands in WP (need to test other
* applications as well, of course). */
@ -506,7 +542,11 @@ static inline int ct_eval_func_call(
}
return SUCCESS;
} else if (zend_string_equals_literal(name, "in_array")) {
if (num_args != 2 || Z_TYPE_P(args[1]) != IS_ARRAY) {
if ((num_args != 2
&& (num_args != 3
|| (Z_TYPE_P(args[2]) != IS_FALSE
&& Z_TYPE_P(args[2]) != IS_TRUE)))
|| Z_TYPE_P(args[1]) != IS_ARRAY) {
return FAILURE;
}
/* pass */
@ -843,6 +883,16 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
}
SET_RESULT_BOT(result);
break;
case ZEND_IN_ARRAY:
SKIP_IF_TOP(op1);
SKIP_IF_TOP(op2);
if (ct_eval_in_array(&zv, opline->extended_value, op1, op2) == SUCCESS) {
SET_RESULT(result, &zv);
zval_ptr_dtor_nogc(&zv);
break;
}
SET_RESULT_BOT(result);
break;
case ZEND_FETCH_DIM_R:
case ZEND_FETCH_DIM_IS:
case ZEND_FETCH_LIST:

Loading…
Cancel
Save