summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/add_002.phpt4
-rw-r--r--Zend/tests/add_007.phpt4
-rw-r--r--Zend/tests/compound_assign_failure.phpt10
-rw-r--r--Zend/zend_operators.c584
4 files changed, 293 insertions, 309 deletions
diff --git a/Zend/tests/add_002.phpt b/Zend/tests/add_002.phpt
index 5d862ef729..da99499864 100644
--- a/Zend/tests/add_002.phpt
+++ b/Zend/tests/add_002.phpt
@@ -20,12 +20,8 @@ var_dump($c);
echo "Done\n";
?>
--EXPECTF--
-Notice: Object of class stdClass could not be converted to number in %sadd_002.php on line %d
-
Exception: Unsupported operand types
-Notice: Object of class stdClass could not be converted to number in %s on line %d
-
Fatal error: Uncaught Error: Unsupported operand types in %s:%d
Stack trace:
#0 {main}
diff --git a/Zend/tests/add_007.phpt b/Zend/tests/add_007.phpt
index e490826d8f..e7e0de79ba 100644
--- a/Zend/tests/add_007.phpt
+++ b/Zend/tests/add_007.phpt
@@ -19,12 +19,8 @@ var_dump($c);
echo "Done\n";
?>
--EXPECTF--
-Warning: A non-numeric value encountered in %s on line %d
-
Exception: Unsupported operand types
-Warning: A non-numeric value encountered in %s on line %d
-
Fatal error: Uncaught Error: Unsupported operand types in %s:%d
Stack trace:
#0 {main}
diff --git a/Zend/tests/compound_assign_failure.phpt b/Zend/tests/compound_assign_failure.phpt
index b4563e341f..1780725d93 100644
--- a/Zend/tests/compound_assign_failure.phpt
+++ b/Zend/tests/compound_assign_failure.phpt
@@ -208,19 +208,19 @@ string(3) "foo"
object(stdClass)#%d (0) {
}
int(1)
-int(0)
+string(3) "foo"
object(stdClass)#%d (0) {
}
int(1)
-int(0)
+string(3) "foo"
object(stdClass)#%d (0) {
}
int(1)
-int(0)
+string(3) "foo"
object(stdClass)#%d (0) {
}
int(1)
-int(0)
+string(3) "foo"
object(stdClass)#%d (0) {
}
int(1)
@@ -228,7 +228,7 @@ string(3) "foo"
object(stdClass)#%d (0) {
}
int(1)
-int(0)
+string(3) "foo"
object(stdClass)#%d (0) {
}
int(1)
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index 54298a00a9..af21693f3b 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -145,7 +145,7 @@ ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) /* {
/* }}} */
-static void ZEND_FASTCALL _convert_scalar_to_number(zval *op, zend_bool silent, zend_bool check) /* {{{ */
+ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
{
try_again:
switch (Z_TYPE_P(op)) {
@@ -157,11 +157,8 @@ try_again:
zend_string *str;
str = Z_STR_P(op);
- if ((Z_TYPE_INFO_P(op)=is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &Z_LVAL_P(op), &Z_DVAL_P(op), silent ? 1 : -1)) == 0) {
+ if ((Z_TYPE_INFO_P(op)=is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &Z_LVAL_P(op), &Z_DVAL_P(op), 1)) == 0) {
ZVAL_LONG(op, 0);
- if (!silent) {
- zend_error(E_WARNING, "A non-numeric value encountered");
- }
}
zend_string_release_ex(str, 0);
break;
@@ -185,9 +182,6 @@ try_again:
zval dst;
convert_object_to_type(op, &dst, _IS_NUMBER);
- if (check && UNEXPECTED(EG(exception))) {
- return;
- }
zval_ptr_dtor(op);
if (Z_TYPE(dst) == IS_LONG || Z_TYPE(dst) == IS_DOUBLE) {
@@ -201,14 +195,8 @@ try_again:
}
/* }}} */
-ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
-{
- _convert_scalar_to_number(op, 1, 0);
-}
-/* }}} */
-
-/* {{{ _zendi_convert_scalar_to_number_ex */
-static zend_always_inline zval* _zendi_convert_scalar_to_number_ex(zval *op, zval *holder, zend_bool silent) /* {{{ */
+/* {{{ _zendi_convert_scalar_to_number */
+static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number_silent(zval *op, zval *holder) /* {{{ */
{
switch (Z_TYPE_P(op)) {
case IS_NULL:
@@ -219,11 +207,8 @@ static zend_always_inline zval* _zendi_convert_scalar_to_number_ex(zval *op, zva
ZVAL_LONG(holder, 1);
return holder;
case IS_STRING:
- if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), silent ? 1 : -1)) == 0) {
+ if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), 1)) == 0) {
ZVAL_LONG(holder, 0);
- if (!silent) {
- zend_error(E_WARNING, "A non-numeric value encountered");
- }
}
return holder;
case IS_RESOURCE:
@@ -244,25 +229,52 @@ static zend_always_inline zval* _zendi_convert_scalar_to_number_ex(zval *op, zva
}
/* }}} */
-/* {{{ _zendi_convert_scalar_to_number */
-static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number_silent(zval *op, zval *holder) /* {{{ */
+static zend_never_inline int ZEND_FASTCALL _zendi_try_convert_scalar_to_number(zval *op, zval *holder) /* {{{ */
{
- return _zendi_convert_scalar_to_number_ex(op, holder, 1);
+ switch (Z_TYPE_P(op)) {
+ case IS_NULL:
+ case IS_FALSE:
+ ZVAL_LONG(holder, 0);
+ return SUCCESS;
+ case IS_TRUE:
+ ZVAL_LONG(holder, 1);
+ return SUCCESS;
+ case IS_STRING:
+ if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), -1)) == 0) {
+ ZVAL_LONG(holder, 0);
+ zend_error(E_WARNING, "A non-numeric value encountered");
+ if (UNEXPECTED(EG(exception))) {
+ return FAILURE;
+ }
+ }
+ return SUCCESS;
+ case IS_RESOURCE:
+ ZVAL_LONG(holder, Z_RES_HANDLE_P(op));
+ return SUCCESS;
+ case IS_OBJECT:
+ convert_object_to_type(op, holder, _IS_NUMBER);
+ if (UNEXPECTED(EG(exception))) {
+ return FAILURE;
+ }
+ if (UNEXPECTED(Z_TYPE_P(holder) != IS_LONG && Z_TYPE_P(holder) != IS_DOUBLE)) {
+ ZVAL_LONG(holder, 1);
+ }
+ return SUCCESS;
+ default:
+ return FAILURE;
+ }
}
/* }}} */
-/* {{{ _zendi_convert_scalar_to_number_noisy */
-static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number_noisy(zval *op, zval *holder) /* {{{ */
+static zend_always_inline int zendi_try_convert_scalar_to_number(zval *op, zval *holder)
{
- return _zendi_convert_scalar_to_number_ex(op, holder, 0);
+ if (Z_TYPE_P(op) == IS_LONG || Z_TYPE_P(op) == IS_DOUBLE) {
+ ZVAL_COPY_VALUE(holder, op);
+ return SUCCESS;
+ } else {
+ return _zendi_try_convert_scalar_to_number(op, holder);
+ }
}
-/* }}} */
-
-#define zendi_convert_scalar_to_number_noisy(op, holder, result) \
- ((Z_TYPE_P(op) == IS_LONG || Z_TYPE_P(op) == IS_DOUBLE) ? (op) : \
- (((op) == result) \
- ? (_convert_scalar_to_number((op), /* silent */ 0, 1), (op)) : \
- _zendi_convert_scalar_to_number_noisy((op), holder)))
#define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, op, op_func) \
do { \
@@ -941,42 +953,35 @@ static zend_always_inline int add_function_fast(zval *result, zval *op1, zval *o
static zend_never_inline int ZEND_FASTCALL add_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
{
- zval op1_copy, op2_copy;
- int converted = 0;
+ ZVAL_DEREF(op1);
+ ZVAL_DEREF(op2);
+ if (add_function_fast(result, op1, op2) == SUCCESS) {
+ return SUCCESS;
+ }
- while (1) {
- if (Z_ISREF_P(op1)) {
- op1 = Z_REFVAL_P(op1);
- } else if (Z_ISREF_P(op2)) {
- op2 = Z_REFVAL_P(op2);
- } else if (!converted) {
- ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function);
-
- if (EXPECTED(op1 != op2)) {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result);
- } else {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = op1;
- }
- if (EG(exception)) {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
- return FAILURE;
- }
- converted = 1;
- } else {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
+ ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function);
+
+ zval op1_copy, op2_copy;
+ if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
+ || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
+ if (!EG(exception)) {
zend_throw_error(NULL, "Unsupported operand types");
- return FAILURE; /* unknown datatype */
}
- if (add_function_fast(result, op1, op2) == SUCCESS) {
- return SUCCESS;
+ if (result != op1) {
+ ZVAL_UNDEF(result);
}
+ return FAILURE;
}
+
+ if (result == op1) {
+ zval_ptr_dtor(result);
+ }
+
+ if (add_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
+ return SUCCESS;
+ }
+
+ ZEND_ASSERT(0 && "Operation must succeed");
} /* }}} */
ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
@@ -1013,42 +1018,35 @@ static zend_always_inline int sub_function_fast(zval *result, zval *op1, zval *o
static zend_never_inline int ZEND_FASTCALL sub_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
{
+ ZVAL_DEREF(op1);
+ ZVAL_DEREF(op2);
+ if (sub_function_fast(result, op1, op2) == SUCCESS) {
+ return SUCCESS;
+ }
+
+ ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function);
+
zval op1_copy, op2_copy;
- int converted = 0;
- while (1) {
- if (Z_ISREF_P(op1)) {
- op1 = Z_REFVAL_P(op1);
- } else if (Z_ISREF_P(op2)) {
- op2 = Z_REFVAL_P(op2);
- } else if (!converted) {
- ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function);
-
- if (EXPECTED(op1 != op2)) {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result);
- } else {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = op1;
- }
- if (EG(exception)) {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
- return FAILURE;
- }
- converted = 1;
- } else {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
+ if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
+ || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
+ if (!EG(exception)) {
zend_throw_error(NULL, "Unsupported operand types");
- return FAILURE; /* unknown datatype */
}
- if (sub_function_fast(result, op1, op2) == SUCCESS) {
- return SUCCESS;
+ if (result != op1) {
+ ZVAL_UNDEF(result);
}
+ return FAILURE;
}
+ if (result == op1) {
+ zval_ptr_dtor(result);
+ }
+
+ if (sub_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
+ return SUCCESS;
+ }
+
+ ZEND_ASSERT(0 && "Operation must succeed");
}
/* }}} */
@@ -1062,249 +1060,243 @@ ZEND_API int ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {
}
/* }}} */
-ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
+static zend_always_inline int mul_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
{
- zval op1_copy, op2_copy;
- int converted = 0;
+ zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
- while (1) {
- zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
+ if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
+ zend_long overflow;
+ ZEND_SIGNED_MULTIPLY_LONG(
+ Z_LVAL_P(op1), Z_LVAL_P(op2),
+ Z_LVAL_P(result), Z_DVAL_P(result), overflow);
+ Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
+ ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+}
- if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
- zend_long overflow;
+static zend_never_inline int ZEND_FASTCALL mul_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
+{
+ ZVAL_DEREF(op1);
+ ZVAL_DEREF(op2);
+ if (mul_function_fast(result, op1, op2) == SUCCESS) {
+ return SUCCESS;
+ }
- ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
- Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
- return SUCCESS;
+ ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function);
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
- ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
- return SUCCESS;
+ zval op1_copy, op2_copy;
+ if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
+ || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
+ if (!EG(exception)) {
+ zend_throw_error(NULL, "Unsupported operand types");
+ }
+ if (result != op1) {
+ ZVAL_UNDEF(result);
+ }
+ return FAILURE;
+ }
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
- ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
- return SUCCESS;
+ if (result == op1) {
+ zval_ptr_dtor(result);
+ }
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
- ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
- return SUCCESS;
+ if (mul_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
+ return SUCCESS;
+ }
- } else {
- if (Z_ISREF_P(op1)) {
- op1 = Z_REFVAL_P(op1);
- } else if (Z_ISREF_P(op2)) {
- op2 = Z_REFVAL_P(op2);
- } else if (!converted) {
- ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function);
+ ZEND_ASSERT(0 && "Operation must succeed");
+}
+/* }}} */
- if (EXPECTED(op1 != op2)) {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result);
- } else {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = op1;
- }
- if (EG(exception)) {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
- return FAILURE;
- }
- converted = 1;
- } else {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
- zend_throw_error(NULL, "Unsupported operand types");
- return FAILURE; /* unknown datatype */
- }
- }
+ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
+{
+ if (mul_function_fast(result, op1, op2) == SUCCESS) {
+ return SUCCESS;
+ } else {
+ return mul_function_slow(result, op1, op2);
}
}
/* }}} */
-ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
+static int ZEND_FASTCALL pow_function_base(zval *result, zval *op1, zval *op2) /* {{{ */
{
- zval op1_copy, op2_copy;
- int converted = 0;
-
- while (1) {
- zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
-
- if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
- if (Z_LVAL_P(op2) >= 0) {
- zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
-
- if (i == 0) {
- ZVAL_LONG(result, 1L);
- return SUCCESS;
- } else if (l2 == 0) {
- ZVAL_LONG(result, 0);
- return SUCCESS;
- }
+ zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
- while (i >= 1) {
- zend_long overflow;
- double dval = 0.0;
+ if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
+ if (Z_LVAL_P(op2) >= 0) {
+ zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
- if (i % 2) {
- --i;
- ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
- if (overflow) {
- ZVAL_DOUBLE(result, dval * pow(l2, i));
- return SUCCESS;
- }
- } else {
- i /= 2;
- ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
- if (overflow) {
- ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
- return SUCCESS;
- }
- }
- }
- /* i == 0 */
- ZVAL_LONG(result, l1);
- } else {
- ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
+ if (i == 0) {
+ ZVAL_LONG(result, 1L);
+ return SUCCESS;
+ } else if (l2 == 0) {
+ ZVAL_LONG(result, 0);
+ return SUCCESS;
}
- return SUCCESS;
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
- ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
- return SUCCESS;
+ while (i >= 1) {
+ zend_long overflow;
+ double dval = 0.0;
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
- ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
- return SUCCESS;
-
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
- ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
- return SUCCESS;
-
- } else {
- if (Z_ISREF_P(op1)) {
- op1 = Z_REFVAL_P(op1);
- } else if (Z_ISREF_P(op2)) {
- op2 = Z_REFVAL_P(op2);
- } else if (!converted) {
- ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function);
-
- if (Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY) {
- if (result != op1) {
- ZVAL_UNDEF(result);
+ if (i % 2) {
+ --i;
+ ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
+ if (overflow) {
+ ZVAL_DOUBLE(result, dval * pow(l2, i));
+ return SUCCESS;
}
- zend_throw_error(NULL, "Unsupported operand types");
- return FAILURE;
- }
-
- if (EXPECTED(op1 != op2)) {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result);
} else {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = op1;
- }
-
- if (EG(exception)) {
- if (result != op1) {
- ZVAL_UNDEF(result);
+ i /= 2;
+ ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
+ if (overflow) {
+ ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
+ return SUCCESS;
}
- return FAILURE;
}
- converted = 1;
- } else {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
- zend_throw_error(NULL, "Unsupported operand types");
- return FAILURE;
}
+ /* i == 0 */
+ ZVAL_LONG(result, l1);
+ } else {
+ ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
}
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
+ ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
+ ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
+ ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
+ return SUCCESS;
+ } else {
+ return FAILURE;
}
}
/* }}} */
-#ifdef __clang__
-__attribute__((no_sanitize("float-divide-by-zero")))
-#endif
-ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
+ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
+ ZVAL_DEREF(op1);
+ ZVAL_DEREF(op2);
+ if (pow_function_base(result, op1, op2) == SUCCESS) {
+ return SUCCESS;
+ }
+
+ ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function);
+
zval op1_copy, op2_copy;
- int converted = 0;
+ if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
+ || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
+ if (!EG(exception)) {
+ zend_throw_error(NULL, "Unsupported operand types");
+ }
+ if (result != op1) {
+ ZVAL_UNDEF(result);
+ }
+ return FAILURE;
+ }
- while (1) {
- zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
+ if (result == op1) {
+ zval_ptr_dtor(result);
+ }
- if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
- if (Z_LVAL_P(op2) == 0) {
- zend_error(E_WARNING, "Division by zero");
- ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2)));
- return SUCCESS;
- } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
- /* Prevent overflow error/crash */
- ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
- return SUCCESS;
- }
- if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
- ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
- } else {
- ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
- }
- return SUCCESS;
+ if (pow_function_base(result, &op1_copy, &op2_copy) == SUCCESS) {
+ return SUCCESS;
+ }
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
- if (Z_DVAL_P(op2) == 0) {
- zend_error(E_WARNING, "Division by zero");
- }
- ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
- return SUCCESS;
+ ZEND_ASSERT(0 && "Operation must succeed");
+}
+/* }}} */
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
- if (Z_LVAL_P(op2) == 0) {
- zend_error(E_WARNING, "Division by zero");
- }
- ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
- return SUCCESS;
+#ifdef __clang__
+__attribute__((no_sanitize("float-divide-by-zero")))
+#endif
+static int ZEND_FASTCALL div_function_base(zval *result, zval *op1, zval *op2) /* {{{ */
+{
+ zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
- } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
- if (Z_DVAL_P(op2) == 0) {
- zend_error(E_WARNING, "Division by zero");
- }
- ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
+ if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
+ if (Z_LVAL_P(op2) == 0) {
+ zend_error(E_WARNING, "Division by zero");
+ ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2)));
return SUCCESS;
-
+ } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
+ /* Prevent overflow error/crash */
+ ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
+ return SUCCESS;
+ }
+ if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
+ ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
} else {
- if (Z_ISREF_P(op1)) {
- op1 = Z_REFVAL_P(op1);
- } else if (Z_ISREF_P(op2)) {
- op2 = Z_REFVAL_P(op2);
- } else if (!converted) {
- ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function);
+ ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
+ }
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
+ if (Z_DVAL_P(op2) == 0) {
+ zend_error(E_WARNING, "Division by zero");
+ }
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
+ if (Z_LVAL_P(op2) == 0) {
+ zend_error(E_WARNING, "Division by zero");
+ }
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
+ return SUCCESS;
+ } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
+ if (Z_DVAL_P(op2) == 0) {
+ zend_error(E_WARNING, "Division by zero");
+ }
+ ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+}
- if (EXPECTED(op1 != op2)) {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = zendi_convert_scalar_to_number_noisy(op2, &op2_copy, result);
- } else {
- op1 = zendi_convert_scalar_to_number_noisy(op1, &op1_copy, result);
- op2 = op1;
- }
- if (EG(exception)) {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
- return FAILURE;
- }
- converted = 1;
- } else {
- if (result != op1) {
- ZVAL_UNDEF(result);
- }
- zend_throw_error(NULL, "Unsupported operand types");
- return FAILURE; /* unknown datatype */
- }
+ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
+{
+ ZVAL_DEREF(op1);
+ ZVAL_DEREF(op2);
+ if (div_function_base(result, op1, op2) == SUCCESS) {
+ return SUCCESS;
+ }
+
+ ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function);
+
+ zval op1_copy, op2_copy;
+ if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
+ || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
+ if (!EG(exception)) {
+ zend_throw_error(NULL, "Unsupported operand types");
}
+ if (result != op1) {
+ ZVAL_UNDEF(result);
+ }
+ return FAILURE;
+ }
+
+ if (result == op1) {
+ zval_ptr_dtor(result);
}
+
+ if (div_function_base(result, &op1_copy, &op2_copy) == SUCCESS) {
+ return SUCCESS;
+ }
+
+ ZEND_ASSERT(0 && "Operation must succeed");
}
/* }}} */