summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2017-07-04 15:10:33 +0300
committerDmitry Stogov <dmitry@zend.com>2017-07-04 15:10:33 +0300
commit6276268b77791884e63bfd1404ebbf64ff5b8385 (patch)
treedcdd4c6cd4676e950f450249ed9eab14285543e8
parent816669af0c0b7d8df24d5cfc36d80987771fff3b (diff)
downloadphp-git-6276268b77791884e63bfd1404ebbf64ff5b8385.tar.gz
Separate constants propagation code shatred between "first" and "block" passes into helper functions.
-rw-r--r--ext/opcache/Optimizer/block_pass.c71
-rw-r--r--ext/opcache/Optimizer/pass1_5.c224
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c89
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h4
4 files changed, 229 insertions, 159 deletions
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
index 0340eb7a11..077088298a 100644
--- a/ext/opcache/Optimizer/block_pass.c
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -194,6 +194,8 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
VAR_SOURCE(op1) = NULL;
literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
+ } else {
+ zval_ptr_dtor_nogc(&c);
}
}
}
@@ -215,6 +217,8 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
VAR_SOURCE(op2) = NULL;
literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
+ } else {
+ zval_ptr_dtor_nogc(&c);
}
}
}
@@ -390,10 +394,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
Tsource[VAR_NUM(opline->op1.var)] = NULL;
break;
}
- if (opline->op1_type == IS_CONST &&
- opline->op2_type == IS_CONST) {
- break;
- }
/* break missing intentionally */
case ZEND_IS_EQUAL:
@@ -723,59 +723,56 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
if (opline->op1_type == IS_CONST &&
opline->op2_type == IS_CONST) {
/* evaluate constant expressions */
- binary_op_type binary_op;
zval result;
- int er;
optimize_constant_binary_op:
- binary_op = get_binary_op(opline->opcode);
- if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
- zval_get_long(&ZEND_OP2_LITERAL(opline)) == 0) {
- SET_VAR_SOURCE(opline);
- opline++;
- continue;
- } else if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) &&
- zval_get_long(&ZEND_OP2_LITERAL(opline)) < 0) {
- SET_VAR_SOURCE(opline);
- opline++;
- continue;
- } else if (zend_binary_op_produces_numeric_string_error(opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline))) {
- SET_VAR_SOURCE(opline);
- opline++;
- continue;
- }
- er = EG(error_reporting);
- EG(error_reporting) = 0;
- if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
+ if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
literal_dtor(&ZEND_OP2_LITERAL(opline));
opline->opcode = ZEND_QM_ASSIGN;
SET_UNUSED(opline->op2);
zend_optimizer_update_op1_const(op_array, opline, &result);
}
- EG(error_reporting) = er;
}
break;
case ZEND_BW_NOT:
if (opline->op1_type == IS_CONST) {
/* evaluate constant unary ops */
- unary_op_type unary_op;
zval result;
optimize_const_unary_op:
- unary_op = get_unary_op(opline->opcode);
- if (unary_op) {
- unary_op(&result, &ZEND_OP1_LITERAL(opline));
+ if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
- } else {
- /* BOOL */
- ZVAL_COPY_VALUE(&result, &ZEND_OP1_LITERAL(opline));
- convert_to_boolean(&result);
- ZVAL_NULL(&ZEND_OP1_LITERAL(opline));
+ opline->opcode = ZEND_QM_ASSIGN;
+ zend_optimizer_update_op1_const(op_array, opline, &result);
+ }
+ }
+ break;
+
+ case ZEND_CAST:
+ if (opline->op1_type == IS_CONST) {
+ /* cast of constant operand */
+ zval result;
+
+ if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ zend_optimizer_update_op1_const(op_array, opline, &result);
+ }
+ }
+ break;
+
+ case ZEND_STRLEN:
+ if (opline->op1_type == IS_CONST) {
+ zval result;
+
+ if (zend_optimizer_eval_strlen(&result, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ opline->opcode = ZEND_QM_ASSIGN;
+ zend_optimizer_update_op1_const(op_array, opline, &result);
}
- opline->opcode = ZEND_QM_ASSIGN;
- zend_optimizer_update_op1_const(op_array, opline, &result);
}
break;
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c
index 8e8759fb58..5374a1887e 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1_5.c
@@ -68,79 +68,45 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_BW_XOR:
case ZEND_BOOL_XOR:
case ZEND_SPACESHIP:
+ case ZEND_CASE:
if (opline->op1_type == IS_CONST &&
opline->op2_type == IS_CONST) {
/* binary operation with constant operands */
- binary_op_type binary_op = get_binary_op(opline->opcode);
- uint32_t tv = opline->result.var; /* temporary variable */
zval result;
- int er;
- if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
- zval_get_long(&ZEND_OP2_LITERAL(opline)) == 0) {
- /* div by 0 */
- break;
- } else if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) &&
- zval_get_long(&ZEND_OP2_LITERAL(opline)) < 0) {
- /* shift by negative number */
- break;
- } else if (zend_binary_op_produces_numeric_string_error(opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline))) {
- /* produces numeric string E_NOTICE/E_WARNING */
- break;
- }
- er = EG(error_reporting);
- EG(error_reporting) = 0;
- /* evaluate constant expression */
- if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) != SUCCESS) {
- EG(error_reporting) = er;
- break;
- }
- EG(error_reporting) = er;
-
- if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
+ if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
literal_dtor(&ZEND_OP2_LITERAL(opline));
- MAKE_NOP(opline);
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
+ MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ SET_UNUSED(opline->op2);
+ zend_optimizer_update_op1_const(op_array, opline, &result);
+ }
}
}
break;
case ZEND_CAST:
- if (opline->op1_type == IS_CONST &&
- opline->extended_value != IS_ARRAY &&
- opline->extended_value != IS_OBJECT &&
- opline->extended_value != IS_RESOURCE &&
- (opline->extended_value != IS_STRING
- || Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_ARRAY)) {
+ if (opline->op1_type == IS_CONST) {
/* cast of constant operand */
- zend_uchar type = opline->result_type;
- uint32_t tv = opline->result.var; /* temporary variable */
- zval res;
- res = ZEND_OP1_LITERAL(opline);
- zval_copy_ctor(&res);
- switch (opline->extended_value) {
- case IS_NULL:
- convert_to_null(&res);
- break;
- case _IS_BOOL:
- convert_to_boolean(&res);
- break;
- case IS_LONG:
- convert_to_long(&res);
- break;
- case IS_DOUBLE:
- convert_to_double(&res);
- break;
- case IS_STRING:
- convert_to_string(&res);
- break;
- }
+ zval result;
- if (zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res)) {
+ if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
- MAKE_NOP(opline);
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, opline->result_type, opline->result.var, &result)) {
+ MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ zend_optimizer_update_op1_const(op_array, opline, &result);
+ }
+ break;
}
- } else if (opline->extended_value == _IS_BOOL) {
+ }
+
+ if (opline->extended_value == _IS_BOOL) {
/* T = CAST(X, IS_BOOL) => T = BOOL(X) */
opline->opcode = ZEND_BOOL;
opline->extended_value = 0;
@@ -149,24 +115,19 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_BW_NOT:
case ZEND_BOOL_NOT:
+ case ZEND_BOOL:
if (opline->op1_type == IS_CONST) {
/* unary operation on constant operand */
- unary_op_type unary_op = get_unary_op(opline->opcode);
zval result;
- uint32_t tv = opline->result.var; /* temporary variable */
- int er;
-
- er = EG(error_reporting);
- EG(error_reporting) = 0;
- if (unary_op(&result, &ZEND_OP1_LITERAL(opline)) != SUCCESS) {
- EG(error_reporting) = er;
- break;
- }
- EG(error_reporting) = er;
- if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
+ if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
- MAKE_NOP(opline);
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
+ MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ zend_optimizer_update_op1_const(op_array, opline, &result);
+ }
}
}
break;
@@ -258,11 +219,15 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
fake_execute_data.func = (zend_function*)op_array;
EG(current_execute_data) = &fake_execute_data;
if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
- uint32_t tv = opline->result.var;
- if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset)) {
- literal_dtor(&ZEND_OP2_LITERAL(opline));
+ literal_dtor(&ZEND_OP2_LITERAL(opline));
+ if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, offset)) {
MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ SET_UNUSED(opline->op2);
+ zend_optimizer_update_op1_const(op_array, opline, offset);
}
}
EG(current_execute_data) = orig_execute_data;
@@ -272,7 +237,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
if (opline->op2_type == IS_CONST &&
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
/* substitute persistent constants */
- uint32_t tv = opline->result.var;
zval c;
if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
@@ -283,9 +247,14 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
if (Z_TYPE(c) == IS_CONSTANT_AST) {
break;
}
- if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
- literal_dtor(&ZEND_OP2_LITERAL(opline));
+ literal_dtor(&ZEND_OP2_LITERAL(opline));
+ if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ SET_UNUSED(opline->op2);
+ zend_optimizer_update_op1_const(op_array, opline, &c);
}
}
break;
@@ -329,7 +298,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
if (ce) {
- uint32_t tv = opline->result.var;
zend_class_constant *cc;
zval *c, t;
@@ -350,14 +318,20 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
zval_copy_ctor(&t);
}
- if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t)) {
- if (opline->op1_type == IS_CONST) {
- literal_dtor(&ZEND_OP1_LITERAL(opline));
- } else if (opline->op1_type == IS_VAR) {
- MAKE_NOP((opline - 1));
- }
- literal_dtor(&ZEND_OP2_LITERAL(opline));
+ if (opline->op1_type == IS_CONST) {
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ } else if (opline->op1_type == IS_VAR) {
+ MAKE_NOP((opline - 1));
+ }
+ literal_dtor(&ZEND_OP2_LITERAL(opline));
+
+ if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &t)) {
MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ SET_UNUSED(opline->op2);
+ zend_optimizer_update_op1_const(op_array, opline, &t);
}
}
}
@@ -469,17 +443,21 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} else {
ZVAL_FALSE(&t);
}
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
- literal_dtor(&ZEND_OP2_LITERAL(init_opline));
- MAKE_NOP(init_opline);
- literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
- MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- zend_string_release(lc_name);
- break;
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ SET_UNUSED(opline->op2);
+ zend_optimizer_update_op1_const(op_array, opline, &t);
}
}
zend_string_release(lc_name);
+ break;
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"extension_loaded", sizeof("extension_loaded")-1) &&
@@ -509,14 +487,19 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
}
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
- literal_dtor(&ZEND_OP2_LITERAL(init_opline));
- MAKE_NOP(init_opline);
- literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
- MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- break;
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ SET_UNUSED(opline->op2);
+ zend_optimizer_update_op1_const(op_array, opline, &t);
}
+ break;
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"constant", sizeof("constant")-1) &&
@@ -524,15 +507,20 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
zval t;
if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
- literal_dtor(&ZEND_OP2_LITERAL(init_opline));
- MAKE_NOP(init_opline);
- literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
- MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- break;
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ SET_UNUSED(opline->op2);
+ zend_optimizer_update_op1_const(op_array, opline, &t);
}
}
+ break;
/* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
@@ -545,17 +533,22 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
zval t;
ZVAL_STR(&t, dirname);
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
- literal_dtor(&ZEND_OP2_LITERAL(init_opline));
- MAKE_NOP(init_opline);
- literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
- MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- break;
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->extended_value = 0;
+ SET_UNUSED(opline->op2);
+ zend_optimizer_update_op1_const(op_array, opline, &t);
}
} else {
zend_string_release(dirname);
}
+ break;
}
}
/* don't colllect constants after any other function call */
@@ -563,28 +556,33 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
}
case ZEND_STRLEN:
- if (opline->op1_type == IS_CONST &&
- Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
+ if (opline->op1_type == IS_CONST) {
zval t;
- ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline)));
- if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &t)) {
+ if (zend_optimizer_eval_strlen(&t, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
- MAKE_NOP(opline);
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &t)) {
+ MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ zend_optimizer_update_op1_const(op_array, opline, &t);
+ }
}
}
break;
case ZEND_DEFINED:
{
zval c;
- uint32_t tv = opline->result.var;
if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
break;
}
ZVAL_TRUE(&c);
- if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
- literal_dtor(&ZEND_OP1_LITERAL(opline));
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
MAKE_NOP(opline);
+ } else {
+ opline->opcode = ZEND_QM_ASSIGN;
+ zend_optimizer_update_op1_const(op_array, opline, &c);
}
}
break;
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 966b472fdb..bf7eb4ba62 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -53,6 +53,86 @@ void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval*
zend_hash_add(ctx->constants, Z_STR_P(name), &val);
}
+int zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zval *op2) /* {{{ */
+{
+ binary_op_type binary_op = get_binary_op(opcode);
+ int er, ret;
+
+ if ((opcode == ZEND_DIV || opcode == ZEND_MOD) &&
+ zval_get_long(op2) == 0) {
+ /* div by 0 */
+ return FAILURE;
+ } else if ((opcode == ZEND_SL || opcode == ZEND_SR) &&
+ zval_get_long(op2) < 0) {
+ /* shift by negative number */
+ return FAILURE;
+ } else if (zend_binary_op_produces_numeric_string_error(opcode, op1, op2)) {
+ /* produces numeric string E_NOTICE/E_WARNING */
+ return FAILURE;
+ }
+
+ er = EG(error_reporting);
+ EG(error_reporting) = 0;
+ ret = binary_op(result, op1, op2);
+ EG(error_reporting) = er;
+
+ return ret;
+}
+/* }}} */
+
+int zend_optimizer_eval_unary_op(zval *result, zend_uchar opcode, zval *op1) /* {{{ */
+{
+ unary_op_type unary_op = get_unary_op(opcode);
+
+ if (unary_op) {
+ return unary_op(result, op1);
+ } else { /* ZEND_BOOL */
+ ZVAL_BOOL(result, zend_is_true(op1));
+ return SUCCESS;
+ }
+}
+/* }}} */
+
+int zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1) /* {{{ */
+{
+ switch (type) {
+ case IS_NULL:
+ ZVAL_NULL(result);
+ return SUCCESS;
+ case _IS_BOOL:
+ ZVAL_BOOL(result, zval_is_true(op1));
+ return SUCCESS;
+ case IS_LONG:
+ ZVAL_LONG(result, zval_get_long(op1));
+ return SUCCESS;
+ case IS_DOUBLE:
+ ZVAL_DOUBLE(result, zval_get_double(op1));
+ return SUCCESS;
+ case IS_STRING:
+ if (Z_TYPE_P(op1) != IS_ARRAY) {
+ ZVAL_STR(result, zval_get_string(op1));
+ return SUCCESS;
+ }
+ break;
+ case IS_ARRAY:
+ ZVAL_COPY(result, op1);
+ convert_to_array(result);
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+int zend_optimizer_eval_strlen(zval *result, zval *op1) /* {{{ */
+{
+ if (Z_TYPE_P(op1) != IS_STRING) {
+ return FAILURE;
+ }
+ ZVAL_LONG(result, Z_STRLEN_P(op1));
+ return SUCCESS;
+}
+/* }}} */
+
int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value)
{
zval *val;
@@ -158,16 +238,13 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
case ZEND_SEPARATE:
case ZEND_SEND_VAR_NO_REF:
case ZEND_SEND_VAR_NO_REF_EX:
- zval_ptr_dtor_nogc(val);
return 0;
case ZEND_VERIFY_RETURN_TYPE:
/* This would require a non-local change.
* zend_optimizer_replace_by_const() supports this. */
- zval_ptr_dtor_nogc(val);
return 0;
case ZEND_CASE:
case ZEND_FETCH_LIST:
- zval_ptr_dtor_nogc(val);
return 0;
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
@@ -198,7 +275,6 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
switch (opline->opcode) {
case ZEND_ASSIGN_REF:
case ZEND_FAST_CALL:
- zval_ptr_dtor_nogc(val);
return 0;
case ZEND_FETCH_CLASS:
case ZEND_INIT_FCALL_BY_NAME:
@@ -229,14 +305,12 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_INIT_DYNAMIC_CALL:
if (Z_TYPE_P(val) == IS_STRING) {
if (zend_memrchr(Z_STRVAL_P(val), ':', Z_STRLEN_P(val))) {
- zval_ptr_dtor_nogc(val);
return 0;
}
if (zend_optimizer_classify_function(Z_STR_P(val), opline->extended_value)) {
/* Dynamic call to various special functions must stay dynamic,
* otherwise would drop a warning */
- zval_ptr_dtor_nogc(val);
return 0;
}
@@ -394,7 +468,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
case ZEND_ASSIGN_DIM:
case ZEND_SEPARATE:
case ZEND_RETURN_BY_REF:
- zval_ptr_dtor_nogc(val);
return 0;
case ZEND_SEND_VAR:
opline->extended_value = 0;
@@ -405,7 +478,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
opline->opcode = ZEND_SEND_VAL_EX;
break;
case ZEND_SEND_VAR_NO_REF:
- zval_ptr_dtor_nogc(val);
return 0;
case ZEND_SEND_VAR_NO_REF_EX:
opline->opcode = ZEND_SEND_VAL;
@@ -507,7 +579,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
|| ZEND_TYPE_CODE(ret_info->type) == IS_CALLABLE
|| !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(val))
|| (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
- zval_ptr_dtor_nogc(val);
return 0;
}
MAKE_NOP(opline);
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
index 39bf62d1a4..b5d4729100 100644
--- a/ext/opcache/Optimizer/zend_optimizer_internal.h
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -74,6 +74,10 @@ int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv);
int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy);
void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value);
int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value);
+int zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zval *op2);
+int zend_optimizer_eval_unary_op(zval *result, zend_uchar opcode, zval *op1);
+int zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1);
+int zend_optimizer_eval_strlen(zval *result, zval *op1);
int zend_optimizer_update_op1_const(zend_op_array *op_array,
zend_op *opline,
zval *val);