Index: README.PARAMETER_PARSING_API
===================================================================
RCS file: /repository/php-src/README.PARAMETER_PARSING_API,v
retrieving revision 1.7.6.2.2.6
diff -u -r1.7.6.2.2.6 README.PARAMETER_PARSING_API
--- README.PARAMETER_PARSING_API	24 Nov 2008 18:10:36 -0000	1.7.6.2.2.6
+++ README.PARAMETER_PARSING_API	29 May 2009 19:22:00 -0000
@@ -48,6 +48,7 @@
  h  - array (returned as HashTable*)
  H  - array or HASH_OF(object) (returned as HashTable*)
  l  - long (long)
+ L  - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (long)
  o  - object of any type (zval*)
  O  - object of specific type given by class entry (zval*, zend_class_entry)
  r  - resource (zval*)
Index: win32/build/config.w32
===================================================================
RCS file: /repository/php-src/win32/build/config.w32,v
retrieving revision 1.40.2.8.2.10.2.48
diff -u -r1.40.2.8.2.10.2.48 config.w32
--- win32/build/config.w32	24 Apr 2009 15:18:37 -0000	1.40.2.8.2.10.2.48
+++ win32/build/config.w32	17 May 2009 18:16:00 -0000
@@ -324,6 +324,10 @@
 	zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c \
 	zend_float.c");
 
+if (VCVERS == 1200) {
+	AC_DEFINE('ZEND_DVAL_TO_LVAL_CAST_OK', 1);
+}
+
 ADD_SOURCES("main", "main.c snprintf.c spprintf.c safe_mode.c getopt.c fopen_wrappers.c \
 	php_scandir.c php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \
 	strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c network.c \
Index: Zend/Zend.m4
===================================================================
RCS file: /repository/ZendEngine2/Zend.m4,v
retrieving revision 1.58.4.4.2.5
diff -u -r1.58.4.4.2.5 Zend.m4
--- Zend/Zend.m4	2 Dec 2008 16:19:09 -0000	1.58.4.4.2.5
+++ Zend/Zend.m4	10 Apr 2009 15:10:00 -0000
@@ -117,6 +117,38 @@
 ZEND_FP_EXCEPT
 
 ZEND_CHECK_FLOAT_PRECISION
+
+dnl test whether double cast to long preserves least significant bits
+AC_MSG_CHECKING(whether double cast to long preserves least significant bits)
+
+AC_TRY_RUN([
+#include <limits.h>
+
+int main()
+{
+	if (sizeof(long) == 4) {
+		double d = (double) LONG_MIN * LONG_MIN + 2e9;
+
+		if ((long) d == 2e9 && (long) -d == -2e9) {
+			exit(0);
+		}
+	} else if (sizeof(long) == 8) {
+		double correct = 18e18 - ((double) LONG_MIN * -2); /* Subtract ULONG_MAX + 1 */
+
+		if ((long) 18e18 == correct) { /* On 64-bit, only check between LONG_MAX and ULONG_MAX */
+			exit(0);
+		}
+	}
+	exit(1);
+}
+], [
+  AC_DEFINE([ZEND_DVAL_TO_LVAL_CAST_OK], 1, [Define if double cast to long preserves least significant bits])
+  AC_MSG_RESULT(yes)
+], [
+  AC_MSG_RESULT(no)
+], [
+  AC_MSG_RESULT(no)
+])
 	
 ])
 
Index: Zend/zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.296.2.27.2.34.2.63
diff -u -r1.296.2.27.2.34.2.63 zend_API.c
--- Zend/zend_API.c	6 Apr 2009 11:10:31 -0000	1.296.2.27.2.34.2.63
+++ Zend/zend_API.c	9 Apr 2009 20:23:04 -0000
@@ -313,6 +313,7 @@
 
 	switch (c) {
 		case 'l':
+		case 'L':
 			{
 				long *p = va_arg(*va, long *);
 				switch (Z_TYPE_PP(arg)) {
@@ -324,14 +325,33 @@
 							if ((type = is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), p, &d, -1)) == 0) {
 								return "long";
 							} else if (type == IS_DOUBLE) {
-								*p = (long) d;
+								if (c == 'L') {
+									if (d > LONG_MAX) {
+										*p = LONG_MAX;
+										break;
+									} else if (d < LONG_MIN) {
+										*p = LONG_MIN;
+										break;
+									}
+								}
+
+								*p = zend_dval_to_lval(d);
 							}
 						}
 						break;
 
+					case IS_DOUBLE:
+						if (c == 'L') {
+							if (Z_DVAL_PP(arg) > LONG_MAX) {
+								*p = LONG_MAX;
+								break;
+							} else if (Z_DVAL_PP(arg) < LONG_MIN) {
+								*p = LONG_MIN;
+								break;
+							}
+						}
 					case IS_NULL:
 					case IS_LONG:
-					case IS_DOUBLE:
 					case IS_BOOL:
 						convert_to_long_ex(arg);
 						*p = Z_LVAL_PP(arg);
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.647.2.27.2.41.2.107
diff -u -r1.647.2.27.2.41.2.107 zend_compile.c
--- Zend/zend_compile.c	22 Apr 2009 21:27:19 -0000	1.647.2.27.2.41.2.107
+++ Zend/zend_compile.c	17 May 2009 18:14:00 -0000
@@ -3997,7 +3997,6 @@
 	ALLOC_ZVAL(element);
 	*element = expr->u.constant;
 	if (offset) {
-		long l;
 		switch (offset->u.constant.type & IS_CONSTANT_TYPE_MASK) {
 			case IS_CONSTANT:
 				/* Ugly hack to denote that this value has a constant index */
@@ -4020,8 +4019,7 @@
 				zend_hash_index_update(Z_ARRVAL(result->u.constant), Z_LVAL(offset->u.constant), &element, sizeof(zval *), NULL);
 				break;
 			case IS_DOUBLE:
-				DVAL_TO_LVAL(Z_DVAL(offset->u.constant), l);
-				zend_hash_index_update(Z_ARRVAL(result->u.constant), l, &element, sizeof(zval *), NULL);
+				zend_hash_index_update(Z_ARRVAL(result->u.constant), zend_dval_to_lval(Z_DVAL(offset->u.constant)), &element, sizeof(zval *), NULL);
 				break;
 			case IS_CONSTANT_ARRAY:
 				zend_error(E_ERROR, "Illegal offset type");
Index: Zend/zend_execute.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute.c,v
retrieving revision 1.716.2.12.2.24.2.43
diff -u -r1.716.2.12.2.24.2.43 zend_execute.c
--- Zend/zend_execute.c	21 Apr 2009 09:40:13 -0000	1.716.2.12.2.24.2.43
+++ Zend/zend_execute.c	17 May 2009 17:59:12 -0000
@@ -823,10 +823,9 @@
 				}
 			}
 			break;
-		case IS_DOUBLE: {
-			DVAL_TO_LVAL(Z_DVAL_P(dim), index);
+		case IS_DOUBLE:
+			index = zend_dval_to_lval(Z_DVAL_P(dim));
 			goto num_index;
-		}
 		case IS_RESOURCE:
 			zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(dim), Z_LVAL_P(dim));
 			/* Fall Through */
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.331.2.20.2.24.2.76
diff -u -r1.331.2.20.2.24.2.76 zend_execute_API.c
--- Zend/zend_execute_API.c	8 Apr 2009 13:17:58 -0000	1.331.2.20.2.24.2.76
+++ Zend/zend_execute_API.c	9 Apr 2009 20:23:05 -0000
@@ -662,7 +662,7 @@
 					ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL);
 					break;
 				case IS_DOUBLE:
-					ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, (long)Z_DVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL);
+					ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, zend_dval_to_lval(Z_DVAL(const_value)), HASH_UPDATE_KEY_IF_BEFORE, NULL);
 					break;
 				case IS_NULL:
 					ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, "", 1, 0, HASH_UPDATE_KEY_IF_BEFORE, NULL);
Index: Zend/zend_operators.c
===================================================================
RCS file: /repository/ZendEngine2/zend_operators.c,v
retrieving revision 1.208.2.4.2.23.2.26
diff -u -r1.208.2.4.2.23.2.26 zend_operators.c
--- Zend/zend_operators.c	11 May 2009 08:31:15 -0000	1.208.2.4.2.23.2.26
+++ Zend/zend_operators.c	17 May 2009 17:59:12 -0000
@@ -225,7 +225,7 @@
 				Z_LVAL(holder) = 0;									\
 				break;												\
 			case IS_DOUBLE:											\
-				DVAL_TO_LVAL(Z_DVAL_P(op), Z_LVAL(holder));			\
+				Z_LVAL(holder) = zend_dval_to_lval(Z_DVAL_P(op));	\
 				break;												\
 			case IS_STRING:											\
 				Z_LVAL(holder) = strtol(Z_STRVAL_P(op), NULL, 10);	\
@@ -349,7 +349,7 @@
 		case IS_LONG:
 			break;
 		case IS_DOUBLE:
-			DVAL_TO_LVAL(Z_DVAL_P(op), Z_LVAL_P(op));
+			Z_LVAL_P(op) = zend_dval_to_lval(Z_DVAL_P(op));
 			break;
 		case IS_STRING:
 			{
@@ -1017,7 +1017,7 @@
 		ZVAL_LONG(result, ~Z_LVAL_P(op1));
 		return SUCCESS;
 	} else if (Z_TYPE_P(op1) == IS_DOUBLE) {
-		ZVAL_LONG(result, ~(long) Z_DVAL_P(op1));
+		ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
 		return SUCCESS;
 	} else if (Z_TYPE_P(op1) == IS_STRING) {
 		int i;
Index: Zend/zend_operators.h
===================================================================
RCS file: /repository/ZendEngine2/zend_operators.h,v
retrieving revision 1.94.2.4.2.10.2.15
diff -u -r1.94.2.4.2.10.2.15 zend_operators.h
--- Zend/zend_operators.h	10 May 2009 22:39:33 -0000	1.94.2.4.2.10.2.15
+++ Zend/zend_operators.h	17 May 2009 18:10:30 -0000
@@ -63,39 +63,24 @@
 ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC);
 END_EXTERN_C()
 
-/* {{{ DVAL_TO_LVAL */
-#define MAX_UNSIGNED_INT ((double) LONG_MAX * 2) + 1
-#ifdef _WIN64
-# define DVAL_TO_LVAL(d, l) \
-	if ((d) > LONG_MAX) { \
-		(l) = (long)(unsigned long)(__int64) (d); \
-	} else { \
-		(l) = (long) (d); \
-	}
-#elif !defined(_WIN64) && __WORDSIZE == 64
-# define DVAL_TO_LVAL(d, l) \
-	if ((d) >= LONG_MAX) { \
-		(l) = LONG_MAX; \
-	} else if ((d) <= LONG_MIN) { \
-		(l) = LONG_MIN; \
-	} else { \
-		(l) = (long) (d); \
+#if ZEND_DVAL_TO_LVAL_CAST_OK
+# define zend_dval_to_lval(d) ((long) (d))
+#elif SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64)
+static zend_always_inline long zend_dval_to_lval(double d)
+{
+	if (d > LONG_MAX || d < LONG_MIN) {
+		return (long)(unsigned long)(zend_long64) d;
 	}
+	return (long) d;
+}
 #else
-# define DVAL_TO_LVAL(d, l) \
-	if ((d) > LONG_MAX) { \
-		if ((d) > MAX_UNSIGNED_INT) { \
-			(l) = LONG_MAX; \
-		} else { \
-			(l) = (unsigned long) (d); \
-		} \
-	} else { \
-		if((d) < LONG_MIN) { \
-			(l) = LONG_MIN; \
-		} else { \
-			(l) = (long) (d); \
-		} \
+static zend_always_inline long zend_dval_to_lval(double d)
+{
+	if (d > LONG_MAX) {
+		return (long)(unsigned long) d;
 	}
+	return (long) d;
+}
 #endif
 /* }}} */
 
Index: Zend/zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.59.2.29.2.48.2.92
diff -u -r1.59.2.29.2.48.2.92 zend_vm_def.h
--- Zend/zend_vm_def.h	1 Jun 2009 15:07:42 -0000	1.59.2.29.2.48.2.92
+++ Zend/zend_vm_def.h	3 Jun 2009 15:30:00 -0000
@@ -3085,11 +3085,9 @@
 		}
 	}
 	if (offset) {
-	  	long l;
 		switch (Z_TYPE_P(offset)) {
 			case IS_DOUBLE:
-			  	DVAL_TO_LVAL(Z_DVAL_P(offset), l);
-				zend_hash_index_update(Z_ARRVAL_P(array_ptr), l, &expr_ptr, sizeof(zval *), NULL);
+				zend_hash_index_update(Z_ARRVAL_P(array_ptr), zend_dval_to_lval(Z_DVAL_P(offset)), &expr_ptr, sizeof(zval *), NULL);
 				break;
 			case IS_LONG:
 			case IS_BOOL:
@@ -3408,7 +3406,6 @@
 	zend_free_op free_op1, free_op2;
 	zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
 	zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
-	long index;
 
 	if (OP1_TYPE != IS_VAR || container) {
 		if (OP1_TYPE == IS_CV && container != &EG(uninitialized_zval_ptr)) {
@@ -3420,14 +3417,12 @@
 
 				switch (Z_TYPE_P(offset)) {
 					case IS_DOUBLE:
-						index = (long) Z_DVAL_P(offset);
-						zend_hash_index_del(ht, index);
+						zend_hash_index_del(ht, zend_dval_to_lval(Z_DVAL_P(offset)));
 						break;
 					case IS_RESOURCE:
 					case IS_BOOL:
 					case IS_LONG:
-						index = Z_LVAL_P(offset);
-						zend_hash_index_del(ht, index);
+						zend_hash_index_del(ht, Z_LVAL_P(offset));
 						break;
 					case IS_STRING:
 						if (OP2_TYPE == IS_CV || OP2_TYPE == IS_VAR) {
@@ -3907,7 +3902,6 @@
 	zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_IS);
 	zval **value = NULL;
 	int result = 0;
-	long index;
 
 	if (OP1_TYPE != IS_VAR || container) {
 		zend_free_op free_op2;
@@ -3921,16 +3915,14 @@
 
 			switch (Z_TYPE_P(offset)) {
 				case IS_DOUBLE:
-					index = (long) Z_DVAL_P(offset);
-					if (zend_hash_index_find(ht, index, (void **) &value) == SUCCESS) {
+					if (zend_hash_index_find(ht, zend_dval_to_lval(Z_DVAL_P(offset)), (void **) &value) == SUCCESS) {
 						isset = 1;
 					}
 					break;
 				case IS_RESOURCE:
 				case IS_BOOL:
 				case IS_LONG:
-					index = Z_LVAL_P(offset);
-					if (zend_hash_index_find(ht, index, (void **) &value) == SUCCESS) {
+					if (zend_hash_index_find(ht, Z_LVAL_P(offset), (void **) &value) == SUCCESS) {
 						isset = 1;
 					}
 					break;
