]> granicus.if.org Git - php/commitdiff
Convert "sparse switch" statements into sequences of "if" with the most probable...
authorDmitry Stogov <dmitry@zend.com>
Wed, 10 Jan 2018 12:12:03 +0000 (15:12 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 10 Jan 2018 12:12:03 +0000 (15:12 +0300)
Zend/zend_operators.c

index 849163e2df30e2c2d2e3805b8c67f20938120e7c..a8af4bf3f722075871596f93a7d2b80b4d60d870 100644 (file)
@@ -911,58 +911,60 @@ ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {
        int converted = 0;
 
        while (1) {
-               switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
-                       case TYPE_PAIR(IS_LONG, IS_LONG):
-                               fast_long_add_function(result, op1, op2);
-                               return SUCCESS;
-                       case TYPE_PAIR(IS_LONG, IS_DOUBLE):
-                               ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
-                               return SUCCESS;
+               zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
 
-                       case TYPE_PAIR(IS_DOUBLE, IS_LONG):
-                               ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
-                               return SUCCESS;
+               if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
+                       fast_long_add_function(result, op1, op2);
+                       return SUCCESS;
 
-                       case 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_DOUBLE, IS_DOUBLE))) {
+                       ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
+                       return SUCCESS;
 
-                       case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
-                               if ((result == op1) && (result == op2)) {
-                                       /* $a += $a */
-                                       return SUCCESS;
-                               }
-                               if (result != op1) {
-                                       ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
-                               } else {
-                                       SEPARATE_ARRAY(result);
-                               }
-                               zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
+               } 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 if (EXPECTED(type_pair == TYPE_PAIR(IS_ARRAY, IS_ARRAY))) {
+                       if ((result == op1) && (result == op2)) {
+                               /* $a += $a */
                                return SUCCESS;
+                       }
+                       if (result != op1) {
+                               ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
+                       } else {
+                               SEPARATE_ARRAY(result);
+                       }
+                       zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
+                       return SUCCESS;
 
-                       default:
-                               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);
+               } 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_ADD, add_function);
 
-                                       if (EXPECTED(op1 != op2)) {
-                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
-                                       } else {
-                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               op2 = op1;
-                                       }
-                                       converted = 1;
+                               if (EXPECTED(op1 != op2)) {
+                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
                                } else {
-                                       if (result != op1) {
-                                               ZVAL_UNDEF(result);
-                                       }
-                                       zend_throw_error(NULL, "Unsupported operand types");
-                                       return FAILURE; /* unknown datatype */
+                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       op2 = op1;
                                }
+                               converted = 1;
+                       } else {
+                               if (result != op1) {
+                                       ZVAL_UNDEF(result);
+                               }
+                               zend_throw_error(NULL, "Unsupported operand types");
+                               return FAILURE; /* unknown datatype */
+                       }
                }
        }
 }
@@ -974,45 +976,47 @@ ZEND_API int ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {
        int converted = 0;
 
        while (1) {
-               switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
-                       case TYPE_PAIR(IS_LONG, IS_LONG):
-                               fast_long_sub_function(result, op1, op2);
-                               return SUCCESS;
-                       case TYPE_PAIR(IS_LONG, IS_DOUBLE):
-                               ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
-                               return SUCCESS;
+               zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
 
-                       case TYPE_PAIR(IS_DOUBLE, IS_LONG):
-                               ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
-                               return SUCCESS;
+               if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
+                       fast_long_sub_function(result, op1, op2);
+                       return SUCCESS;
 
-                       case 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_DOUBLE, IS_DOUBLE))) {
+                       ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
+                       return SUCCESS;
 
-                       default:
-                               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);
+               } 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 (EXPECTED(op1 != op2)) {
-                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
-                                       } else {
-                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               op2 = op1;
-                                       }
-                                       converted = 1;
+               } 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 {
+                       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)) {
+                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
                                } else {
-                                       if (result != op1) {
-                                               ZVAL_UNDEF(result);
-                                       }
-                                       zend_throw_error(NULL, "Unsupported operand types");
-                                       return FAILURE; /* unknown datatype */
+                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       op2 = op1;
+                               }
+                               converted = 1;
+                       } else {
+                               if (result != op1) {
+                                       ZVAL_UNDEF(result);
                                }
+                               zend_throw_error(NULL, "Unsupported operand types");
+                               return FAILURE; /* unknown datatype */
+                       }
                }
        }
 }
@@ -1024,50 +1028,50 @@ ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {
        int converted = 0;
 
        while (1) {
-               switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
-                       case TYPE_PAIR(IS_LONG, IS_LONG): {
-                               zend_long overflow;
+               zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
 
-                               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;
+               if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
+                       zend_long overflow;
 
-                       }
-                       case TYPE_PAIR(IS_LONG, IS_DOUBLE):
-                               ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
-                               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;
 
-                       case TYPE_PAIR(IS_DOUBLE, IS_LONG):
-                               ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
-                               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;
 
-                       case 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;
 
-                       default:
-                               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);
+               } 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 (EXPECTED(op1 != op2)) {
-                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
-                                       } else {
-                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               op2 = op1;
-                                       }
-                                       converted = 1;
+               } 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);
+
+                               if (EXPECTED(op1 != op2)) {
+                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
                                } else {
-                                       if (result != op1) {
-                                               ZVAL_UNDEF(result);
-                                       }
-                                       zend_throw_error(NULL, "Unsupported operand types");
-                                       return FAILURE; /* unknown datatype */
+                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       op2 = op1;
                                }
+                               converted = 1;
+                       } else {
+                               if (result != op1) {
+                                       ZVAL_UNDEF(result);
+                               }
+                               zend_throw_error(NULL, "Unsupported operand types");
+                               return FAILURE; /* unknown datatype */
+                       }
                }
        }
 }
@@ -1079,96 +1083,97 @@ ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {
        int converted = 0;
 
        while (1) {
-               switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
-                       case 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);
+               zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
 
-                                       if (i == 0) {
-                                               ZVAL_LONG(result, 1L);
-                                               return SUCCESS;
-                                       } else if (l2 == 0) {
-                                               ZVAL_LONG(result, 0);
-                                               return SUCCESS;
-                                       }
+               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);
 
-                                       while (i >= 1) {
-                                               zend_long overflow;
-                                               double dval = 0.0;
-
-                                               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;
-                                                       }
+                               if (i == 0) {
+                                       ZVAL_LONG(result, 1L);
+                                       return SUCCESS;
+                               } else if (l2 == 0) {
+                                       ZVAL_LONG(result, 0);
+                                       return SUCCESS;
+                               }
+
+                               while (i >= 1) {
+                                       zend_long overflow;
+                                       double dval = 0.0;
+
+                                       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)));
                                }
-                               return SUCCESS;
+                               /* i == 0 */
+                               ZVAL_LONG(result, l1);
+                       } else {
+                               ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
+                       }
+                       return SUCCESS;
 
-                       case 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_DOUBLE))) {
+                       ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
+                       return SUCCESS;
 
-                       case TYPE_PAIR(IS_DOUBLE, IS_LONG):
-                               ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_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;
 
-                       case 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_DOUBLE, IS_LONG))) {
+                       ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
+                       return SUCCESS;
 
-                       default:
-                               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);
+               } 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 (EXPECTED(op1 != op2)) {
-                                               if (Z_TYPE_P(op1) == IS_ARRAY) {
-                                                       ZVAL_LONG(result, 0);
-                                                       return SUCCESS;
-                                               } else {
-                                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               }
-                                               if (Z_TYPE_P(op2) == IS_ARRAY) {
-                                                       ZVAL_LONG(result, 1L);
-                                                       return SUCCESS;
-                                               } else {
-                                                       zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
-                                               }
+                               if (EXPECTED(op1 != op2)) {
+                                       if (Z_TYPE_P(op1) == IS_ARRAY) {
+                                               ZVAL_LONG(result, 0);
+                                               return SUCCESS;
                                        } else {
-                                               if (Z_TYPE_P(op1) == IS_ARRAY) {
-                                                       ZVAL_LONG(result, 0);
-                                                       return SUCCESS;
-                                               } else {
-                                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               }
-                                               op2 = op1;
+                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       }
+                                       if (Z_TYPE_P(op2) == IS_ARRAY) {
+                                               ZVAL_LONG(result, 1L);
+                                               return SUCCESS;
+                                       } else {
+                                               zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
                                        }
-                                       converted = 1;
                                } else {
-                                       if (result != op1) {
-                                               ZVAL_UNDEF(result);
+                                       if (Z_TYPE_P(op1) == IS_ARRAY) {
+                                               ZVAL_LONG(result, 0);
+                                               return SUCCESS;
+                                       } else {
+                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
                                        }
-                                       zend_throw_error(NULL, "Unsupported operand types");
-                                       return FAILURE;
+                                       op2 = op1;
+                               }
+                               converted = 1;
+                       } else {
+                               if (result != op1) {
+                                       ZVAL_UNDEF(result);
                                }
+                               zend_throw_error(NULL, "Unsupported operand types");
+                               return FAILURE;
+                       }
                }
        }
 }
@@ -1180,68 +1185,69 @@ ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {
        int converted = 0;
 
        while (1) {
-               switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
-                       case 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;
+               zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
 
-                       case 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));
+               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;
-
-                       case 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));
+                       } 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;
 
-                       case 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_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;
 
-                       default:
-                               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);
+               } 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;
 
-                                       if (EXPECTED(op1 != op2)) {
-                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
-                                       } else {
-                                               zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
-                                               op2 = op1;
-                                       }
-                                       converted = 1;
+               } 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 {
+                       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);
+
+                               if (EXPECTED(op1 != op2)) {
+                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
                                } else {
-                                       if (result != op1) {
-                                               ZVAL_UNDEF(result);
-                                       }
-                                       zend_throw_error(NULL, "Unsupported operand types");
-                                       return FAILURE; /* unknown datatype */
+                                       zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
+                                       op2 = op1;
                                }
+                               converted = 1;
+                       } else {
+                               if (result != op1) {
+                                       ZVAL_UNDEF(result);
+                               }
+                               zend_throw_error(NULL, "Unsupported operand types");
+                               return FAILURE; /* unknown datatype */
+                       }
                }
        }
 }