Browse Source

Merge branch 'PHP-7.2'

* PHP-7.2:
  Remove dead JMP/JMPZ/JMPNZ/JMPZNZ (DCE pass can't remove them)
  Constant evaluation of few more constant functions
  Disabled compile-time constant DOUBLE to STRING evaluation (its result depends on run-time 'precision' setting)
  Update NEWS for 7.2.0beta2
  Update NEWS for PHP 7.2.0beta1
pull/2636/merge
Dmitry Stogov 9 years ago
parent
commit
f2d4205cfa
  1. 83
      ext/opcache/Optimizer/dfa_pass.c
  2. 331
      ext/opcache/Optimizer/sccp.c
  3. 4
      ext/opcache/Optimizer/zend_optimizer.c

83
ext/opcache/Optimizer/dfa_pass.c

@ -450,6 +450,84 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
return removed_ops; return removed_ops;
} }
static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
{
int removed_ops = 0;
int block_num = 0;
while (block_num < ssa->cfg.blocks_count
&& !(ssa->cfg.blocks[block_num].flags & ZEND_BB_REACHABLE)) {
block_num++;
}
while (block_num < ssa->cfg.blocks_count) {
int next_block_num = block_num + 1;
zend_basic_block *block = &ssa->cfg.blocks[block_num];
uint32_t op_num;
zend_op *opline;
zend_ssa_op *op;
while (next_block_num < ssa->cfg.blocks_count
&& !(ssa->cfg.blocks[next_block_num].flags & ZEND_BB_REACHABLE)) {
next_block_num++;
}
if (block->len) {
if (block->successors_count == 2) {
if (block->successors[0] == block->successors[1]) {
op_num = block->start + block->len - 1;
opline = op_array->opcodes + op_num;
switch (opline->opcode) {
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZNZ:
op = ssa->ops + op_num;
if (block->successors[0] == next_block_num) {
if (opline->op1_type & (IS_CV|IS_CONST)) {
zend_ssa_remove_instr(ssa, opline, op);
if (op->op1_use >= 0) {
zend_ssa_unlink_use_chain(ssa, op_num, op->op1_use);
op->op1_use = -1;
op->op1_use_chain = -1;
}
MAKE_NOP(opline);
removed_ops++;
} else {
opline->opcode = ZEND_FREE;
opline->op2.num = 0;
}
} else {
if (opline->op1_type & (IS_CV|IS_CONST)) {
if (op->op1_use >= 0) {
zend_ssa_unlink_use_chain(ssa, op_num, op->op1_use);
op->op1_use = -1;
op->op1_use_chain = -1;
}
opline->opcode = ZEND_JMP;
opline->op1_type = IS_UNUSED;
opline->op1.num = opline->op2.num;
}
}
break;
default:
break;
}
}
} else if (block->successors_count == 1 && block->successors[0] == next_block_num) {
op_num = block->start + block->len - 1;
opline = op_array->opcodes + op_num;
if (opline->opcode == ZEND_JMP) {
MAKE_NOP(opline);
removed_ops++;
}
}
}
block_num = next_block_num;
}
return removed_ops;
}
void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map) void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map)
{ {
if (ctx->debug_level & ZEND_DUMP_BEFORE_DFA_PASS) { if (ctx->debug_level & ZEND_DUMP_BEFORE_DFA_PASS) {
@ -467,6 +545,11 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
if (sccp_optimize_op_array(ctx, op_array, ssa, call_map)) { if (sccp_optimize_op_array(ctx, op_array, ssa, call_map)) {
remove_nops = 1; remove_nops = 1;
} }
if (zend_dfa_optimize_jmps(op_array, ssa)) {
remove_nops = 1;
}
#if ZEND_DEBUG_DFA #if ZEND_DEBUG_DFA
ssa_verify_integrity(op_array, ssa, "after sccp"); ssa_verify_integrity(op_array, ssa, "after sccp");
#endif #endif

331
ext/opcache/Optimizer/sccp.c

@ -501,143 +501,242 @@ static inline int ct_eval_func_call(
zend_function *func; zend_function *func;
int overflow; int overflow;
if (zend_string_equals_literal(name, "chr")) {
zend_long c;
if (num_args != 1 || Z_TYPE_P(args[0]) != IS_LONG) {
return FAILURE;
}
c = Z_LVAL_P(args[0]) & 0xff;
ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
return SUCCESS;
} else if (zend_string_equals_literal(name, "count")) {
if (num_args != 1 || Z_TYPE_P(args[0]) != IS_ARRAY) {
if (num_args == 0) {
if (zend_string_equals_literal(name, "get_magic_quotes_gpc")
|| zend_string_equals_literal(name, "get_magic_quotes_gpc_runtime")
|| zend_string_equals_literal(name, "php_sapi_name")
|| zend_string_equals_literal(name, "imagetypes")
|| zend_string_equals_literal(name, "phpversion")) {
/* pass */
} else {
return FAILURE; return FAILURE;
} }
} else if (num_args == 1) {
if (zend_string_equals_literal(name, "chr")) {
zend_long c;
if (Z_TYPE_P(args[0]) != IS_LONG) {
return FAILURE;
}
ZVAL_LONG(result, zend_hash_num_elements(Z_ARRVAL_P(args[0])));
return SUCCESS;
} else if (zend_string_equals_literal(name, "ini_get")) {
zend_ini_entry *ini_entry;
c = Z_LVAL_P(args[0]) & 0xff;
ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
return SUCCESS;
} else if (zend_string_equals_literal(name, "count")) {
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
return FAILURE;
}
if (num_args != 1 || Z_TYPE_P(args[0]) != IS_STRING) {
return FAILURE;
}
ZVAL_LONG(result, zend_hash_num_elements(Z_ARRVAL_P(args[0])));
return SUCCESS;
} else if (zend_string_equals_literal(name, "ini_get")) {
zend_ini_entry *ini_entry;
ini_entry = zend_hash_find_ptr(EG(ini_directives), Z_STR_P(args[0]));
if (!ini_entry) {
ZVAL_FALSE(result);
} else if (ini_entry->modifiable != ZEND_INI_SYSTEM) {
return FAILURE;
} else if (ini_entry->value) {
ZVAL_STR_COPY(result, ini_entry->value);
} else {
ZVAL_EMPTY_STRING(result);
}
return SUCCESS;
} else if (zend_string_equals_literal(name, "in_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 */
} else if (zend_string_equals_literal(name, "strpos")) {
if (num_args != 2
|| Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_STRING
|| !Z_STRLEN_P(args[1])) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "array_key_exists")) {
if (num_args != 2 || Z_TYPE_P(args[1]) != IS_ARRAY ||
(Z_TYPE_P(args[0]) != IS_LONG && Z_TYPE_P(args[0]) != IS_STRING
&& Z_TYPE_P(args[0]) != IS_NULL)) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "trim")
|| zend_string_equals_literal(name, "rtrim")
|| zend_string_equals_literal(name, "ltrim")) {
if ((num_args < 1 || num_args > 2) || Z_TYPE_P(args[0]) != IS_STRING
|| (num_args == 2 && Z_TYPE_P(args[1]) != IS_STRING)) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "array_keys")
|| zend_string_equals_literal(name, "array_values")) {
if (num_args != 1 || Z_TYPE_P(args[0]) != IS_ARRAY) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "array_flip")) {
zval *entry;
if (Z_TYPE_P(args[0]) != IS_STRING) {
return FAILURE;
}
if (num_args != 1 || Z_TYPE_P(args[0]) != IS_ARRAY) {
return FAILURE;
}
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
if (Z_TYPE_P(entry) != IS_LONG && Z_TYPE_P(entry) != IS_STRING) {
ini_entry = zend_hash_find_ptr(EG(ini_directives), Z_STR_P(args[0]));
if (!ini_entry) {
ZVAL_FALSE(result);
} else if (ini_entry->modifiable != ZEND_INI_SYSTEM) {
return FAILURE; return FAILURE;
} else if (ini_entry->value) {
ZVAL_STR_COPY(result, ini_entry->value);
} else {
ZVAL_EMPTY_STRING(result);
} }
} ZEND_HASH_FOREACH_END();
/* pass */
} else if (zend_string_equals_literal(name, "str_repeat")) {
if (num_args != 2
|| Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_LONG
|| zend_safe_address(Z_STRLEN_P(args[0]), Z_LVAL_P(args[1]), 0, &overflow) > 64 * 1024
|| overflow) {
return FAILURE;
}
/* pass */
} else if ((zend_string_equals_literal(name, "array_merge")
|| zend_string_equals_literal(name, "array_replace")
|| zend_string_equals_literal(name, "array_merge_recursive")
|| zend_string_equals_literal(name, "array_merge_recursive")
|| zend_string_equals_literal(name, "array_diff")
|| zend_string_equals_literal(name, "array_diff_assoc")
|| zend_string_equals_literal(name, "array_diff_key"))
&& num_args > 0) {
for (i = 0; i < num_args; i++) {
if (Z_TYPE_P(args[i]) != IS_ARRAY) {
return SUCCESS;
} else if (zend_string_equals_literal(name, "trim")
|| zend_string_equals_literal(name, "rtrim")
|| zend_string_equals_literal(name, "ltrim")
|| zend_string_equals_literal(name, "str_split")
|| zend_string_equals_literal(name, "preg_quote")
|| zend_string_equals_literal(name, "base64_encode")
|| zend_string_equals_literal(name, "base64_decode")
|| zend_string_equals_literal(name, "urlencode")
|| zend_string_equals_literal(name, "urldecode")
|| zend_string_equals_literal(name, "rawurlencode")
|| zend_string_equals_literal(name, "rawurldecode")
|| zend_string_equals_literal(name, "php_uname")) {
if (Z_TYPE_P(args[0]) != IS_STRING) {
return FAILURE; return FAILURE;
} }
}
/* pass */
} else if (zend_string_equals_literal(name, "implode")) {
zval *entry;
/* pass */
} else if (zend_string_equals_literal(name, "array_keys")
|| zend_string_equals_literal(name, "array_values")) {
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "array_flip")) {
zval *entry;
if (!(num_args == 1 && Z_TYPE_P(args[0]) == IS_ARRAY)
&& !(num_args == 2 && Z_TYPE_P(args[0]) == IS_STRING && Z_TYPE_P(args[1]) == IS_ARRAY)
&& !(num_args == 2 && Z_TYPE_P(args[0]) == IS_ARRAY && Z_TYPE_P(args[1]) == IS_STRING)) {
return FAILURE;
}
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
return FAILURE;
}
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
if (Z_TYPE_P(entry) != IS_LONG && Z_TYPE_P(entry) != IS_STRING) {
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
/* pass */
} else if (zend_string_equals_literal(name, "implode")) {
zval *entry;
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
return FAILURE;
}
if (Z_TYPE_P(args[0]) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) { ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
if (Z_TYPE_P(entry) > IS_STRING) { if (Z_TYPE_P(entry) > IS_STRING) {
return FAILURE; return FAILURE;
} }
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
/* pass */
} else if (zend_string_equals_literal(name, "serialize")) {
/* pass */
} else { } else {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[1]), entry) {
if (Z_TYPE_P(entry) > IS_STRING) {
return FAILURE;
}
} else if (num_args == 2) {
if (zend_string_equals_literal(name, "in_array")) {
if (Z_TYPE_P(args[1]) != IS_ARRAY) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "strpos")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_STRING
|| !Z_STRLEN_P(args[1])) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "str_split")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_LONG
|| !Z_LVAL_P(args[1]) <= 0) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "array_key_exists")) {
if (Z_TYPE_P(args[1]) != IS_ARRAY
|| (Z_TYPE_P(args[0]) != IS_LONG
&& Z_TYPE_P(args[0]) != IS_STRING
&& Z_TYPE_P(args[0]) != IS_NULL)) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "trim")
|| zend_string_equals_literal(name, "rtrim")
|| zend_string_equals_literal(name, "ltrim")
|| zend_string_equals_literal(name, "preg_quote")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_STRING) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "str_repeat")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_LONG
|| zend_safe_address(Z_STRLEN_P(args[0]), Z_LVAL_P(args[1]), 0, &overflow) > 64 * 1024
|| overflow) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "array_merge")
|| zend_string_equals_literal(name, "array_replace")
|| zend_string_equals_literal(name, "array_merge_recursive")
|| zend_string_equals_literal(name, "array_merge_recursive")
|| zend_string_equals_literal(name, "array_diff")
|| zend_string_equals_literal(name, "array_diff_assoc")
|| zend_string_equals_literal(name, "array_diff_key")) {
for (i = 0; i < num_args; i++) {
if (Z_TYPE_P(args[i]) != IS_ARRAY) {
return FAILURE; return FAILURE;
} }
} ZEND_HASH_FOREACH_END();
}
/* pass */
} else if (zend_string_equals_literal(name, "implode")) {
zval *entry;
if ((Z_TYPE_P(args[0]) != IS_STRING || Z_TYPE_P(args[1]) != IS_ARRAY)
&& (Z_TYPE_P(args[0]) != IS_ARRAY || Z_TYPE_P(args[1]) != IS_STRING)) {
return FAILURE;
}
if (Z_TYPE_P(args[0]) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
if (Z_TYPE_P(entry) > IS_STRING) {
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
} else {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[1]), entry) {
if (Z_TYPE_P(entry) > IS_STRING) {
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
}
/* pass */
} else if (zend_string_equals_literal(name, "version_compare")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_STRING) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "substr")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_LONG) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "pow")) {
if ((Z_TYPE_P(args[0]) != IS_LONG && Z_TYPE_P(args[0]) != IS_DOUBLE)
|| (Z_TYPE_P(args[1]) != IS_LONG && Z_TYPE_P(args[1]) != IS_DOUBLE)) {
return FAILURE;
}
/* pass */
} else {
return FAILURE;
} }
/* pass */
} else if (zend_string_equals_literal(name, "version_comapre")) {
if ((num_args != 2 && (num_args != 3 || Z_TYPE_P(args[2]) != IS_STRING))
|| Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_STRING) {
} else if (num_args == 3) {
if (zend_string_equals_literal(name, "in_array")) {
if (Z_TYPE_P(args[1]) != IS_ARRAY
|| (Z_TYPE_P(args[2]) != IS_FALSE
&& Z_TYPE_P(args[2]) != IS_TRUE)) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "array_merge")
|| zend_string_equals_literal(name, "array_replace")
|| zend_string_equals_literal(name, "array_merge_recursive")
|| zend_string_equals_literal(name, "array_merge_recursive")
|| zend_string_equals_literal(name, "array_diff")
|| zend_string_equals_literal(name, "array_diff_assoc")
|| zend_string_equals_literal(name, "array_diff_key")) {
for (i = 0; i < num_args; i++) {
if (Z_TYPE_P(args[i]) != IS_ARRAY) {
return FAILURE;
}
}
/* pass */
} else if (zend_string_equals_literal(name, "version_compare")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_STRING
|| Z_TYPE_P(args[2]) != IS_STRING) {
return FAILURE;
}
/* pass */
} else if (zend_string_equals_literal(name, "substr")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_LONG
|| Z_TYPE_P(args[2]) != IS_LONG) {
return FAILURE;
}
/* pass */
} else {
return FAILURE; return FAILURE;
} }
/* pass */
} else { } else {
return FAILURE; return FAILURE;
} }
@ -1059,8 +1158,8 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
break; break;
} }
/* We're only interested in functions with one, two or three arguments right now */
if (call->num_args == 0 || call->num_args > 3) {
/* We're only interested in functions with up to three arguments right now */
if (call->num_args > 3) {
SET_RESULT_BOT(result); SET_RESULT_BOT(result);
break; break;
} }

4
ext/opcache/Optimizer/zend_optimizer.c

@ -163,7 +163,9 @@ int zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1) /* {{{ */
ZVAL_DOUBLE(result, zval_get_double(op1)); ZVAL_DOUBLE(result, zval_get_double(op1));
return SUCCESS; return SUCCESS;
case IS_STRING: case IS_STRING:
if (Z_TYPE_P(op1) != IS_ARRAY) {
/* Conversion from double to string takes into account run-time
'precision' setting and cannot be evaluated at compile-time */
if (Z_TYPE_P(op1) != IS_ARRAY && Z_TYPE_P(op1) != IS_DOUBLE) {
ZVAL_STR(result, zval_get_string(op1)); ZVAL_STR(result, zval_get_string(op1));
return SUCCESS; return SUCCESS;
} }

Loading…
Cancel
Save