Index: Zend/zend_operators.c =================================================================== RCS file: /repository/ZendEngine2/zend_operators.c,v retrieving revision 1.302 diff -u -r1.302 zend_operators.c --- Zend/zend_operators.c 18 Mar 2009 11:25:47 -0000 1.302 +++ Zend/zend_operators.c 19 Mar 2009 00:26:41 -0000 @@ -47,6 +47,15 @@ #define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2)) +#define ZVAL_LONG64_SET(z, value) { \ + zend_long64 __result = (zend_long64) (value); \ + if (__result > LONG_MAX || __result < LONG_MIN) { \ + ZVAL_DOUBLE(z, (double) __result); \ + } else { \ + ZVAL_LONG(z, (long) __result); \ + } \ + } + ZEND_API int zend_atoi(const char *str, int str_len) /* {{{ */ { int retval; @@ -308,6 +317,47 @@ /* }}} */ +/* {{{ zendi_convert_to_double */ +#define zendi_convert_to_double(op, holder, result) \ + if (Z_TYPE_P(op) != IS_DOUBLE) { \ + if (op == result) { \ + convert_to_double(op); \ + } else { \ + switch (Z_TYPE_P(op)) { \ + case IS_NULL: \ + Z_DVAL(holder) = 0; \ + break; \ + case IS_BOOL: \ + case IS_LONG: \ + case IS_RESOURCE: \ + Z_DVAL(holder) = (double) Z_LVAL_P(op); \ + break; \ + case IS_STRING: \ + Z_DVAL(holder) = zend_strtod(Z_STRVAL_P(op), NULL); \ + break; \ + case IS_UNICODE: \ + Z_DVAL(holder) = zend_u_strtod(Z_USTRVAL_P(op), NULL); \ + break; \ + case IS_ARRAY: \ + Z_DVAL(holder) = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0); \ + break; \ + case IS_OBJECT: \ + (holder) = (*(op)); \ + zval_copy_ctor(&(holder)); \ + convert_to_double(&(holder)); \ + break; \ + default: \ + zend_error(E_WARNING, "Cannot convert to real value (type=%d)", Z_TYPE_P(op)); \ + Z_DVAL(holder) = 0; \ + break; \ + } \ + Z_TYPE(holder) = IS_DOUBLE; \ + (op) = &(holder); \ + } \ + } + +/* }}} */ + /* {{{ zendi_convert_to_boolean */ #define zendi_convert_to_boolean(op, holder, result) \ if (op==result) { \ @@ -1475,8 +1525,34 @@ { zval op1_copy, op2_copy; +#if SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + zend_long64 op2_64; + + zendi_convert_to_double(op1, op1_copy, result); + zendi_convert_to_double(op2, op2_copy, result); + + op2_64 = (zend_long64) Z_DVAL_P(op2); + + if (op2_64 == 0) { + zend_error(E_WARNING, "Division by zero"); + ZVAL_BOOL(result, 0); + return FAILURE; /* modulus by zero */ + } + + if (op2_64 == -1) { + /* Prevent overflow error/crash if op1==-2^63 */ + ZVAL_LONG(result, 0); + return SUCCESS; + } + + ZVAL_LONG64_SET(result, (zend_long64) Z_DVAL_P(op1) % op2_64); + return SUCCESS; + } +#else zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); +#endif if (Z_LVAL_P(op2) == 0) { zend_error(E_WARNING, "Division by zero"); @@ -1523,18 +1599,21 @@ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { - zval op1_copy = *op1; - - op1 = &op1_copy; - if (Z_TYPE_P(op1) == IS_LONG) { ZVAL_LONG(result, ~Z_LVAL_P(op1)); return SUCCESS; } else if (Z_TYPE_P(op1) == IS_DOUBLE) { +#if SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) + ZVAL_LONG64_SET(result, ~(zend_long64) Z_DVAL_P(op1)); +#else ZVAL_LONG(result, ~(long)Z_DVAL_P(op1)); +#endif return SUCCESS; } else if (Z_TYPE_P(op1) == IS_STRING) { int i; + zval op1_copy = *op1; + + op1 = &op1_copy; Z_TYPE_P(result) = Z_TYPE_P(op1); Z_STRVAL_P(result) = estrndup(Z_STRVAL_P(op1), Z_STRLEN_P(op1)); @@ -1583,8 +1662,19 @@ zend_error(E_ERROR, "Unsupported operand types"); return FAILURE; } + +#if SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + zendi_convert_to_double(op1, op1_copy, result); + zendi_convert_to_double(op2, op2_copy, result); + + ZVAL_LONG64_SET(result, (zend_long64) Z_DVAL_P(op1) | (zend_long64) Z_DVAL_P(op2)); + return SUCCESS; + } +#else zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); +#endif Z_TYPE_P(result) = IS_LONG; Z_LVAL_P(result) = Z_LVAL_P(op1) | Z_LVAL_P(op2); @@ -1628,8 +1718,18 @@ return FAILURE; } +#if SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + zendi_convert_to_double(op1, op1_copy, result); + zendi_convert_to_double(op2, op2_copy, result); + + ZVAL_LONG64_SET(result, (zend_long64) Z_DVAL_P(op1) & (zend_long64) Z_DVAL_P(op2)); + return SUCCESS; + } +#else zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); +#endif Z_TYPE_P(result) = IS_LONG; Z_LVAL_P(result) = Z_LVAL_P(op1) & Z_LVAL_P(op2); @@ -1673,8 +1773,18 @@ return FAILURE; } +#if SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + zendi_convert_to_double(op1, op1_copy, result); + zendi_convert_to_double(op2, op2_copy, result); + + ZVAL_LONG64_SET(result, (zend_long64) Z_DVAL_P(op1) ^ (zend_long64) Z_DVAL_P(op2)); + return SUCCESS; + } +#else zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); +#endif Z_TYPE_P(result) = IS_LONG; Z_LVAL_P(result) = Z_LVAL_P(op1) ^ Z_LVAL_P(op2); @@ -1686,10 +1796,20 @@ { zval op1_copy, op2_copy; - zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); + +#if SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) + if (Z_TYPE_P(op1) != IS_LONG) { + zendi_convert_to_double(op1, op1_copy, result); + ZVAL_LONG64_SET(result, (zend_long64) Z_DVAL_P(op1) << Z_LVAL_P(op2)); + } else { + ZVAL_LONG64_SET(result, (zend_long64) Z_LVAL_P(op1) << Z_LVAL_P(op2)); + } +#else + zendi_convert_to_long(op1, op1_copy, result); Z_LVAL_P(result) = Z_LVAL_P(op1) << Z_LVAL_P(op2); Z_TYPE_P(result) = IS_LONG; +#endif return SUCCESS; } /* }}} */ @@ -1698,8 +1818,17 @@ { zval op1_copy, op2_copy; - zendi_convert_to_long(op1, op1_copy, result); zendi_convert_to_long(op2, op2_copy, result); + +#if SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) + if (Z_TYPE_P(op1) != IS_LONG) { + zendi_convert_to_double(op1, op1_copy, result); + ZVAL_LONG64_SET(result, (zend_long64) Z_DVAL_P(op1) >> Z_LVAL_P(op2)); + return SUCCESS; + } +#else + zendi_convert_to_long(op1, op1_copy, result); +#endif Z_LVAL_P(result) = Z_LVAL_P(op1) >> Z_LVAL_P(op2); Z_TYPE_P(result) = IS_LONG; return SUCCESS;