Last active
August 29, 2015 14:02
-
-
Save hikari-no-yume/08bcb39ed197be10764d to your computer and use it in GitHub Desktop.
Work-in-progress Zend bigint patch (zend_language_scanner.c's massive diff removed for the sake of readability)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From bdec0820b6933a64c388b0451c8ae0914e817aa4 Mon Sep 17 00:00:00 2001 | |
From: Andrea Faulds <ajf@ajf.me> | |
Date: Fri, 6 Jun 2014 02:12:59 +0100 | |
Subject: [PATCH] Working bigints with no tests and some unfixed corner cases | |
--- | |
Zend/Makefile.am | 2 +- | |
Zend/Zend.dsp | 4 + | |
Zend/Zend.m4 | 24 + | |
Zend/ZendTS.dsp | 4 + | |
Zend/zend.c | 5 + | |
Zend/zend.h | 1 + | |
Zend/zend_API.c | 16 + | |
Zend/zend_ast.c | 8 + | |
Zend/zend_bigint.c | 480 ++++ | |
Zend/zend_bigint.h | 213 ++ | |
Zend/zend_builtin_functions.c | 2 + | |
Zend/zend_compile.c | 8 +- | |
Zend/zend_exceptions.c | 8 + | |
Zend/zend_execute.c | 9 + | |
Zend/zend_execute.h | 4 + | |
Zend/zend_language_scanner.c | 5659 +++++++++++++++++++------------------ | |
Zend/zend_language_scanner.l | 26 +- | |
Zend/zend_language_scanner_defs.h | 2 +- | |
Zend/zend_multiply.h | 17 +- | |
Zend/zend_operators.c | 986 ++++++- | |
Zend/zend_operators.h | 56 +- | |
Zend/zend_types.h | 55 +- | |
Zend/zend_variables.c | 24 +- | |
Zend/zend_vm_def.h | 42 + | |
Zend/zend_vm_execute.h | 578 ++++ | |
configure.in | 2 +- | |
ext/standard/type.c | 3 + | |
ext/standard/var.c | 6 + | |
win32/build/config.w32 | 2 +- | |
29 files changed, 5299 insertions(+), 2947 deletions(-) | |
create mode 100644 Zend/zend_bigint.c | |
create mode 100644 Zend/zend_bigint.h | |
diff --git a/Zend/Makefile.am b/Zend/Makefile.am | |
index 65c4113..75a804d 100644 | |
--- a/Zend/Makefile.am | |
+++ b/Zend/Makefile.am | |
@@ -18,7 +18,7 @@ libZend_la_SOURCES=\ | |
zend_default_classes.c \ | |
zend_iterators.c zend_interfaces.c zend_exceptions.c \ | |
zend_strtod.c zend_closures.c zend_float.c zend_string.c zend_signal.c \ | |
- zend_generators.c zend_virtual_cwd.c zend_ast.c | |
+ zend_generators.c zend_virtual_cwd.c zend_ast.c zend_bigint.c | |
libZend_la_LDFLAGS = | |
libZend_la_LIBADD = @ZEND_EXTRA_LIBS@ | |
diff --git a/Zend/Zend.dsp b/Zend/Zend.dsp | |
index 98d368f..74b89ea 100644 | |
--- a/Zend/Zend.dsp | |
+++ b/Zend/Zend.dsp | |
@@ -123,6 +123,10 @@ SOURCE=.\zend_ast.c | |
# End Source File | |
# Begin Source File | |
+SOURCE=.\zend_bigint.c | |
+# End Source File | |
+# Begin Source File | |
+ | |
SOURCE=.\zend_builtin_functions.c | |
# End Source File | |
# Begin Source File | |
diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 | |
index 945409e..a749b31 100644 | |
--- a/Zend/Zend.m4 | |
+++ b/Zend/Zend.m4 | |
@@ -433,3 +433,27 @@ else | |
AC_MSG_RESULT(no) | |
fi | |
fi | |
+ | |
+for i in $PHP_GMP /usr/local /usr; do | |
+ test -f $i/include/gmp.h && GMP_DIR=$i && break | |
+done | |
+ | |
+if test -z "$GMP_DIR"; then | |
+ AC_MSG_ERROR(Unable to locate gmp.h) | |
+fi | |
+ | |
+PHP_CHECK_LIBRARY(gmp, __gmp_randinit_lc_2exp_size, | |
+[],[ | |
+ PHP_CHECK_LIBRARY(gmp, gmp_randinit_lc_2exp_size, | |
+ [],[ | |
+ AC_MSG_ERROR([GNU MP Library version 4.1.2 or greater required.]) | |
+ ],[ | |
+ -L$GMP_DIR/$PHP_LIBDIR | |
+ ]) | |
+],[ | |
+ -L$GMP_DIR/$PHP_LIBDIR | |
+]) | |
+ | |
+PHP_ADD_LIBRARY_WITH_PATH(gmp, $GMP_DIR/$PHP_LIBDIR, GMP_SHARED_LIBADD) | |
+PHP_ADD_INCLUDE($GMP_DIR/include) | |
+AC_DEFINE(HAVE_GMP, 1, [ ]) | |
\ No newline at end of file | |
diff --git a/Zend/ZendTS.dsp b/Zend/ZendTS.dsp | |
index 21210f1..ec70e4d 100644 | |
--- a/Zend/ZendTS.dsp | |
+++ b/Zend/ZendTS.dsp | |
@@ -148,6 +148,10 @@ SOURCE=.\zend_API.c | |
# End Source File | |
# Begin Source File | |
+SOURCE=.\zend_bigint.c | |
+# End Source File | |
+# Begin Source File | |
+ | |
SOURCE=.\zend_builtin_functions.c | |
# End Source File | |
# Begin Source File | |
diff --git a/Zend/zend.c b/Zend/zend.c | |
index a1ffb5f..af6ab57 100644 | |
--- a/Zend/zend.c | |
+++ b/Zend/zend.c | |
@@ -31,6 +31,7 @@ | |
#include "zend_vm.h" | |
#include "zend_dtrace.h" | |
#include "zend_virtual_cwd.h" | |
+#include "zend_bigint.h" | |
#ifdef ZTS | |
# define GLOBAL_FUNCTION_TABLE global_function_table | |
@@ -277,6 +278,9 @@ again: | |
ZVAL_EMPTY_STRING(expr_copy); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ ZVAL_NEW_STR(expr_copy, zend_bigint_to_zend_string(Z_BIG_P(expr), 0)); | |
+ break; | |
case IS_DOUBLE: | |
ZVAL_DUP(expr_copy, expr); | |
zend_locale_sprintf_double(expr_copy ZEND_FILE_LINE_CC); | |
@@ -661,6 +665,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions TS | |
#endif | |
zend_startup_strtod(); | |
+ zend_startup_bigint(); | |
zend_startup_extensions_mechanism(); | |
/* Set up utility functions and values */ | |
diff --git a/Zend/zend.h b/Zend/zend.h | |
index c346c02..1c4904a 100644 | |
--- a/Zend/zend.h | |
+++ b/Zend/zend.h | |
@@ -301,6 +301,7 @@ void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((nore | |
#include "zend_object_handlers.h" | |
#include "zend_ast.h" | |
+#include "zend_bigint.h" | |
/* overloaded elements data types */ | |
#define OE_IS_ARRAY (1<<0) | |
diff --git a/Zend/zend_API.c b/Zend/zend_API.c | |
index 33f1fc6..014bc0b 100644 | |
--- a/Zend/zend_API.c | |
+++ b/Zend/zend_API.c | |
@@ -27,6 +27,7 @@ | |
#include "zend_constants.h" | |
#include "zend_exceptions.h" | |
#include "zend_closures.h" | |
+#include "zend_bigint.h" | |
#ifdef HAVE_STDARG_H | |
#include <stdarg.h> | |
@@ -205,6 +206,7 @@ ZEND_API char *zend_get_type_by_const(int type) /* {{{ */ | |
case IS_TRUE: | |
return "boolean"; | |
case IS_LONG: | |
+ case IS_BIGINT: | |
return "integer"; | |
case IS_DOUBLE: | |
return "double"; | |
@@ -408,10 +410,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons | |
break; | |
} | |
} | |
+ | |
case IS_NULL: | |
case IS_FALSE: | |
case IS_TRUE: | |
case IS_LONG: | |
+ case IS_BIGINT: | |
convert_to_long_ex(arg); | |
*p = Z_LVAL_P(arg); | |
break; | |
@@ -453,6 +457,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons | |
case IS_TRUE: | |
case IS_LONG: | |
case IS_DOUBLE: | |
+ case IS_BIGINT: | |
convert_to_double_ex(arg); | |
*p = Z_DVAL_P(arg); | |
break; | |
@@ -482,6 +487,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons | |
case IS_LONG: | |
case IS_DOUBLE: | |
+ case IS_BIGINT: | |
case IS_FALSE: | |
case IS_TRUE: | |
convert_to_string_ex(arg); | |
@@ -523,6 +529,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons | |
case IS_LONG: | |
case IS_DOUBLE: | |
+ case IS_BIGINT: | |
case IS_FALSE: | |
case IS_TRUE: | |
convert_to_string_ex(arg); | |
@@ -563,6 +570,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons | |
case IS_STRING: | |
case IS_LONG: | |
case IS_DOUBLE: | |
+ case IS_BIGINT: | |
case IS_FALSE: | |
case IS_TRUE: | |
convert_to_boolean_ex(arg); | |
@@ -1632,6 +1640,13 @@ ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value TSRMLS_DC) | |
case IS_NULL: | |
result = zend_symtable_update(ht, STR_EMPTY_ALLOC(), value); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp = zend_bigint_to_string(Z_BIG_P(key)); | |
+ zend_symtable_str_update(ht, temp, strlen(temp), value); | |
+ efree(temp); | |
+ } | |
+ break; | |
case IS_RESOURCE: | |
zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_RES_HANDLE_P(key), Z_RES_HANDLE_P(key)); | |
result = zend_hash_index_update(ht, Z_RES_HANDLE_P(key), value); | |
@@ -3984,6 +3999,7 @@ static int same_zval(zval *zv1, zval *zv2) /* {{{ */ | |
return Z_LVAL_P(zv1) == Z_LVAL_P(zv2); | |
case IS_DOUBLE: | |
return Z_LVAL_P(zv1) == Z_LVAL_P(zv2); | |
+ case IS_BIGINT: | |
case IS_STRING: | |
case IS_ARRAY: | |
case IS_OBJECT: | |
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c | |
index 7a9547b..580c8f3 100644 | |
--- a/Zend/zend_ast.c | |
+++ b/Zend/zend_ast.c | |
@@ -22,6 +22,7 @@ | |
#include "zend_ast.h" | |
#include "zend_API.h" | |
#include "zend_operators.h" | |
+#include "zend_bigint.h" | |
ZEND_API zend_ast *zend_ast_create_constant(zval *zv) | |
{ | |
@@ -112,6 +113,13 @@ static void zend_ast_add_array_element(zval *result, zval *offset, zval *expr TS | |
//??? | |
zval_dtor(offset); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ zend_symtable_str_update(Z_ARRVAL_P(result), temp, strlen(temp), expr); | |
+ efree(temp); | |
+ } | |
+ break; | |
case IS_NULL: | |
zend_symtable_update(Z_ARRVAL_P(result), STR_EMPTY_ALLOC(), expr); | |
break; | |
diff --git a/Zend/zend_bigint.c b/Zend/zend_bigint.c | |
new file mode 100644 | |
index 0000000..684e9ae | |
--- /dev/null | |
+++ b/Zend/zend_bigint.c | |
@@ -0,0 +1,480 @@ | |
+/* | |
+ +----------------------------------------------------------------------+ | |
+ | Zend Big Integer Support | | |
+ +----------------------------------------------------------------------+ | |
+ | Copyright (c) 2014 The PHP Group | | |
+ +----------------------------------------------------------------------+ | |
+ | This source file is subject to version 3.01 of the PHP license, | | |
+ | that is bundled with this package in the file LICENSE, and is | | |
+ | available through the world-wide-web at the following url: | | |
+ | http://www.php.net/license/3_01.txt | | |
+ | If you did not receive a copy of the PHP license and are unable to | | |
+ | obtain it through the world-wide-web, please send a note to | | |
+ | license@php.net so we can mail you a copy immediately. | | |
+ +----------------------------------------------------------------------+ | |
+ | Authors: Andrea Faulds <ajf@ajf.me> | | |
+ +----------------------------------------------------------------------+ | |
+*/ | |
+ | |
+/* $Id$ */ | |
+ | |
+#include <ctype.h> | |
+#include <limits.h> | |
+#include <gmp.h> | |
+ | |
+#include "zend.h" | |
+#include "zend_types.h" | |
+#include "zend_bigint.h" | |
+#include "zend_string.h" | |
+ | |
+/*** INTERNAL MACROS ***/ | |
+ | |
+#define WITH_TEMP_MPZ_FROM_LONG(long, temp, codeblock) { \ | |
+ mpz_t temp; \ | |
+ mpz_init(temp); \ | |
+ mpz_set_si(temp, long); \ | |
+ codeblock \ | |
+ mpz_clear(temp); \ | |
+} | |
+ | |
+/*** INTERNAL FUNCTIONS ***/ | |
+ | |
+/* emalloc/realloc/free are macros, not functions, so we make them functions */ | |
+static void* gmp_emalloc(size_t size) | |
+{ | |
+ return emalloc(size); | |
+} | |
+static void* gmp_erealloc(void *ptr, size_t old_size, size_t new_size) | |
+{ | |
+ return erealloc(ptr, new_size); | |
+} | |
+static void gmp_efree(void *ptr, size_t size) | |
+{ | |
+ efree(ptr); | |
+} | |
+ | |
+/* Called by zend_startup */ | |
+void zend_startup_bigint(void) | |
+{ | |
+ mp_set_memory_functions(gmp_emalloc, gmp_erealloc, gmp_efree); | |
+} | |
+ | |
+/*** INITIALISERS ***/ | |
+ | |
+/* Initialises a bigint | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API void zend_bigint_init(zend_bigint *big) | |
+{ | |
+ GC_REFCOUNT(big) = 1; | |
+ GC_TYPE_INFO(big) = IS_BIGINT; | |
+ mpz_init(big->mpz); | |
+} | |
+ | |
+/* Convenience function: Allocates non-persistently and initialises a bigint | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API zend_bigint* zend_bigint_init_alloc(void) | |
+{ | |
+ zend_bigint *return_value; | |
+ return_value = emalloc(sizeof(zend_bigint)); | |
+ zend_bigint_init(return_value); | |
+ return return_value; | |
+} | |
+ | |
+/* Initialises a bigint from a string with the specified base (in range 2-36) | |
+ * Returns FAILURE on failure (if the string is not entirely numeric), else SUCCESS | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API int zend_bigint_init_from_string(zend_bigint *big, const char *str, int base) | |
+{ | |
+ zend_bigint_init(big); | |
+ if (mpz_set_str(big->mpz, str, base) < 0) { | |
+ mpz_clear(big); | |
+ return FAILURE; | |
+ } | |
+ return SUCCESS; | |
+} | |
+ | |
+/* Intialises a bigint from a string with the specified base (in range 2-36) | |
+ * If base is zero, it shall be detected from the prefix (0 for octal, 0x/X for hex, 0b/B for binary) | |
+ * Leading whitespace is ignored, will take as many valid characters as possible | |
+ * Stops at first non-valid character, or end of string | |
+ * This behaviour is supposed to mostly match that of strtol but is not exactly the same | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API void zend_bigint_init_from_string_tolerant(zend_bigint *big, const char *str, int base) | |
+{ | |
+ zend_bigint_init(big); | |
+ if (mpz_set_str(big->mpz, str, base) < 0) { | |
+ char *temp_str = estrdup(str); | |
+ size_t len = strlen(temp_str); | |
+ /* truncate string until valid */ | |
+ /* FIXME: Do this more performantly */ | |
+ do { | |
+ temp_str[--len] = '\0'; | |
+ if (!len) { | |
+ break; | |
+ } | |
+ } | |
+ while (mpz_set_str(big->mpz, temp_str, base) < 0); | |
+ efree(temp_str); | |
+ } | |
+} | |
+ | |
+/* Initialises a bigint from a long */ | |
+ZEND_API void zend_bigint_init_from_long(zend_bigint *big, long value) | |
+{ | |
+ zend_bigint_init(big); | |
+ mpz_set_si(big->mpz, value); | |
+} | |
+ | |
+/* Initialises a bigint from a double | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API void zend_bigint_init_from_double(zend_bigint *big, double value) | |
+{ | |
+ zend_bigint_init(big); | |
+ mpz_set_d(big->mpz, value); | |
+} | |
+ | |
+/* Destroys a bigint */ | |
+ZEND_API void zend_bigint_dtor(zend_bigint *big) | |
+{ | |
+ mpz_clear(big->mpz); | |
+} | |
+ | |
+/*** INFORMATION ***/ | |
+ | |
+/* Returns true if bigint can fit into an unsigned long without truncation */ | |
+ZEND_API zend_bool zend_bigint_can_fit_ulong(const zend_bigint *big) | |
+{ | |
+ return mpz_fits_ulong_p(big->mpz); | |
+} | |
+ | |
+/* Returns sign of bigint (-1 for negative, 0 for zero or 1 for positive) */ | |
+ZEND_API int zend_bigint_sign(const zend_bigint *big) | |
+{ | |
+ return mpz_sgn(big->mpz); | |
+} | |
+ | |
+/* Returns true if bigint is divisible by a bigint */ | |
+ZEND_API zend_bool zend_bigint_divisible(const zend_bigint *num, const zend_bigint *divisor) | |
+{ | |
+ return mpz_divisible_p(num->mpz, divisor->mpz) ? 1 : 0; | |
+} | |
+ | |
+/* Returns true if bigint is divisible by a long */ | |
+ZEND_API zend_bool zend_bigint_divisible_long(const zend_bigint *num, long divisor) | |
+{ | |
+ zend_bool return_value; | |
+ WITH_TEMP_MPZ_FROM_LONG(divisor, divisor_mpz, { | |
+ return_value = mpz_divisible_p(num->mpz, divisor_mpz) ? 1 : 0; | |
+ }) | |
+ return return_value; | |
+} | |
+ | |
+/* Returns true if long is divisible by a bigint */ | |
+ZEND_API zend_bool zend_bigint_long_divisible(long num, const zend_bigint *divisor) | |
+{ | |
+ zend_bool return_value; | |
+ WITH_TEMP_MPZ_FROM_LONG(num, num_mpz, { | |
+ return_value = mpz_divisible_p(num_mpz, divisor->mpz) ? 1 : 0; | |
+ }) | |
+ return return_value; | |
+} | |
+ | |
+/*** CONVERTORS ***/ | |
+ | |
+/* Converts to long; this will cap at the max value of a long */ | |
+ZEND_API long zend_bigint_to_long(const zend_bigint *big) | |
+{ | |
+ if (mpz_fits_slong_p(big->mpz)) { | |
+ return mpz_get_si(big->mpz); | |
+ } else { | |
+ if (mpz_sgn(big->mpz) == 1) { | |
+ return LONG_MAX; | |
+ } else { | |
+ return LONG_MIN; | |
+ } | |
+ } | |
+} | |
+ | |
+/* Converts to unsigned long; this will cap at the max value of an unsigned long */ | |
+ZEND_API unsigned long zend_bigint_to_ulong(const zend_bigint *big) | |
+{ | |
+ if (mpz_fits_ulong_p(big->mpz)) { | |
+ return mpz_get_ui(big->mpz); | |
+ } else { | |
+ if (mpz_sgn(big->mpz) == 1) { | |
+ return ULONG_MAX; | |
+ } else { | |
+ return 0; | |
+ } | |
+ } | |
+} | |
+ | |
+/* Converts to bool */ | |
+ZEND_API zend_bool zend_bigint_to_bool(const zend_bigint *big) | |
+{ | |
+ return mpz_sgn(big->mpz) ? 1 : 0; | |
+} | |
+ | |
+/* Converts to double; this will lose precision beyond a certain point */ | |
+ZEND_API double zend_bigint_to_double(const zend_bigint *big) | |
+{ | |
+ return mpz_get_d(big->mpz); | |
+} | |
+ | |
+/* Converts to decimal C string | |
+ * HERE BE DRAGONS: String allocated is non-persistent */ | |
+ZEND_API char* zend_bigint_to_string(const zend_bigint *big) | |
+{ | |
+ return mpz_get_str(NULL, 10, big->mpz); | |
+} | |
+ | |
+/* Convenience function: Converts to zend string */ | |
+ZEND_API zend_string* zend_bigint_to_zend_string(const zend_bigint *big, int persistent) | |
+{ | |
+ char *temp_string = zend_bigint_to_string(big); | |
+ zend_string *return_value = STR_INIT(temp_string, strlen(temp_string), persistent); | |
+ efree(temp_string); | |
+ return return_value; | |
+} | |
+ | |
+/* Converts to C string of arbitrary base */ | |
+ZEND_API char* zend_bigint_to_string_base(const zend_bigint *big, int base) | |
+{ | |
+ return mpz_get_str(NULL, base, big->mpz); | |
+} | |
+ | |
+/*** OPERATIONS **/ | |
+ | |
+/* Adds two bigints and stores result in out */ | |
+ZEND_API void zend_bigint_add(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2) | |
+{ | |
+ mpz_add(out->mpz, op1->mpz, op2->mpz); | |
+} | |
+ | |
+/* Adds a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_add_long(zend_bigint *out, const zend_bigint *op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_add(out->mpz, op1->mpz, op2_mpz); | |
+ }) | |
+} | |
+ | |
+/* Adds a long and a long and stores result in out */ | |
+ZEND_API void zend_bigint_long_add_long(zend_bigint *out, long op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op1, op1_mpz, WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_add(out->mpz, op1_mpz, op2_mpz); | |
+ })) | |
+} | |
+ | |
+/* Subtracts two bigints and stores result in out */ | |
+ZEND_API void zend_bigint_subtract(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2) | |
+{ | |
+ mpz_sub(out->mpz, op1->mpz, op2->mpz); | |
+} | |
+ | |
+/* Subtracts a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_subtract_long(zend_bigint *out, const zend_bigint *op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_sub(out->mpz, op1->mpz, op2_mpz); | |
+ }) | |
+} | |
+ | |
+/* Subtracts a long and a long and stores result in out */ | |
+ZEND_API void zend_bigint_long_subtract_long(zend_bigint *out, long op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op1, op1_mpz, WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_sub(out->mpz, op1_mpz, op2_mpz); | |
+ })) | |
+} | |
+ | |
+/* Subtracts a long and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_subtract(zend_bigint *out, long op1, const zend_bigint *op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op1, op1_mpz, { | |
+ mpz_sub(out->mpz, op1_mpz, op2->mpz); | |
+ }) | |
+} | |
+ | |
+/* Multiplies two bigints and stores result in out */ | |
+ZEND_API void zend_bigint_multiply(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2) | |
+{ | |
+ mpz_mul(out->mpz, op1->mpz, op2->mpz); | |
+} | |
+ | |
+/* Multiplies a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_multiply_long(zend_bigint *out, const zend_bigint *op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_mul(out->mpz, op1->mpz, op2_mpz); | |
+ }) | |
+} | |
+ | |
+/* Multiplies a long and a long and stores result in out */ | |
+ZEND_API void zend_bigint_long_multiply_long(zend_bigint *out, long op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op1, op1_mpz, WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_mul(out->mpz, op1_mpz, op2_mpz); | |
+ })) | |
+} | |
+ | |
+/* Raises a bigint base to an unsigned long power and stores result in out */ | |
+ZEND_API void zend_bigint_pow_ulong(zend_bigint *out, const zend_bigint *base, unsigned long power) | |
+{ | |
+ mpz_pow_ui(out->mpz, base->mpz, power); | |
+} | |
+ | |
+/* Raises a long base to an unsigned long power and stores result in out */ | |
+ZEND_API void zend_bigint_long_pow_ulong(zend_bigint *out, long base, unsigned long power) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(base, base_mpz, { | |
+ mpz_pow_ui(out->mpz, base_mpz, power); | |
+ }) | |
+} | |
+ | |
+/* Divides a bigint by a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_divide(zend_bigint *out, const zend_bigint *num, const zend_bigint *divisor) | |
+{ | |
+ mpz_fdiv_q(out->mpz, num->mpz, divisor->mpz); | |
+} | |
+ | |
+/* Divides a bigint by a long and stores result in out */ | |
+ZEND_API void zend_bigint_divide_long(zend_bigint *out, const zend_bigint *num, long divisor) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(divisor, divisor_mpz, { | |
+ mpz_fdiv_q(out->mpz, num->mpz, divisor_mpz); | |
+ }) | |
+} | |
+ | |
+/* Divides a long by a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_divide(zend_bigint *out, long num, const zend_bigint *divisor) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(num, num_mpz, { | |
+ mpz_fdiv_q(out->mpz, num_mpz, divisor->mpz); | |
+ }) | |
+} | |
+ | |
+/* Finds the remainder of the division of a bigint by a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_modulus(zend_bigint *out, const zend_bigint *num, const zend_bigint *divisor) | |
+{ | |
+ mpz_fdiv_r(out->mpz, num->mpz, divisor->mpz); | |
+} | |
+ | |
+/* Finds the remainder of the division of a bigint by a long and stores result in out */ | |
+ZEND_API void zend_bigint_modulus_long(zend_bigint *out, const zend_bigint *num, long divisor) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(divisor, divisor_mpz, { | |
+ mpz_fdiv_r(out->mpz, num->mpz, divisor_mpz); | |
+ )} | |
+} | |
+ | |
+/* Finds the remainder of the division of a long by a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_modulus(zend_bigint *out, long num, const zend_bigint *divisor) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(num, num_mpz, { | |
+ mpz_fdiv_r(out->mpz, num_mpz, divisor->mpz); | |
+ )} | |
+} | |
+ | |
+/* Finds the one's complement of a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_ones_complement(zend_bigint *out, const zend_bigint *op) | |
+{ | |
+ mpz_com(out->mpz, op->mpz); | |
+} | |
+ | |
+/* Finds the bitwise OR of a bigint and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_or(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2) | |
+{ | |
+ mpz_ior(out->mpz, op1->mpz, op2->mpz); | |
+} | |
+ | |
+/* Finds the bitwise OR of a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_or_long(zend_bigint *out, const zend_bigint *op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_ior(out->mpz, op1->mpz, op2_mpz); | |
+ }) | |
+} | |
+ | |
+/* Finds the bitwise OR of a long and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_or(zend_bigint *out, long op1, const zend_bigint *op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op1, op1_mpz, { | |
+ mpz_ior(out->mpz, op1_mpz, op2->mpz); | |
+ }) | |
+} | |
+ | |
+/* Finds the bitwise AND of a bigint and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_and(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2) | |
+{ | |
+ mpz_and(out->mpz, op1->mpz, op2->mpz); | |
+} | |
+ | |
+/* Finds the bitwise AND of a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_and_long(zend_bigint *out, const zend_bigint *op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_and(out->mpz, op1->mpz, op2_mpz); | |
+ }) | |
+} | |
+ | |
+/* Finds the bitwise AND of a long and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_and(zend_bigint *out, long op1, const zend_bigint *op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op1, op1_mpz, { | |
+ mpz_and(out->mpz, op1_mpz, op2->mpz); | |
+ }) | |
+} | |
+ | |
+/* Finds the bitwise XOR of a bigint and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_xor(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2) | |
+{ | |
+ mpz_xor(out->mpz, op1->mpz, op2->mpz); | |
+} | |
+ | |
+/* Finds the bitwise XOR of a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_xor_long(zend_bigint *out, const zend_bigint *op1, long op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op2, op2_mpz, { | |
+ mpz_xor(out->mpz, op1->mpz, op2_mpz); | |
+ }) | |
+} | |
+ | |
+/* Finds the bitwise XOR of a long and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_xor(zend_bigint *out, long op1, const zend_bigint *op2) | |
+{ | |
+ WITH_TEMP_MPZ_FROM_LONG(op1, op1_mpz, { | |
+ mpz_xor(out->mpz, op1_mpz, op2->mpz); | |
+ }) | |
+} | |
+ | |
+/* Shifts a bigint left by an unsigned long and stores result in out */ | |
+ZEND_API void zend_bigint_shift_left_ulong(zend_bigint *out, const zend_bigint *num, unsigned long shift) | |
+{ | |
+ mpz_mul_2exp(out->mpz, num->mpz, shift); | |
+} | |
+ | |
+/* Shifts a bigint right by an unsigned long and stores result in out */ | |
+ZEND_API void zend_bigint_shift_right_ulong(zend_bigint *out, const zend_bigint *num, unsigned long shift) | |
+{ | |
+ mpz_fdiv_q_2exp(out->mpz, num->mpz, shift); | |
+} | |
+ | |
+/* Compares a bigint and a bigint and returns result (negative if op1 > op2, zero if op1 == op2, positive if op1 < op2) */ | |
+ZEND_API int zend_bigint_cmp(const zend_bigint *op1, const zend_bigint *op2) | |
+{ | |
+ return mpz_cmp(op1->mpz, op2->mpz); | |
+} | |
+ | |
+/* Compares a bigint and a long and returns result (negative if op1 > op2, zero if op1 == op2, positive if op1 < op2) */ | |
+ZEND_API int zend_bigint_cmp_long(const zend_bigint *op1, long op2) | |
+{ | |
+ return mpz_cmp_si(op1->mpz, op2); | |
+} | |
+ | |
+/* Compares a bigint and a double and returns result (negative if op1 > op2, zero if op1 == op2, positive if op1 < op2) */ | |
+ZEND_API int zend_bigint_cmp_double(const zend_bigint *op1, double op2) | |
+{ | |
+ return mpz_cmp_d(op1->mpz, op2); | |
+} | |
\ No newline at end of file | |
diff --git a/Zend/zend_bigint.h b/Zend/zend_bigint.h | |
new file mode 100644 | |
index 0000000..2eec8fa | |
--- /dev/null | |
+++ b/Zend/zend_bigint.h | |
@@ -0,0 +1,213 @@ | |
+/* | |
+ +----------------------------------------------------------------------+ | |
+ | Zend Big Integer Support | | |
+ +----------------------------------------------------------------------+ | |
+ | Copyright (c) 2014 The PHP Group | | |
+ +----------------------------------------------------------------------+ | |
+ | This source file is subject to version 3.01 of the PHP license, | | |
+ | that is bundled with this package in the file LICENSE, and is | | |
+ | available through the world-wide-web at the following url: | | |
+ | http://www.php.net/license/3_01.txt | | |
+ | If you did not receive a copy of the PHP license and are unable to | | |
+ | obtain it through the world-wide-web, please send a note to | | |
+ | license@php.net so we can mail you a copy immediately. | | |
+ +----------------------------------------------------------------------+ | |
+ | Authors: Andrea Faulds <ajf@ajf.me> | | |
+ +----------------------------------------------------------------------+ | |
+*/ | |
+ | |
+/* $Id$ */ | |
+ | |
+#ifndef ZEND_BIGINT_H | |
+#define ZEND_BIGINT_H | |
+ | |
+#include <gmp.h> | |
+ | |
+#include "zend.h" | |
+#include "zend_types.h" | |
+ | |
+/*** INTERNAL FUNCTIONS ***/ | |
+ | |
+/* Called by zend_startup */ | |
+void zend_startup_bigint(void); | |
+ | |
+/*** INITIALISERS ***/ | |
+ | |
+/* Initialises a bigint | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API void zend_bigint_init(zend_bigint *big); | |
+ | |
+/* Convenience function: Allocates non-persistently and initialises a bigint | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API zend_bigint* zend_bigint_init_alloc(void); | |
+ | |
+/* Initialises a bigint from a string with the specified base (in range 2-36) | |
+ * Returns FAILURE on failure, else SUCCESS | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API int zend_bigint_init_from_string(zend_bigint *big, const char *str, int base); | |
+ | |
+/* Intialises a bigint from a string with the specified base (in range 2-36) | |
+ * If base is zero, it shall be detected from the prefix (0 for octal, 0x/X for hex, 0b/B for binary) | |
+ * Leading whitespace is ignored, will take as many valid characters as possible | |
+ * Stops at first non-valid character, or end of string | |
+ * This behaviour is supposed to mostly match that of strtol but is not exactly the same | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API void zend_bigint_init_from_string_tolerant(zend_bigint *big, const char *str, int base); | |
+ | |
+/* Initialises a bigint from a long | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API void zend_bigint_init_from_long(zend_bigint *big, long value); | |
+ | |
+/* Initialises a bigint from a double | |
+ * HERE BE DRAGONS: Memory allocated internally by gmp is non-persistent */ | |
+ZEND_API void zend_bigint_init_from_double(zend_bigint *big, double value); | |
+ | |
+/* Destroys a bigint */ | |
+ZEND_API void zend_bigint_dtor(zend_bigint *big); | |
+ | |
+/*** INFORMATION ***/ | |
+ | |
+/* Returns true if bigint can fit into an unsigned long without truncation */ | |
+ZEND_API zend_bool zend_bigint_can_fit_ulong(const zend_bigint *big); | |
+ | |
+/* Returns sign of bigint (-1 for negative, 0 for zero or 1 for positive) */ | |
+ZEND_API int zend_bigint_sign(const zend_bigint *big); | |
+ | |
+/* Returns true if bigint is divisible by a bigint */ | |
+ZEND_API zend_bool zend_bigint_divisible(const zend_bigint *num, const zend_bigint *divisor); | |
+ | |
+/* Returns true if bigint is divisible by a long */ | |
+ZEND_API zend_bool zend_bigint_divisible_long(const zend_bigint *num, long divisor); | |
+ | |
+/* Returns true if long is divisible by a bigint */ | |
+ZEND_API zend_bool zend_bigint_long_divisible(long num, const zend_bigint *divisor); | |
+ | |
+/*** CONVERTORS ***/ | |
+ | |
+/* Converts to long; this will cap at the max value of a long */ | |
+ZEND_API long zend_bigint_to_long(const zend_bigint *big); | |
+ | |
+/* Converts to unsigned long; this will cap at the max value of an unsigned long */ | |
+ZEND_API unsigned long zend_bigint_to_ulong(const zend_bigint *big); | |
+ | |
+/* Converts to bool */ | |
+ZEND_API zend_bool zend_bigint_to_bool(const zend_bigint *big); | |
+ | |
+/* Converts to double; this will lose precision beyond a certain point */ | |
+ZEND_API double zend_bigint_to_double(const zend_bigint *big); | |
+ | |
+/* Converts to decimal C string | |
+ * HERE BE DRAGONS: String allocated is non-persistent */ | |
+ZEND_API char* zend_bigint_to_string(const zend_bigint *big); | |
+ | |
+/* Convenience function: Converts to zend string */ | |
+ZEND_API zend_string* zend_bigint_to_zend_string(const zend_bigint *big, int persistent); | |
+ | |
+/* Converts to C string of arbitrary base */ | |
+ZEND_API char* zend_bigint_to_string_base(const zend_bigint *big, int base); | |
+ | |
+/*** OPERATIONS **/ | |
+ | |
+/* Adds two bigints and stores result in out */ | |
+ZEND_API void zend_bigint_add(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2); | |
+ | |
+/* Adds a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_add_long(zend_bigint *out, const zend_bigint *op1, long op2); | |
+ | |
+/* Adds a long and a long and stores result in out */ | |
+ZEND_API void zend_bigint_long_add_long(zend_bigint *out, long op1, long op2); | |
+ | |
+/* Subtracts two bigints and stores result in out */ | |
+ZEND_API void zend_bigint_subtract(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2); | |
+ | |
+/* Subtracts a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_subtract_long(zend_bigint *out, const zend_bigint *op1, long op2); | |
+ | |
+/* Subtracts a long and a long and stores result in out */ | |
+ZEND_API void zend_long_subtract_long(zend_bigint *out, long op1, long op2); | |
+ | |
+/* Subtracts a long and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_subtract(zend_bigint *out, long op1, const zend_bigint *op2); | |
+ | |
+/* Subtracts a long and a long and stores result in out */ | |
+ZEND_API void zend_bigint_long_subtract_long(zend_bigint *out, long op1, long op2); | |
+ | |
+/* Multiplies two bigints and stores result in out */ | |
+ZEND_API void zend_bigint_multiply(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2); | |
+ | |
+/* Multiplies a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_multiply_long(zend_bigint *out, const zend_bigint *op1, long op2); | |
+ | |
+/* Multiplies a long and a long and stores result in out */ | |
+ZEND_API void zend_bigint_long_multiply_long(zend_bigint *out, long op1, long op2); | |
+ | |
+/* Raises a bigint base to an unsigned long power and stores result in out */ | |
+ZEND_API void zend_bigint_pow_ulong(zend_bigint *out, const zend_bigint *base, unsigned long power); | |
+ | |
+/* Raises a long base to an unsigned long power and stores result in out */ | |
+ZEND_API void zend_bigint_long_pow_ulong(zend_bigint *out, long base, unsigned long power); | |
+ | |
+/* Divides a bigint by a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_divide(zend_bigint *out, const zend_bigint *big, const zend_bigint *divisor); | |
+ | |
+/* Divides a bigint by a long and stores result in out */ | |
+ZEND_API void zend_bigint_divide_long(zend_bigint *out, const zend_bigint *big, long divisor); | |
+ | |
+/* Divides a long by a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_divide(zend_bigint *out, long big, const zend_bigint *divisor); | |
+ | |
+/* Finds the remainder of the division of a bigint by a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_modulus(zend_bigint *out, const zend_bigint *num, const zend_bigint *divisor); | |
+ | |
+/* Finds the remainder of the division of a bigint by a long and stores result in out */ | |
+ZEND_API void zend_bigint_modulus_long(zend_bigint *out, const zend_bigint *num, long divisor); | |
+ | |
+/* Finds the remainder of the division of a long by a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_modulus(zend_bigint *out, long num, const zend_bigint *divisor); | |
+ | |
+/* Finds the one's complement of a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_ones_complement(zend_bigint *out, const zend_bigint *op); | |
+ | |
+/* Finds the bitwise OR of a bigint and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_or(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2); | |
+ | |
+/* Finds the bitwise OR of a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_or_long(zend_bigint *out, const zend_bigint *op1, long op2); | |
+ | |
+/* Finds the bitwise OR of a long and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_or(zend_bigint *out, long op1, const zend_bigint *op2); | |
+ | |
+/* Finds the bitwise AND of a bigint and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_and(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2); | |
+ | |
+/* Finds the bitwise AND of a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_and_long(zend_bigint *out, const zend_bigint *op1, long op2); | |
+ | |
+/* Finds the bitwise AND of a long and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_and(zend_bigint *out, long op1, const zend_bigint *op2); | |
+ | |
+/* Finds the bitwise XOR of a bigint and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_xor(zend_bigint *out, const zend_bigint *op1, const zend_bigint *op2); | |
+ | |
+/* Finds the bitwise XOR of a bigint and a long and stores result in out */ | |
+ZEND_API void zend_bigint_xor_long(zend_bigint *out, const zend_bigint *op1, long op2); | |
+ | |
+/* Finds the bitwise XOR of a long and a bigint and stores result in out */ | |
+ZEND_API void zend_bigint_long_xor(zend_bigint *out, long op1, const zend_bigint *op2); | |
+ | |
+/* Shifts a bigint left by an unsigned long and stores result in out */ | |
+ZEND_API void zend_bigint_shift_left_ulong(zend_bigint *out, const zend_bigint *num, unsigned long shift); | |
+ | |
+/* Shifts a bigint right by an unsigned long and stores result in out */ | |
+ZEND_API void zend_bigint_shift_right_ulong(zend_bigint *out, const zend_bigint *num, unsigned long shift); | |
+ | |
+/* Compares a bigint and a bigint and returns result (negative if op1 > op2, zero if op1 == op2, positive if op1 < op2) */ | |
+ZEND_API int zend_bigint_cmp(const zend_bigint *op1, const zend_bigint *op2); | |
+ | |
+/* Compares a bigint and a long and returns result (negative if op1 > op2, zero if op1 == op2, positive if op1 < op2) */ | |
+ZEND_API int zend_bigint_cmp_long(const zend_bigint *op1, long op2); | |
+ | |
+/* Compares a bigint and a double and returns result (negative if op1 > op2, zero if op1 == op2, positive if op1 < op2) */ | |
+ZEND_API int zend_bigint_cmp_double(const zend_bigint *op1, double op2); | |
+ | |
+#endif | |
\ No newline at end of file | |
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c | |
index f8f6a43..57f257a 100644 | |
--- a/Zend/zend_builtin_functions.c | |
+++ b/Zend/zend_builtin_functions.c | |
@@ -27,6 +27,7 @@ | |
#include "zend_exceptions.h" | |
#include "zend_extensions.h" | |
#include "zend_closures.h" | |
+#include "zend_bigint.h" | |
#undef ZEND_TEST_EXCEPTIONS | |
@@ -690,6 +691,7 @@ repeat: | |
switch (Z_TYPE_P(val)) { | |
case IS_LONG: | |
case IS_DOUBLE: | |
+ case IS_BIGINT: | |
case IS_STRING: | |
case IS_FALSE: | |
case IS_TRUE: | |
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c | |
index c84937b..7d9676c 100644 | |
--- a/Zend/zend_compile.c | |
+++ b/Zend/zend_compile.c | |
@@ -29,6 +29,8 @@ | |
#include "zend_virtual_cwd.h" | |
#include "zend_multibyte.h" | |
#include "zend_language_scanner.h" | |
+#include "zend_string.h" | |
+#include "zend_bigint.h" | |
#define CONSTANT_EX(op_array, op) \ | |
(op_array)->literals[op] | |
@@ -4968,7 +4970,8 @@ void zend_do_brk_cont(zend_uchar op, znode *expr TSRMLS_DC) /* {{{ */ | |
if (expr) { | |
if (expr->op_type != IS_CONST) { | |
zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator with non-constant operand is no longer supported", op == ZEND_BRK ? "break" : "continue"); | |
- } else if (Z_TYPE(expr->u.constant) != IS_LONG || Z_LVAL(expr->u.constant) < 1) { | |
+ } else if (!((Z_TYPE(expr->u.constant) == IS_LONG && Z_LVAL(expr->u.constant) > 1) | |
+ || (Z_TYPE(expr->u.constant) == IS_BIGINT && zend_bigint_sign(Z_BIG(expr->u.constant)) == 1))) { | |
zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator accepts only positive numbers", op == ZEND_BRK ? "break" : "continue"); | |
} | |
SET_NODE(opline->op2, expr); | |
@@ -5985,6 +5988,9 @@ str_index: | |
case IS_DOUBLE: | |
num = zend_dval_to_lval(Z_DVAL(CONSTANT(opline->op2.constant))); | |
goto num_index; | |
+ case IS_BIGINT: | |
+ constant_array = 0; | |
+ break; | |
case IS_FALSE: | |
num = 0; | |
goto num_index; | |
diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c | |
index a8e57c9..9da0954 100644 | |
--- a/Zend/zend_exceptions.c | |
+++ b/Zend/zend_exceptions.c | |
@@ -28,6 +28,7 @@ | |
#include "zend_exceptions.h" | |
#include "zend_vm.h" | |
#include "zend_dtrace.h" | |
+#include "zend_bigint.h" | |
static zend_class_entry *default_exception_ce; | |
static zend_class_entry *error_exception_ce; | |
@@ -493,6 +494,13 @@ static void _build_trace_args(zval *arg, zend_string **str_ptr TSRMLS_DC) /* {{{ | |
TRACE_APPEND_STR(", "); | |
break; | |
} | |
+ case IS_BIGINT: { | |
+ char *s_tmp = zend_bigint_to_string(Z_BIG_P(arg)); | |
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp)); | |
+ efree(s_tmp); | |
+ TRACE_APPEND_STR(", "); | |
+ break; | |
+ } | |
case IS_ARRAY: | |
TRACE_APPEND_STR("Array, "); | |
break; | |
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c | |
index 95028ff..a99def9 100644 | |
--- a/Zend/zend_execute.c | |
+++ b/Zend/zend_execute.c | |
@@ -985,6 +985,7 @@ static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht | |
zval *retval; | |
zend_string *offset_key; | |
ulong hval; | |
+ zend_bool key_needs_release = 0; | |
if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) { | |
hval = Z_LVAL_P(dim); | |
@@ -1055,6 +1056,10 @@ str_index: | |
break; | |
} | |
} | |
+ if (key_needs_release) | |
+ { | |
+ STR_RELEASE(offset_key); | |
+ } | |
} else { | |
switch (Z_TYPE_P(dim)) { | |
case IS_NULL: | |
@@ -1063,6 +1068,10 @@ str_index: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(dim)); | |
goto num_index; | |
+ case IS_BIGINT: | |
+ offset_key = zend_bigint_to_zend_string(Z_BIG_P(dim), 0); | |
+ key_needs_release = 1; | |
+ goto str_index; | |
case IS_RESOURCE: | |
zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim)); | |
hval = Z_RES_HANDLE_P(dim); | |
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h | |
index 623d3a8..9605e4c 100644 | |
--- a/Zend/zend_execute.h | |
+++ b/Zend/zend_execute.h | |
@@ -26,6 +26,7 @@ | |
#include "zend_hash.h" | |
#include "zend_operators.h" | |
#include "zend_variables.h" | |
+#include "zend_bigint.h" | |
BEGIN_EXTERN_C() | |
struct _zend_fcall_info; | |
@@ -95,6 +96,9 @@ again: | |
case IS_DOUBLE: | |
result = (Z_DVAL_P(op) ? 1 : 0); | |
break; | |
+ case IS_BIGINT: | |
+ result = zend_bigint_to_bool(Z_BIG_P(op)); | |
+ break; | |
case IS_STRING: | |
if (Z_STRLEN_P(op) == 0 | |
|| (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) { | |
diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l | |
index b510086..ca0ad6c 100644 | |
--- a/Zend/zend_language_scanner.l | |
+++ b/Zend/zend_language_scanner.l | |
@@ -48,6 +48,7 @@ | |
#include "zend_strtod.h" | |
#include "zend_exceptions.h" | |
#include "zend_virtual_cwd.h" | |
+#include "zend_bigint.h" | |
#include "tsrm_config_common.h" | |
#define YYCTYPE unsigned char | |
@@ -1527,11 +1528,13 @@ NEWLINE ("\r"|"\n"|"\r\n") | |
} else { | |
ZVAL_LONG(zendlval, strtol(bin, NULL, 2)); | |
} | |
- return T_LNUMBER; | |
} else { | |
- ZVAL_DOUBLE(zendlval, zend_bin_strtod(bin, NULL)); | |
- return T_DNUMBER; | |
+ char *temp_str = estrndup(bin, len); | |
+ ZVAL_NEW_BIGINT(zendlval); | |
+ zend_bigint_init_from_string(Z_BIG_P(zendlval), temp_str, 2); | |
+ efree(temp_str); | |
} | |
+ return T_LNUMBER; | |
} | |
<ST_IN_SCRIPTING>{LNUM} { | |
@@ -1541,12 +1544,15 @@ NEWLINE ("\r"|"\n"|"\r\n") | |
errno = 0; | |
ZVAL_LONG(zendlval, strtol(yytext, NULL, 0)); | |
if (errno == ERANGE) { /* Overflow */ | |
+ char *temp_str = estrndup(yytext, yyleng); | |
if (yytext[0] == '0') { /* octal overflow */ | |
- ZVAL_DOUBLE(zendlval, zend_oct_strtod(yytext, NULL)); | |
+ ZVAL_NEW_BIGINT(zendlval); | |
+ zend_bigint_init_from_string(Z_BIG_P(zendlval), temp_str, 8); | |
} else { | |
- ZVAL_DOUBLE(zendlval, zend_strtod(yytext, NULL)); | |
+ ZVAL_NEW_BIGINT(zendlval); | |
+ zend_bigint_init_from_string(Z_BIG_P(zendlval), temp_str, 10); | |
} | |
- return T_DNUMBER; | |
+ efree(temp_str); | |
} | |
} | |
return T_LNUMBER; | |
@@ -1568,11 +1574,13 @@ NEWLINE ("\r"|"\n"|"\r\n") | |
} else { | |
ZVAL_LONG(zendlval, strtol(hex, NULL, 16)); | |
} | |
- return T_LNUMBER; | |
} else { | |
- ZVAL_DOUBLE(zendlval, zend_hex_strtod(hex, NULL)); | |
- return T_DNUMBER; | |
+ char *temp_str = estrndup(hex, len); | |
+ ZVAL_NEW_BIGINT(zendlval); | |
+ zend_bigint_init_from_string(Z_BIG_P(zendlval), temp_str, 16); | |
+ efree(temp_str); | |
} | |
+ return T_DNUMBER; | |
} | |
<ST_VAR_OFFSET>[0]|([1-9][0-9]*) { /* Offset could be treated as a long */ | |
diff --git a/Zend/zend_language_scanner_defs.h b/Zend/zend_language_scanner_defs.h | |
index 5926e3c..1118239 100644 | |
--- a/Zend/zend_language_scanner_defs.h | |
+++ b/Zend/zend_language_scanner_defs.h | |
@@ -1,4 +1,4 @@ | |
-/* Generated by re2c 0.13.5 */ | |
+/* Generated by re2c 0.13.6 */ | |
#line 3 "Zend/zend_language_scanner_defs.h" | |
enum YYCONDTYPE { | |
diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h | |
index 74dc7d1..499359b 100644 | |
--- a/Zend/zend_multiply.h | |
+++ b/Zend/zend_multiply.h | |
@@ -19,6 +19,11 @@ | |
/* $Id$ */ | |
+#include "zend_bigint.h" | |
+ | |
+/* assembly commented-out as it uses the old float overflow behaviour | |
+* however, now longs overflow to bigints, so we can't use it */ | |
+/* | |
#if defined(__i386__) && defined(__GNUC__) | |
#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \ | |
@@ -69,11 +74,14 @@ | |
} while (0) | |
#elif SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) | |
+*/ | |
+#if SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) | |
-#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \ | |
+#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, big, usedval) do { \ | |
zend_long64 __result = (zend_long64) (a) * (zend_long64) (b); \ | |
if (__result > LONG_MAX || __result < LONG_MIN) { \ | |
- (dval) = (double) __result; \ | |
+ (big) = zend_bigint_init_alloc(); \ | |
+ zend_bigint_long_multiply_long(big, a, b); \ | |
(usedval) = 1; \ | |
} else { \ | |
(lval) = (long) __result; \ | |
@@ -83,12 +91,13 @@ | |
#else | |
-#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \ | |
+#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, big, usedval) do { \ | |
long __lres = (a) * (b); \ | |
long double __dres = (long double)(a) * (long double)(b); \ | |
long double __delta = (long double) __lres - __dres; \ | |
if ( ((usedval) = (( __dres + __delta ) != __dres))) { \ | |
- (dval) = __dres; \ | |
+ (big) = zend_bigint_init_alloc(); \ | |
+ zend_bigint_long_multiply_long(big, a, b); \ | |
} else { \ | |
(lval) = __lres; \ | |
} \ | |
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c | |
index caf5e78..d57f243 100644 | |
--- a/Zend/zend_operators.c | |
+++ b/Zend/zend_operators.c | |
@@ -30,6 +30,7 @@ | |
#include "zend_strtod.h" | |
#include "zend_exceptions.h" | |
#include "zend_closures.h" | |
+#include "zend_bigint.h" | |
#if ZEND_USE_TOLOWER_L | |
#include <locale.h> | |
@@ -279,6 +280,9 @@ try_again: | |
case IS_TRUE: \ | |
ZVAL_LONG(&(holder), 1); \ | |
break; \ | |
+ case IS_BIGINT: \ | |
+ ZVAL_LONG(&holder, zend_bigint_to_long(Z_BIG_P(op)));\ | |
+ break; \ | |
case IS_DOUBLE: \ | |
ZVAL_LONG(&holder, zend_dval_to_lval(Z_DVAL_P(op)));\ | |
break; \ | |
@@ -305,6 +309,99 @@ try_again: | |
/* }}} */ | |
+/* {{{ zendi_convert_to_bigint */ | |
+#define zendi_convert_to_bigint(op, holder, result) \ | |
+ if (op == result) { \ | |
+ convert_to_bigint(op); \ | |
+ } else if (Z_TYPE_P(op) != IS_BIGINT) { \ | |
+ switch (Z_TYPE_P(op)) { \ | |
+ case IS_NULL: \ | |
+ case IS_FALSE: \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_long(Z_BIG(holder), 0); \ | |
+ break; \ | |
+ case IS_TRUE: \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_long(Z_BIG(holder), 1); \ | |
+ break; \ | |
+ case IS_LONG: \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_long(Z_BIG(holder), Z_LVAL(op));\ | |
+ break; \ | |
+ case IS_DOUBLE: \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_double(Z_BIG(holder), Z_DVAL(op));\ | |
+ break; \ | |
+ case IS_STRING: \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_string_tolerant(Z_BIG(holder), Z_STRVAL(op), 10);\ | |
+ break; \ | |
+ case IS_ARRAY: \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_long(Z_BIG(holder), zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);\ | |
+ break; \ | |
+ case IS_OBJECT: \ | |
+ ZVAL_DUP(&(holder), (op)); \ | |
+ convert_to_bigint_base(&(holder), 10); \ | |
+ break; \ | |
+ case IS_RESOURCE: \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_long(Z_BIG(holder), Z_RES_HANDLE_P(op);\ | |
+ break; \ | |
+ default: \ | |
+ zend_error(E_WARNING, "Cannot convert to ordinal value"); \ | |
+ ZVAL_LONG(&holder, 0); \ | |
+ break; \ | |
+ } \ | |
+ (op) = &(holder); \ | |
+ } | |
+ | |
+/* }}} */ | |
+ | |
+/* {{{ zendi_convert_to_bigint_or_long */ | |
+#define zendi_convert_to_bigint_or_long(op, holder, result) \ | |
+ if (op == result) { \ | |
+ convert_to_bigint(op); \ | |
+ } else if (!(Z_TYPE_P(op) == IS_LONG || Z_TYPE_P(op) == IS_BIGINT)) {\ | |
+ switch (Z_TYPE_P(op)) { \ | |
+ case IS_NULL: \ | |
+ case IS_FALSE: \ | |
+ ZVAL_LONG(&holder, 0); \ | |
+ break; \ | |
+ case IS_TRUE: \ | |
+ ZVAL_LONG(&holder, 1); \ | |
+ break; \ | |
+ case IS_DOUBLE: \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_double(Z_BIG(holder), Z_DVAL_P(op));\ | |
+ break; \ | |
+ case IS_STRING: \ | |
+ ZVAL_LONG(&holder, strtol(Z_STRVAL_P(op), NULL, 10));\ | |
+ if (errno == ERANGE) { /* Overflow */ \ | |
+ ZVAL_NEW_BIGINT(&holder); \ | |
+ zend_bigint_init_from_string_tolerant(Z_BIG(holder), Z_STRVAL_P(op), 10);\ | |
+ } \ | |
+ break; \ | |
+ case IS_ARRAY: \ | |
+ ZVAL_LONG(&holder, zend_hash_num_elements(Z_ARRVAL_P(op))?1:0); \ | |
+ break; \ | |
+ case IS_OBJECT: \ | |
+ ZVAL_DUP(&(holder), (op)); \ | |
+ convert_to_bigint_or_long_base(&(holder), 10); \ | |
+ break; \ | |
+ case IS_RESOURCE: \ | |
+ ZVAL_LONG(&holder, Z_RES_HANDLE_P(op)); \ | |
+ break; \ | |
+ default: \ | |
+ zend_error(E_WARNING, "Cannot convert to ordinal value"); \ | |
+ ZVAL_LONG(&holder, 0); \ | |
+ break; \ | |
+ } \ | |
+ (op) = &(holder); \ | |
+ } | |
+ | |
+/* }}} */ | |
+ | |
/* {{{ zendi_convert_to_boolean */ | |
#define zendi_convert_to_boolean(op, holder, result) \ | |
if (op==result) { \ | |
@@ -324,6 +421,9 @@ try_again: | |
case IS_DOUBLE: \ | |
ZVAL_BOOL(&holder, Z_DVAL_P(op) ? 1 : 0); \ | |
break; \ | |
+ case IS_BIGINT: \ | |
+ ZVAL_BOOL(&holder, zend_bigint_to_bool(Z_BIG_P(op)));\ | |
+ break; \ | |
case IS_STRING: \ | |
if (Z_STRLEN_P(op) == 0 \ | |
|| (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) { \ | |
@@ -376,6 +476,22 @@ ZEND_API void convert_to_long(zval *op) /* {{{ */ | |
} | |
/* }}} */ | |
+ZEND_API void convert_to_bigint(zval *op) /* {{{ */ | |
+{ | |
+ if (Z_TYPE_P(op) != IS_BIGINT) { | |
+ convert_to_bigint_base(op, 10); | |
+ } | |
+} | |
+/* }}} */ | |
+ | |
+ZEND_API void convert_to_bigint_or_long(zval *op) /* {{{ */ | |
+{ | |
+ if (Z_TYPE_P(op) != IS_BIGINT && Z_TYPE_P(op) != IS_LONG) { | |
+ convert_to_bigint_or_long_base(op, 10); | |
+ } | |
+} | |
+/* }}} */ | |
+ | |
ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */ | |
{ | |
long tmp; | |
@@ -401,6 +517,13 @@ ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */ | |
case IS_DOUBLE: | |
ZVAL_LONG(op, zend_dval_to_lval(Z_DVAL_P(op))); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ long l = zend_bigint_to_long(Z_BIG_P(op)); | |
+ zval_dtor(op); | |
+ ZVAL_LONG(op, l); | |
+ } | |
+ break; | |
case IS_STRING: | |
{ | |
zend_string *str = Z_STR_P(op); | |
@@ -436,6 +559,151 @@ ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */ | |
} | |
/* }}} */ | |
+ZEND_API void convert_to_bigint_base(zval *op, int base) /* {{{ */ | |
+{ | |
+ long tmp; | |
+ | |
+ switch (Z_TYPE_P(op)) { | |
+ case IS_NULL: | |
+ case IS_FALSE: | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_long(Z_BIG_P(op), 0); | |
+ break; | |
+ case IS_TRUE: | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_long(Z_BIG_P(op), 1); | |
+ break; | |
+ case IS_RESOURCE: | |
+ { | |
+ long l = Z_RES_HANDLE_P(op); | |
+ zval_ptr_dtor(op); | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_long(Z_BIG_P(op), l); | |
+ } | |
+ break; | |
+ case IS_LONG: | |
+ { | |
+ long l = Z_LVAL_P(op); | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_long(Z_BIG_P(op), l); | |
+ } | |
+ break; | |
+ case IS_DOUBLE: | |
+ { | |
+ double d = Z_DVAL_P(op); | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_double(Z_BIG_P(op), d); | |
+ } | |
+ break; | |
+ case IS_BIGINT: | |
+ break; | |
+ case IS_STRING: | |
+ { | |
+ zend_string *str = Z_STR_P(op); | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_string_tolerant(Z_BIG_P(op), str->val, base); | |
+ STR_RELEASE(str); | |
+ } | |
+ break; | |
+ case IS_ARRAY: | |
+ tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0); | |
+ zval_dtor(op); | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_long(Z_BIG_P(op), tmp); | |
+ break; | |
+ case IS_OBJECT: | |
+ { | |
+ zval dst; | |
+ TSRMLS_FETCH(); | |
+ | |
+ convert_object_to_type(op, &dst, IS_BIGINT, convert_to_bigint); | |
+ zval_dtor(op); | |
+ | |
+ if (Z_TYPE(dst) == IS_BIGINT) { | |
+ ZVAL_COPY_VALUE(op, &dst); | |
+ } else { | |
+ zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name->val); | |
+ | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_long(Z_BIG_P(op), 1); | |
+ } | |
+ return; | |
+ } | |
+ EMPTY_SWITCH_DEFAULT_CASE() | |
+ } | |
+} | |
+/* }}} */ | |
+ | |
+ZEND_API void convert_to_bigint_or_long_base(zval *op, int base) /* {{{ */ | |
+{ | |
+ long tmp; | |
+ | |
+ switch (Z_TYPE_P(op)) { | |
+ case IS_NULL: | |
+ case IS_FALSE: | |
+ ZVAL_LONG(op, 0); | |
+ break; | |
+ case IS_TRUE: | |
+ ZVAL_LONG(op, 1); | |
+ break; | |
+ case IS_RESOURCE: { | |
+ long l = Z_RES_HANDLE_P(op); | |
+ zval_ptr_dtor(op); | |
+ ZVAL_LONG(op, l); | |
+ } | |
+ /* break missing intentionally */ | |
+ Z_TYPE_INFO_P(op) = IS_LONG; | |
+ break; | |
+ case IS_LONG: | |
+ break; | |
+ case IS_DOUBLE: | |
+ { | |
+ double d = Z_DVAL_P(op); | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_double(Z_BIG_P(op), d); | |
+ } | |
+ break; | |
+ case IS_BIGINT: | |
+ break; | |
+ case IS_STRING: | |
+ { | |
+ zend_string *str = Z_STR_P(op); | |
+ ZVAL_LONG(op, strtol(str->val, NULL, 10)); | |
+ if (errno == ERANGE) { /* Overflow */ | |
+ ZVAL_NEW_BIGINT(op); | |
+ zend_bigint_init_from_string_tolerant(Z_BIG_P(op), str->val, base); | |
+ } | |
+ STR_RELEASE(str); | |
+ } | |
+ break; | |
+ case IS_ARRAY: | |
+ tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0); | |
+ zval_dtor(op); | |
+ ZVAL_LONG(op, tmp); | |
+ break; | |
+ case IS_OBJECT: | |
+ { | |
+ zval dst; | |
+ TSRMLS_FETCH(); | |
+ | |
+ convert_object_to_type(op, &dst, IS_BIGINT, convert_to_bigint_or_long); | |
+ zval_dtor(op); | |
+ | |
+ if (Z_TYPE(dst) == IS_BIGINT) { | |
+ ZVAL_COPY_VALUE(op, &dst); | |
+ } else { | |
+ zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name->val); | |
+ | |
+ ZVAL_NEW_BIGINT(op); | |
+ ZVAL_LONG(op, 1); | |
+ } | |
+ return; | |
+ } | |
+ EMPTY_SWITCH_DEFAULT_CASE() | |
+ } | |
+} | |
+/* }}} */ | |
+ | |
ZEND_API void convert_to_double(zval *op) /* {{{ */ | |
{ | |
double tmp; | |
@@ -459,6 +727,13 @@ ZEND_API void convert_to_double(zval *op) /* {{{ */ | |
break; | |
case IS_DOUBLE: | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ double d = zend_bigint_to_double(Z_BIG_P(op)); | |
+ zval_dtor(op); | |
+ ZVAL_DOUBLE(op, d); | |
+ } | |
+ break; | |
case IS_STRING: | |
{ | |
zend_string *str = Z_STR_P(op); | |
@@ -539,6 +814,13 @@ ZEND_API void convert_to_boolean(zval *op) /* {{{ */ | |
case IS_DOUBLE: | |
ZVAL_BOOL(op, Z_DVAL_P(op) ? 1 : 0); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_bool b = zend_bigint_to_bool(Z_BIG_P(op)); | |
+ zval_dtor(op); | |
+ ZVAL_BOOL(op, b); | |
+ } | |
+ break; | |
case IS_STRING: | |
{ | |
zend_string *str = Z_STR_P(op); | |
@@ -617,6 +899,10 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */ | |
ZVAL_NEW_STR(op, str); | |
break; | |
} | |
+ case IS_BIGINT: { | |
+ ZVAL_NEW_STR(op, zend_bigint_to_zend_string(Z_BIG_P(op), 0)); | |
+ break; | |
+ } | |
case IS_ARRAY: | |
zend_error(E_NOTICE, "Array to string conversion"); | |
zval_dtor(op); | |
@@ -798,6 +1084,8 @@ try_again: | |
return Z_LVAL_P(op); | |
case IS_DOUBLE: | |
return zend_dval_to_lval(Z_DVAL_P(op)); | |
+ case IS_BIGINT: | |
+ return zend_bigint_to_long(Z_BIG_P(op)); | |
case IS_STRING: | |
return strtol(Z_STRVAL_P(op), NULL, 10); | |
case IS_ARRAY: | |
@@ -836,6 +1124,8 @@ try_again: | |
return (double) Z_LVAL_P(op); | |
case IS_DOUBLE: | |
return Z_DVAL_P(op); | |
+ case IS_BIGINT: | |
+ return zend_bigint_to_double(Z_BIG_P(op)); | |
case IS_STRING: | |
return zend_strtod(Z_STRVAL_P(op), NULL); | |
case IS_ARRAY: | |
@@ -885,6 +1175,9 @@ try_again: | |
case IS_DOUBLE: { | |
return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op)); | |
} | |
+ case IS_BIGINT: { | |
+ return zend_bigint_to_zend_string(Z_BIG_P(op), 0); | |
+ } | |
case IS_ARRAY: | |
zend_error(E_NOTICE, "Array to string conversion"); | |
return STR_INIT("Array", sizeof("Array")-1, 0); | |
@@ -947,6 +1240,54 @@ ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * | |
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); | |
return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_add(out, Z_BIG_P(op1), Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_add_long(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_add_long(out, Z_BIG_P(op2), Z_LVAL_P(op1)); | |
+ /* unary plus does this */ | |
+ if (op2 == result) { | |
+ zval_dtor(op2); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_DOUBLE): | |
+ { | |
+ double out = zend_bigint_to_double(Z_BIG_P(op1)) + Z_DVAL_P(op2); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_DOUBLE(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_DOUBLE, IS_BIGINT): | |
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) + zend_bigint_to_double(Z_BIG_P(op2))); | |
+ return SUCCESS; | |
+ | |
case TYPE_PAIR(IS_ARRAY, IS_ARRAY): | |
if ((result == op1) && (result == op2)) { | |
/* $a += $a */ | |
@@ -1011,6 +1352,54 @@ ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * | |
ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); | |
return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_subtract(out, Z_BIG_P(op1), Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_subtract_long(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_long_subtract(out, Z_LVAL_P(op1), Z_BIG_P(op2)); | |
+ /* unary minus does this */ | |
+ if (op2 == result) { | |
+ zval_dtor(op2); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_DOUBLE): | |
+ { | |
+ double out = zend_bigint_to_double(Z_BIG_P(op1)) - Z_DVAL_P(op2); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_DOUBLE(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_DOUBLE, IS_BIGINT): | |
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) - zend_bigint_to_double(Z_BIG_P(op2))); | |
+ return SUCCESS; | |
+ | |
default: | |
if (Z_ISREF_P(op1)) { | |
op1 = Z_REFVAL_P(op1); | |
@@ -1041,8 +1430,8 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * | |
case TYPE_PAIR(IS_LONG, IS_LONG): { | |
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; | |
+ ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_BIG_P(result),overflow); | |
+ Z_TYPE_INFO_P(result) = overflow ? IS_BIGINT_EX : IS_LONG; | |
return SUCCESS; | |
} | |
@@ -1058,6 +1447,47 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * | |
ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); | |
return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_multiply(out, Z_BIG_P(op1), Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_multiply_long(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ ZVAL_BIGINT(result, zend_bigint_init_alloc()); | |
+ zend_bigint_multiply_long(Z_BIG_P(result), Z_BIG_P(op2), Z_LVAL_P(op1)); | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_DOUBLE): | |
+ { | |
+ double out = zend_bigint_to_double(Z_BIG_P(op1)) * Z_DVAL_P(op2); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_DOUBLE(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_DOUBLE, IS_BIGINT): | |
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) * zend_bigint_to_double(Z_BIG_P(op2))); | |
+ return SUCCESS; | |
+ | |
default: | |
if (Z_ISREF_P(op1)) { | |
op1 = Z_REFVAL_P(op1); | |
@@ -1099,20 +1529,28 @@ ZEND_API int pow_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * | |
while (i >= 1) { | |
long overflow; | |
- double dval = 0.0; | |
+ zend_bigint *big; | |
if (i % 2) { | |
--i; | |
- ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow); | |
+ ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, big, overflow); | |
if (overflow) { | |
- ZVAL_DOUBLE(result, dval * pow(l2, i)); | |
+ zend_bigint *big2; | |
+ big2 = zend_bigint_init_alloc(); | |
+ zend_bigint_long_pow_ulong(big2, l2, i); | |
+ zend_bigint_multiply(big, big, big2); | |
+ zend_bigint_dtor(big2); | |
+ efree(big2); | |
+ ZVAL_BIGINT(result, big); | |
return SUCCESS; | |
} | |
} else { | |
i /= 2; | |
- ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow); | |
+ ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, big, overflow); | |
if (overflow) { | |
- ZVAL_DOUBLE(result, (double)l1 * pow(dval, i)); | |
+ zend_bigint_pow_ulong(big, big, i); | |
+ zend_bigint_multiply_long(big, big, l1); | |
+ ZVAL_BIGINT(result, big); | |
return SUCCESS; | |
} | |
} | |
@@ -1136,6 +1574,73 @@ ZEND_API int pow_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * | |
ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2))); | |
return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ if (zend_bigint_sign(Z_BIG_P(op2)) < 0) { | |
+ double out = pow(zend_bigint_to_double(Z_BIG_P(op1)), zend_bigint_to_double(Z_BIG_P(op2))); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_DOUBLE(result, out); | |
+ return SUCCESS; | |
+ } | |
+ if (zend_bigint_can_fit_ulong(Z_BIG_P(op2))) { | |
+ unsigned long ulval = zend_bigint_to_ulong(Z_BIG_P(op2)); | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_pow_ulong(out, Z_BIG_P(op1), ulval); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ return SUCCESS; | |
+ } else { | |
+ zend_error(E_WARNING, "Exponent too large"); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; | |
+ } | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ if (Z_LVAL_P(op2) >= 0) { | |
+ unsigned long ulval = Z_LVAL_P(op2); | |
+ ZVAL_BIGINT(result, zend_bigint_init_alloc()); | |
+ zend_bigint_pow_ulong(Z_BIG_P(result), Z_BIG_P(op1), ulval); | |
+ } else { | |
+ ZVAL_DOUBLE(result, pow(zend_bigint_to_double(Z_BIG_P(op1)), (double)Z_LVAL_P(op2))); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ if (zend_bigint_sign(Z_BIG_P(op2)) <= 0) { | |
+ ZVAL_DOUBLE(result, pow(zend_bigint_to_double(Z_BIG_P(op1)), zend_bigint_to_double(Z_BIG_P(op2)))); | |
+ return SUCCESS; | |
+ } | |
+ if (zend_bigint_can_fit_ulong(Z_BIG_P(op2))) { | |
+ unsigned long ulval = zend_bigint_to_ulong(Z_BIG_P(op2)); | |
+ ZVAL_BIGINT(result, zend_bigint_init_alloc()); | |
+ zend_bigint_long_pow_ulong(Z_BIG_P(result), Z_LVAL_P(op1), ulval); | |
+ return SUCCESS; | |
+ } else { | |
+ zend_error(E_WARNING, "Exponent too large"); | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; | |
+ } | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_DOUBLE): | |
+ { | |
+ double out = pow(zend_bigint_to_double(Z_BIG_P(op1)), Z_DVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_DOUBLE(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_DOUBLE, IS_BIGINT): | |
+ ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), zend_bigint_to_double(Z_BIG_P(op2)))); | |
+ return SUCCESS; | |
+ | |
default: | |
if (Z_ISREF_P(op1)) { | |
op1 = Z_REFVAL_P(op1); | |
@@ -1217,6 +1722,98 @@ ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * | |
ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2)); | |
return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ if (zend_bigint_sign(Z_BIG_P(op2)) == 0) { | |
+ zend_error(E_WARNING, "Division by zero"); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; /* division by zero */ | |
+ } | |
+ if (zend_bigint_divisible(Z_BIG_P(op1), Z_BIG_P(op2))) { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_divide(out, Z_BIG_P(op1), Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } else { | |
+ double out = zend_bigint_to_double(Z_BIG_P(op1)) / zend_bigint_to_double(Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_DOUBLE(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ if (Z_LVAL_P(op2) == 0) { | |
+ zend_error(E_WARNING, "Division by zero"); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; /* division by zero */ | |
+ } | |
+ if (zend_bigint_divisible_long(Z_BIG_P(op1), Z_LVAL_P(op2))) { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_divide_long(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } else { | |
+ double out = zend_bigint_to_double(Z_BIG_P(op1)) / (double)Z_LVAL_P(op2); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_DOUBLE(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ if (zend_bigint_sign(Z_BIG_P(op2)) == 0) { | |
+ zend_error(E_WARNING, "Division by zero"); | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; /* division by zero */ | |
+ } | |
+ if (zend_bigint_long_divisible(Z_LVAL_P(op1), Z_BIG_P(op2))) { | |
+ ZVAL_BIGINT(result, zend_bigint_init_alloc()); | |
+ zend_bigint_long_divide(Z_BIG_P(result), Z_LVAL_P(op1), Z_BIG_P(op2)); | |
+ } else { | |
+ ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / zend_bigint_to_double(Z_BIG_P(op2))); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_DOUBLE): | |
+ { | |
+ double out; | |
+ if (Z_DVAL_P(op2) == 0) { | |
+ zend_error(E_WARNING, "Division by zero"); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; /* division by zero */ | |
+ } | |
+ out = zend_bigint_to_double(Z_BIG_P(op1)) / Z_DVAL_P(op2); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_DOUBLE(result, out); | |
+ } | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_DOUBLE, IS_BIGINT): | |
+ if (zend_bigint_sign(Z_BIG_P(op2)) == 0) { | |
+ zend_error(E_WARNING, "Division by zero"); | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; /* division by zero */ | |
+ } | |
+ ZVAL_DOUBLE(result, Z_DVAL_P(op1) / zend_bigint_to_double(Z_BIG_P(op2))); | |
+ return SUCCESS; | |
+ | |
default: | |
if (Z_ISREF_P(op1)) { | |
op1 = Z_REFVAL_P(op1); | |
@@ -1240,32 +1837,89 @@ ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * | |
ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ | |
{ | |
zval op1_copy, op2_copy; | |
- long op1_lval; | |
- if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { | |
+ if (!(Z_TYPE_P(op1) == IS_LONG || Z_TYPE_P(op1) == IS_BIGINT) | |
+ || !(Z_TYPE_P(op2) == IS_LONG || Z_TYPE_P(op2) == IS_BIGINT)) { | |
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD); | |
- zendi_convert_to_long(op1, op1_copy, result); | |
- op1_lval = Z_LVAL_P(op1); | |
- zendi_convert_to_long(op2, op2_copy, result); | |
- } else { | |
- op1_lval = Z_LVAL_P(op1); | |
+ zendi_convert_to_bigint_or_long(op1, op1_copy, result); | |
+ zendi_convert_to_bigint_or_long(op2, op2_copy, result); | |
} | |
- if (Z_LVAL_P(op2) == 0) { | |
- zend_error(E_WARNING, "Division by zero"); | |
- ZVAL_BOOL(result, 0); | |
- return FAILURE; /* modulus by zero */ | |
- } | |
- | |
- if (Z_LVAL_P(op2) == -1) { | |
- /* Prevent overflow error/crash if op1==LONG_MIN */ | |
- ZVAL_LONG(result, 0); | |
- return SUCCESS; | |
+ 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_BOOL(result, 0); | |
+ return FAILURE; /* modulus by zero */ | |
+ } | |
+ if (Z_LVAL_P(op2) == -1) { | |
+ /* Prevent overflow error/crash if op1==LONG_MIN */ | |
+ ZVAL_LONG(result, 0); | |
+ return SUCCESS; | |
+ } | |
+ ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ { | |
+ zend_bigint *out; | |
+ if (zend_bigint_sign(Z_BIG_P(op2)) == 0) { | |
+ zend_error(E_WARNING, "Division by zero"); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; /* modulus by zero */ | |
+ } | |
+ out = zend_bigint_init_alloc(); | |
+ zend_bigint_modulus(out, Z_BIG_P(op1), Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ if (op2 == &op2_copy) { | |
+ zval_dtor(&op2_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out; | |
+ if (Z_LVAL_P(op2) == 0) { | |
+ zend_error(E_WARNING, "Division by zero"); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; /* modulus by zero */ | |
+ } | |
+ out = zend_bigint_init_alloc(); | |
+ zend_bigint_modulus_long(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ if (zend_bigint_sign(Z_BIG_P(op2)) == 0) { | |
+ zend_error(E_WARNING, "Division by zero"); | |
+ ZVAL_BOOL(result, 0); | |
+ return FAILURE; /* modulus by zero */ | |
+ } | |
+ ZVAL_BIGINT(result, zend_bigint_init_alloc()); | |
+ zend_bigint_long_modulus(Z_BIG_P(result), Z_LVAL_P(op1), Z_BIG_P(op2)); | |
+ if (op2 == &op2_copy) { | |
+ zval_dtor(&op2_copy); | |
+ } | |
+ return SUCCESS; | |
} | |
- | |
- ZVAL_LONG(result, op1_lval % Z_LVAL_P(op2)); | |
- return SUCCESS; | |
} | |
/* }}} */ | |
@@ -1319,6 +1973,16 @@ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ | |
case IS_DOUBLE: | |
ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1))); | |
return SUCCESS; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_ones_complement(out, Z_BIG_P(op1)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ } | |
+ return SUCCESS; | |
case IS_STRING: { | |
int i; | |
zval op1_copy = *op1; | |
@@ -1342,7 +2006,6 @@ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ | |
ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ | |
{ | |
zval op1_copy, op2_copy; | |
- long op1_lval; | |
if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) { | |
zval *longer, *shorter; | |
@@ -1369,25 +2032,61 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / | |
return SUCCESS; | |
} | |
- if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { | |
+ if (!(Z_TYPE_P(op1) == IS_LONG || Z_TYPE_P(op1) == IS_BIGINT) | |
+ || !(Z_TYPE_P(op2) == IS_LONG || Z_TYPE_P(op2) == IS_BIGINT)) { | |
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR); | |
- zendi_convert_to_long(op1, op1_copy, result); | |
- op1_lval = Z_LVAL_P(op1); | |
- zendi_convert_to_long(op2, op2_copy, result); | |
- } else { | |
- op1_lval = Z_LVAL_P(op1); | |
+ zendi_convert_to_bigint_or_long(op1, op1_copy, result); | |
+ zendi_convert_to_bigint_or_long(op2, op2_copy, result); | |
} | |
- ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2)); | |
- return SUCCESS; | |
+ switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { | |
+ case TYPE_PAIR(IS_LONG, IS_LONG): | |
+ ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2)); | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_or(out, Z_BIG_P(op1), Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ if (op2 == &op2_copy) { | |
+ zval_dtor(&op2_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_or_long(Z_BIG_P(result), Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ ZVAL_BIGINT(result, zend_bigint_init_alloc()); | |
+ zend_bigint_long_or(Z_BIG_P(result), Z_LVAL_P(op1), Z_BIG_P(op2)); | |
+ if (op2 == &op2_copy) { | |
+ zval_dtor(&op2_copy); | |
+ } | |
+ return SUCCESS; | |
+ } | |
} | |
/* }}} */ | |
ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ | |
{ | |
zval op1_copy, op2_copy; | |
- long op1_lval; | |
if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) { | |
zval *longer, *shorter; | |
@@ -1414,25 +2113,61 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) | |
return SUCCESS; | |
} | |
- if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { | |
+ if (!(Z_TYPE_P(op1) == IS_LONG || Z_TYPE_P(op1) == IS_BIGINT) | |
+ || !(Z_TYPE_P(op2) == IS_LONG || Z_TYPE_P(op2) == IS_BIGINT)) { | |
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND); | |
- zendi_convert_to_long(op1, op1_copy, result); | |
- op1_lval = Z_LVAL_P(op1); | |
- zendi_convert_to_long(op2, op2_copy, result); | |
- } else { | |
- op1_lval = Z_LVAL_P(op1); | |
+ zendi_convert_to_bigint_or_long(op1, op1_copy, result); | |
+ zendi_convert_to_bigint_or_long(op2, op2_copy, result); | |
} | |
- ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2)); | |
- return SUCCESS; | |
+ switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { | |
+ case TYPE_PAIR(IS_LONG, IS_LONG): | |
+ ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2)); | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_and(out, Z_BIG_P(op1), Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ if (op2 == &op2_copy) { | |
+ zval_dtor(&op2_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_and_long(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ ZVAL_BIGINT(result, zend_bigint_init_alloc()); | |
+ zend_bigint_long_and(Z_BIG_P(result), Z_LVAL_P(op1), Z_BIG_P(op2)); | |
+ if (op2 == &op2_copy) { | |
+ zval_dtor(&op2_copy); | |
+ } | |
+ return SUCCESS; | |
+ } | |
} | |
/* }}} */ | |
ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ | |
{ | |
zval op1_copy, op2_copy; | |
- long op1_lval; | |
if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) { | |
zval *longer, *shorter; | |
@@ -1459,58 +2194,121 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) | |
return SUCCESS; | |
} | |
- if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { | |
+ if (!(Z_TYPE_P(op1) == IS_LONG || Z_TYPE_P(op1) == IS_BIGINT) | |
+ || !(Z_TYPE_P(op2) == IS_LONG || Z_TYPE_P(op2) == IS_BIGINT)) { | |
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR); | |
- zendi_convert_to_long(op1, op1_copy, result); | |
- op1_lval = Z_LVAL_P(op1); | |
- zendi_convert_to_long(op2, op2_copy, result); | |
- } else { | |
- op1_lval = Z_LVAL_P(op1); | |
+ zendi_convert_to_bigint_or_long(op1, op1_copy, result); | |
+ zendi_convert_to_bigint_or_long(op2, op2_copy, result); | |
} | |
- ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2)); | |
- return SUCCESS; | |
+ switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { | |
+ case TYPE_PAIR(IS_LONG, IS_LONG): | |
+ ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2)); | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_xor(out, Z_BIG_P(op1), Z_BIG_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ if (op2 == &op2_copy) { | |
+ zval_dtor(&op2_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_xor_long(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ ZVAL_BIGINT(result, zend_bigint_init_alloc()); | |
+ zend_bigint_long_xor(Z_BIG_P(result), Z_LVAL_P(op1), Z_BIG_P(op2)); | |
+ if (op2 == &op2_copy) { | |
+ zval_dtor(&op2_copy); | |
+ } | |
+ return SUCCESS; | |
+ } | |
} | |
/* }}} */ | |
ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ | |
{ | |
zval op1_copy, op2_copy; | |
- long op1_lval; | |
- if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { | |
+ if (!(Z_TYPE_P(op1) == IS_LONG || Z_TYPE_P(op1) == IS_BIGINT) | |
+ || Z_TYPE_P(op2) != IS_LONG) { | |
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL); | |
- zendi_convert_to_long(op1, op1_copy, result); | |
- op1_lval = Z_LVAL_P(op1); | |
+ zendi_convert_to_bigint_or_long(op1, op1_copy, result); | |
zendi_convert_to_long(op2, op2_copy, result); | |
- } else { | |
- op1_lval = Z_LVAL_P(op1); | |
} | |
- ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2)); | |
- return SUCCESS; | |
+ switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { | |
+ case TYPE_PAIR(IS_LONG, IS_LONG): | |
+ ZVAL_LONG(result, Z_LVAL_P(op1) << Z_LVAL_P(op2)); | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_shift_left_ulong(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ } | |
} | |
/* }}} */ | |
ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ | |
{ | |
zval op1_copy, op2_copy; | |
- long op1_lval; | |
- if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { | |
+ if (!(Z_TYPE_P(op1) == IS_LONG || Z_TYPE_P(op1) == IS_BIGINT) | |
+ || Z_TYPE_P(op2) != IS_LONG) { | |
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR); | |
- zendi_convert_to_long(op1, op1_copy, result); | |
- op1_lval = Z_LVAL_P(op1); | |
+ zendi_convert_to_bigint_or_long(op1, op1_copy, result); | |
zendi_convert_to_long(op2, op2_copy, result); | |
- } else { | |
- op1_lval = Z_LVAL_P(op1); | |
} | |
- ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2)); | |
- return SUCCESS; | |
+ switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { | |
+ case TYPE_PAIR(IS_LONG, IS_LONG): | |
+ ZVAL_LONG(result, Z_LVAL_P(op1) >> Z_LVAL_P(op2)); | |
+ return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ { | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_shift_right_ulong(out, Z_BIG_P(op1), Z_LVAL_P(op2)); | |
+ if (op1 == result) { | |
+ zval_dtor(op1); | |
+ } | |
+ ZVAL_BIGINT(result, out); | |
+ if (op1 == &op1_copy) { | |
+ zval_dtor(&op1_copy); | |
+ } | |
+ } | |
+ return SUCCESS; | |
+ } | |
} | |
/* }}} */ | |
@@ -1703,6 +2501,31 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { | |
} | |
return SUCCESS; | |
+ case TYPE_PAIR(IS_BIGINT, IS_BIGINT): | |
+ ZVAL_LONG(result, zend_bigint_cmp(Z_BIG_P(op1), Z_BIG_P(op2))); | |
+ ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result))); | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_LONG): | |
+ ZVAL_LONG(result, zend_bigint_cmp_long(Z_BIG_P(op1), Z_LVAL_P(op2))); | |
+ ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result))); | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_LONG, IS_BIGINT): | |
+ ZVAL_LONG(result, zend_bigint_cmp_long(Z_BIG_P(op2), Z_LVAL_P(op1))); | |
+ ZVAL_LONG(result, -ZEND_NORMALIZE_BOOL(Z_LVAL_P(result))); | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_BIGINT, IS_DOUBLE): | |
+ ZVAL_LONG(result, zend_bigint_cmp_double(Z_BIG_P(op1), Z_DVAL_P(op2))); | |
+ ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result))); | |
+ return SUCCESS; | |
+ | |
+ case TYPE_PAIR(IS_DOUBLE, IS_BIGINT): | |
+ ZVAL_LONG(result, zend_bigint_cmp_double(Z_BIG_P(op2), Z_DVAL_P(op1))); | |
+ ZVAL_LONG(result, -ZEND_NORMALIZE_BOOL(Z_LVAL_P(result))); | |
+ return SUCCESS; | |
+ | |
case TYPE_PAIR(IS_ARRAY, IS_ARRAY): | |
zend_compare_arrays(result, op1, op2 TSRMLS_CC); | |
return SUCCESS; | |
@@ -1887,6 +2710,13 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) | |
case IS_LONG: | |
ZVAL_BOOL(result, Z_LVAL_P(op1) == Z_LVAL_P(op2)); | |
break; | |
+ case IS_BIGINT: | |
+ if (Z_BIG_P(op1) == Z_BIG_P(op2)) { | |
+ ZVAL_BOOL(result, 1); | |
+ } else { | |
+ ZVAL_BOOL(result, !zend_bigint_cmp(Z_BIG_P(op1), Z_BIG_P(op2))); | |
+ } | |
+ break; | |
case IS_RESOURCE: | |
ZVAL_BOOL(result, Z_RES_P(op1) == Z_RES_P(op2)); | |
break; | |
@@ -2105,6 +2935,14 @@ try_again: | |
case IS_DOUBLE: | |
Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1; | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_bigint *new = zend_bigint_init_alloc(); | |
+ zend_bigint_add_long(new, Z_BIG_P(op1), 1); | |
+ zval_dtor(op1); | |
+ Z_BIG_P(op1) = new; | |
+ } | |
+ break; | |
case IS_NULL: | |
ZVAL_LONG(op1, 1); | |
break; | |
@@ -2175,6 +3013,14 @@ try_again: | |
case IS_DOUBLE: | |
Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1; | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_bigint *new = zend_bigint_init_alloc(); | |
+ zend_bigint_subtract_long(new, Z_BIG_P(op1), 1); | |
+ zval_dtor(op1); | |
+ Z_BIG_P(op1) = new; | |
+ } | |
+ break; | |
case IS_STRING: /* Like perl we only support string increment */ | |
if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */ | |
STR_RELEASE(Z_STR_P(op1)); | |
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h | |
index b952b98..5c33c5a 100644 | |
--- a/Zend/zend_operators.h | |
+++ b/Zend/zend_operators.h | |
@@ -36,6 +36,7 @@ | |
#include "zend_strtod.h" | |
#include "zend_multiply.h" | |
+#include "zend_bigint.h" | |
#if 0&&HAVE_BCMATH | |
#include "ext/bcmath/libbcmath/src/bcmath.h" | |
@@ -330,6 +331,10 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC); | |
ZEND_API void convert_to_long(zval *op); | |
ZEND_API void convert_to_double(zval *op); | |
ZEND_API void convert_to_long_base(zval *op, int base); | |
+ZEND_API void convert_to_bigint(zval *op); | |
+ZEND_API void convert_to_bigint_base(zval *op, int base); | |
+ZEND_API void convert_to_bigint_or_long(zval *op); | |
+ZEND_API void convert_to_bigint_or_long_base(zval *op, int base); | |
ZEND_API void convert_to_null(zval *op); | |
ZEND_API void convert_to_boolean(zval *op); | |
ZEND_API void convert_to_array(zval *op); | |
@@ -417,6 +422,9 @@ END_EXTERN_C() | |
case IS_DOUBLE: \ | |
convert_to_double(pzv); \ | |
break; \ | |
+ case IS_BIGINT_OR_LONG: \ | |
+ convert_to_bigint_or_long(pzv); \ | |
+ break; \ | |
case _IS_BOOL: \ | |
convert_to_boolean(pzv); \ | |
break; \ | |
@@ -441,13 +449,15 @@ END_EXTERN_C() | |
convert_to_explicit_type(pzv, str_type); \ | |
} | |
-#define convert_to_boolean_ex(pzv) convert_to_ex_master(pzv, boolean, _IS_BOOL) | |
-#define convert_to_long_ex(pzv) convert_to_ex_master(pzv, long, IS_LONG) | |
-#define convert_to_double_ex(pzv) convert_to_ex_master(pzv, double, IS_DOUBLE) | |
-#define convert_to_string_ex(pzv) convert_to_ex_master(pzv, string, IS_STRING) | |
-#define convert_to_array_ex(pzv) convert_to_ex_master(pzv, array, IS_ARRAY) | |
-#define convert_to_object_ex(pzv) convert_to_ex_master(pzv, object, IS_OBJECT) | |
-#define convert_to_null_ex(pzv) convert_to_ex_master(pzv, null, IS_NULL) | |
+#define convert_to_boolean_ex(pzv) convert_to_ex_master(pzv, boolean, _IS_BOOL) | |
+#define convert_to_long_ex(pzv) convert_to_ex_master(pzv, long, IS_LONG) | |
+#define convert_to_double_ex(pzv) convert_to_ex_master(pzv, double, IS_DOUBLE) | |
+#define convert_to_bigint_ex(pzv) convert_to_ex_master(pzv, bigint, IS_LONG) | |
+#define convert_to_bigint_or_long_ex(pzv) convert_to_ex_master(pzv, bigint_or_long, IS_BIGINT_OR_LONG) | |
+#define convert_to_string_ex(pzv) convert_to_ex_master(pzv, string, IS_STRING) | |
+#define convert_to_array_ex(pzv) convert_to_ex_master(pzv, array, IS_ARRAY) | |
+#define convert_to_object_ex(pzv) convert_to_ex_master(pzv, object, IS_OBJECT) | |
+#define convert_to_null_ex(pzv) convert_to_ex_master(pzv, null, IS_NULL) | |
#define convert_scalar_to_number_ex(pzv) \ | |
if (Z_TYPE_P(pzv)!=IS_LONG && Z_TYPE_P(pzv)!=IS_DOUBLE) { \ | |
@@ -560,7 +570,9 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o | |
{ | |
if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { | |
if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { | |
-#if defined(__GNUC__) && defined(__i386__) | |
+/* assembly commented-out as it uses the old float overflow behaviour | |
+ * however, now longs overflow to bigints, so we can't use it */ | |
+/*#if defined(__GNUC__) && defined(__i386__) | |
__asm__( | |
"movl (%1), %%eax\n\t" | |
"addl (%2), %%eax\n\t" | |
@@ -606,7 +618,7 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o | |
"n"(IS_DOUBLE), | |
"n"(ZVAL_OFFSETOF_TYPE) | |
: "rax","cc"); | |
-#else | |
+#else*/ | |
/* | |
* 'result' may alias with op1 or op2, so we need to | |
* ensure that 'result' is not updated until after we | |
@@ -615,11 +627,13 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o | |
if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) | |
&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) { | |
- ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2)); | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_long_add_long(out, Z_LVAL_P(op1), Z_LVAL_P(op2)); | |
+ ZVAL_BIGINT(result, out); | |
} else { | |
ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2)); | |
} | |
-#endif | |
+/*#endif*/ | |
return SUCCESS; | |
} else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { | |
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); | |
@@ -641,7 +655,9 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o | |
{ | |
if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { | |
if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { | |
-#if defined(__GNUC__) && defined(__i386__) | |
+/* assembly commented-out as it uses the old float overflow behaviour | |
+* however, now longs overflow to bigints, so we can't use it */ | |
+/*#if defined(__GNUC__) && defined(__i386__) | |
__asm__( | |
"movl (%1), %%eax\n\t" | |
"subl (%2), %%eax\n\t" | |
@@ -654,7 +670,7 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o | |
"fildl (%1)\n\t" | |
#if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10)) | |
"fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */ | |
-#else | |
+/*#else | |
"fsubp %%st, %%st(1)\n\t" | |
#endif | |
"movl %4, %c5(%0)\n\t" | |
@@ -681,7 +697,7 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o | |
"fildq (%1)\n\t" | |
#if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10)) | |
"fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */ | |
-#else | |
+/*#else | |
"fsubp %%st, %%st(1)\n\t" | |
#endif | |
"movl %4, %c5(%0)\n\t" | |
@@ -695,14 +711,16 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o | |
"n"(IS_DOUBLE), | |
"n"(ZVAL_OFFSETOF_TYPE) | |
: "rax","cc"); | |
-#else | |
+#else*/ | |
ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2)); | |
if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK) | |
&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) { | |
- ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2)); | |
+ zend_bigint *out = zend_bigint_init_alloc(); | |
+ zend_bigint_long_subtract_long(out, Z_LVAL_P(op1), Z_LVAL_P(op2)); | |
+ ZVAL_BIGINT(result, out); | |
} | |
-#endif | |
+/*#endif*/ | |
return SUCCESS; | |
} else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { | |
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2)); | |
@@ -726,8 +744,8 @@ static zend_always_inline int fast_mul_function(zval *result, zval *op1, zval *o | |
if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { | |
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; | |
+ ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_BIG_P(result), overflow); | |
+ Z_TYPE_INFO_P(result) = overflow ? IS_BIGINT_EX : IS_LONG; | |
return SUCCESS; | |
} else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { | |
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2)); | |
diff --git a/Zend/zend_types.h b/Zend/zend_types.h | |
index 232fcba..c773f21 100644 | |
--- a/Zend/zend_types.h | |
+++ b/Zend/zend_types.h | |
@@ -22,6 +22,9 @@ | |
#ifndef ZEND_TYPES_H | |
#define ZEND_TYPES_H | |
+/* For defining zend_bigint */ | |
+#include <gmp.h> | |
+ | |
#ifdef WORDS_BIGENDIAN | |
# define ZEND_ENDIAN_LOHI(lo, hi) hi; lo; | |
# define ZEND_ENDIAN_LOHI_3(lo, mi, hi) hi; mi; lo; | |
@@ -73,6 +76,7 @@ typedef union _zend_function zend_function; | |
typedef struct _zval_struct zval; | |
typedef struct _zend_refcounted zend_refcounted; | |
+typedef struct _zend_bigint zend_bigint; | |
typedef struct _zend_string zend_string; | |
typedef struct _zend_array zend_array; | |
typedef struct _zend_object zend_object; | |
@@ -89,6 +93,7 @@ typedef void (*copy_ctor_func_t)(zval *pElement); | |
typedef union _zend_value { | |
long lval; /* long value */ | |
double dval; /* double value */ | |
+ zend_bigint *big; | |
zend_refcounted *counted; | |
zend_string *str; | |
zend_array *arr; | |
@@ -135,6 +140,11 @@ struct _zend_refcounted { | |
} u; | |
}; | |
+struct _zend_bigint { | |
+ zend_refcounted gc; | |
+ mpz_t mpz; | |
+}; | |
+ | |
struct _zend_string { | |
zend_refcounted gc; | |
zend_ulong h; /* hash value */ | |
@@ -208,24 +218,26 @@ struct _zend_ast_ref { | |
#define IS_TRUE 3 | |
#define IS_LONG 4 | |
#define IS_DOUBLE 5 | |
-#define IS_STRING 6 | |
-#define IS_ARRAY 7 | |
-#define IS_OBJECT 8 | |
-#define IS_RESOURCE 9 | |
-#define IS_REFERENCE 10 | |
+#define IS_STRING 7 | |
+#define IS_BIGINT 8 | |
+#define IS_ARRAY 9 | |
+#define IS_OBJECT 10 | |
+#define IS_RESOURCE 11 | |
+#define IS_REFERENCE 12 | |
/* constant expressions */ | |
-#define IS_CONSTANT 11 | |
-#define IS_CONSTANT_AST 12 | |
+#define IS_CONSTANT 13 | |
+#define IS_CONSTANT_AST 14 | |
/* fake types */ | |
-#define _IS_BOOL 13 | |
-#define IS_CALLABLE 14 | |
+#define _IS_BOOL 15 | |
+#define IS_CALLABLE 16 | |
+#define IS_BIGINT_OR_LONG 17 | |
/* internal types */ | |
-#define IS_INDIRECT 15 | |
-#define IS_STR_OFFSET 16 | |
-#define IS_PTR 17 | |
+#define IS_INDIRECT 18 | |
+#define IS_STR_OFFSET 19 | |
+#define IS_PTR 20 | |
static inline zend_uchar zval_get_type(const zval* pz) { | |
return pz->u1.v.type; | |
@@ -289,6 +301,7 @@ static inline zend_uchar zval_get_type(const zval* pz) { | |
#define IS_STRING_EX (IS_STRING | (( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) | |
#define IS_ARRAY_EX (IS_ARRAY | (( IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) | |
+#define IS_BIGINT_EX (IS_BIGINT | (( IS_TYPE_REFCOUNTED ) << Z_TYPE_FLAGS_SHIFT)) | |
#define IS_OBJECT_EX (IS_OBJECT | (( IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE ) << Z_TYPE_FLAGS_SHIFT)) | |
#define IS_RESOURCE_EX (IS_RESOURCE | (( IS_TYPE_REFCOUNTED ) << Z_TYPE_FLAGS_SHIFT)) | |
#define IS_REFERENCE_EX (IS_REFERENCE | (( IS_TYPE_REFCOUNTED ) << Z_TYPE_FLAGS_SHIFT)) | |
@@ -387,6 +400,9 @@ static inline zend_uchar zval_get_type(const zval* pz) { | |
#define Z_DVAL(zval) (zval).value.dval | |
#define Z_DVAL_P(zval_p) Z_DVAL(*(zval_p)) | |
+#define Z_BIG(zval) (zval).value.big | |
+#define Z_BIG_P(zval_p) Z_BIG(*(zval_p)) | |
+ | |
#define Z_STR(zval) (zval).value.str | |
#define Z_STR_P(zval_p) Z_STR(*(zval_p)) | |
@@ -495,6 +511,21 @@ static inline zend_uchar zval_get_type(const zval* pz) { | |
Z_TYPE_INFO_P(__z) = IS_DOUBLE; \ | |
} | |
+#define ZVAL_BIGINT(z, b) { \ | |
+ zval *__z = (z); \ | |
+ Z_BIG_P(__z) = b; \ | |
+ Z_TYPE_INFO_P(__z) = IS_BIGINT_EX; \ | |
+ } | |
+ | |
+#define ZVAL_NEW_BIGINT(z) do { \ | |
+ zval *__z = (z); \ | |
+ zend_bigint *_big = emalloc(sizeof(zend_bigint)); \ | |
+ GC_REFCOUNT(_big) = 1; \ | |
+ GC_TYPE_INFO(_big) = IS_BIGINT; \ | |
+ Z_BIG_P(__z) = _big; \ | |
+ Z_TYPE_INFO_P(__z) = IS_BIGINT_EX; \ | |
+ } while (0) | |
+ | |
#define ZVAL_STR(z, s) do { \ | |
zval *__z = (z); \ | |
zend_string *__s = (s); \ | |
diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c | |
index 2031b01..07210df 100644 | |
--- a/Zend/zend_variables.c | |
+++ b/Zend/zend_variables.c | |
@@ -26,6 +26,7 @@ | |
#include "zend_globals.h" | |
#include "zend_constants.h" | |
#include "zend_list.h" | |
+#include "zend_bigint.h" | |
ZEND_API void _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC) | |
{ | |
@@ -50,6 +51,15 @@ ZEND_API void _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC) | |
} | |
break; | |
} | |
+ case IS_BIGINT: { | |
+ zend_bigint *big = (zend_bigint*)p; | |
+ | |
+ if (--GC_REFCOUNT(big) <= 0) { | |
+ zend_bigint_dtor(big); | |
+ efree(big); | |
+ } | |
+ break; | |
+ } | |
case IS_CONSTANT_AST: { | |
zend_ast_ref *ast = (zend_ast_ref*)p; | |
@@ -110,6 +120,13 @@ ZEND_API void _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE_LINE_DC) | |
} | |
break; | |
} | |
+ case IS_BIGINT: { | |
+ zend_bigint *big = (zend_bigint*)p; | |
+ | |
+ zend_bigint_dtor(big); | |
+ efree(big); | |
+ break; | |
+ } | |
case IS_CONSTANT_AST: { | |
zend_ast_ref *ast = (zend_ast_ref*)p; | |
@@ -153,10 +170,11 @@ ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC) | |
STR_RELEASE(Z_STR_P(zvalue)); | |
break; | |
case IS_ARRAY: | |
+ case IS_BIGINT: | |
case IS_CONSTANT_AST: | |
case IS_OBJECT: | |
case IS_RESOURCE: | |
- zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources"); | |
+ zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, bigints, constant ASTs, objects or resources"); | |
break; | |
case IS_REFERENCE: { | |
zend_reference *ref = (zend_reference*)Z_REF_P(zvalue); | |
@@ -184,10 +202,11 @@ ZEND_API void _zval_internal_dtor_for_ptr(zval *zvalue ZEND_FILE_LINE_DC) | |
STR_FREE(Z_STR_P(zvalue)); | |
break; | |
case IS_ARRAY: | |
+ case IS_BIGINT: | |
case IS_CONSTANT_AST: | |
case IS_OBJECT: | |
case IS_RESOURCE: | |
- zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources"); | |
+ zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, bigints, constant ASTs, objects or resources"); | |
break; | |
case IS_REFERENCE: { | |
zend_reference *ref = (zend_reference*)Z_REF_P(zvalue); | |
@@ -257,6 +276,7 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) | |
Z_AST_P(zvalue) = ast; | |
} | |
break; | |
+ case IS_BIGINT: | |
case IS_OBJECT: | |
case IS_RESOURCE: | |
case IS_REFERENCE: | |
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h | |
index 8aa60ce..7f66b7c 100644 | |
--- a/Zend/zend_vm_def.h | |
+++ b/Zend/zend_vm_def.h | |
@@ -3763,6 +3763,17 @@ ZEND_VM_C_LABEL(num_index): | |
ZEND_VM_C_LABEL(str_index): | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
ZEND_VM_C_GOTO(str_index); | |
@@ -4174,6 +4185,21 @@ ZEND_VM_C_LABEL(num_index_dim): | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
ZEND_VM_C_LABEL(numeric_index_dim): | |
zend_hash_index_del(ht, hval); | |
if (OP2_TYPE == IS_CV || OP2_TYPE == IS_VAR) { | |
@@ -4701,6 +4727,17 @@ ZEND_VM_C_LABEL(num_index_prop): | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
ZEND_VM_C_GOTO(num_index_prop); | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
ZEND_VM_C_GOTO(str_index_prop); | |
@@ -4750,6 +4787,9 @@ ZEND_VM_C_LABEL(num_index_prop): | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -4819,6 +4859,8 @@ ZEND_VM_HANDLER(79, ZEND_EXIT, CONST|TMP|VAR|UNUSED|CV, ANY) | |
if (Z_TYPE_P(ptr) == IS_LONG) { | |
EG(exit_status) = Z_LVAL_P(ptr); | |
+ } else if (Z_TYPE_P(ptr) == IS_BIGINT) { | |
+ EG(exit_status) = zend_bigint_to_long(Z_BIG_P(ptr)); | |
} else { | |
zend_print_variable(ptr TSRMLS_CC); | |
} | |
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h | |
index 1babe85..c83ec5d 100644 | |
--- a/Zend/zend_vm_execute.h | |
+++ b/Zend/zend_vm_execute.h | |
@@ -3220,6 +3220,8 @@ static int ZEND_FASTCALL ZEND_EXIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) | |
if (Z_TYPE_P(ptr) == IS_LONG) { | |
EG(exit_status) = Z_LVAL_P(ptr); | |
+ } else if (Z_TYPE_P(ptr) == IS_BIGINT) { | |
+ EG(exit_status) = zend_bigint_to_long(Z_BIG_P(ptr)); | |
} else { | |
zend_print_variable(ptr TSRMLS_CC); | |
} | |
@@ -4071,6 +4073,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -4941,6 +4954,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -5775,6 +5799,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -6452,6 +6487,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -7344,6 +7390,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -8410,6 +8467,8 @@ static int ZEND_FASTCALL ZEND_EXIT_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) | |
if (Z_TYPE_P(ptr) == IS_LONG) { | |
EG(exit_status) = Z_LVAL_P(ptr); | |
+ } else if (Z_TYPE_P(ptr) == IS_BIGINT) { | |
+ EG(exit_status) = zend_bigint_to_long(Z_BIG_P(ptr)); | |
} else { | |
zend_print_variable(ptr TSRMLS_CC); | |
} | |
@@ -9205,6 +9264,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -10042,6 +10112,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -10876,6 +10957,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -11439,6 +11531,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -12258,6 +12361,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -13810,6 +13924,8 @@ static int ZEND_FASTCALL ZEND_EXIT_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) | |
if (Z_TYPE_P(ptr) == IS_LONG) { | |
EG(exit_status) = Z_LVAL_P(ptr); | |
+ } else if (Z_TYPE_P(ptr) == IS_BIGINT) { | |
+ EG(exit_status) = zend_bigint_to_long(Z_BIG_P(ptr)); | |
} else { | |
zend_print_variable(ptr TSRMLS_CC); | |
} | |
@@ -15680,6 +15796,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -15858,6 +15985,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { | |
@@ -16058,6 +16200,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -16107,6 +16260,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -17821,6 +17977,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -17927,6 +18094,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { | |
@@ -18048,6 +18230,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -18097,6 +18290,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -20025,6 +20221,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -20203,6 +20410,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { | |
@@ -20403,6 +20625,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -20452,6 +20685,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -21483,6 +21719,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -23408,6 +23655,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -23514,6 +23772,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_CV == IS_CV || IS_CV == IS_VAR) { | |
@@ -23635,6 +23908,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -23684,6 +23968,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -23960,6 +24247,8 @@ static int ZEND_FASTCALL ZEND_EXIT_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS | |
if (Z_TYPE_P(ptr) == IS_LONG) { | |
EG(exit_status) = Z_LVAL_P(ptr); | |
+ } else if (Z_TYPE_P(ptr) == IS_BIGINT) { | |
+ EG(exit_status) = zend_bigint_to_long(Z_BIG_P(ptr)); | |
} else { | |
zend_print_variable(ptr TSRMLS_CC); | |
} | |
@@ -24982,6 +25271,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { | |
@@ -25103,6 +25407,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -25152,6 +25467,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -26267,6 +26585,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { | |
@@ -26388,6 +26721,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -26437,6 +26781,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -27554,6 +27901,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { | |
@@ -27675,6 +28037,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -27724,6 +28097,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -29356,6 +29732,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_CV == IS_CV || IS_CV == IS_VAR) { | |
@@ -29477,6 +29868,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -29526,6 +29928,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -30883,6 +31288,8 @@ static int ZEND_FASTCALL ZEND_EXIT_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) | |
if (Z_TYPE_P(ptr) == IS_LONG) { | |
EG(exit_status) = Z_LVAL_P(ptr); | |
+ } else if (Z_TYPE_P(ptr) == IS_BIGINT) { | |
+ EG(exit_status) = zend_bigint_to_long(Z_BIG_P(ptr)); | |
} else { | |
zend_print_variable(ptr TSRMLS_CC); | |
} | |
@@ -32536,6 +32943,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -32714,6 +33132,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_CONST == IS_CV || IS_CONST == IS_VAR) { | |
@@ -32914,6 +33347,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -32963,6 +33407,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -34560,6 +35007,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -34666,6 +35124,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) { | |
@@ -34787,6 +35260,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -34836,6 +35320,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -36646,6 +37133,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -36824,6 +37322,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { | |
@@ -37024,6 +37537,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -37073,6 +37597,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
@@ -37988,6 +38515,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -39777,6 +40315,17 @@ num_index: | |
str_index: | |
zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr); | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr); | |
+ } else { | |
+ zend_hash_str_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), temp_str, strlen(temp_str), expr_ptr); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index; | |
@@ -39883,6 +40432,21 @@ num_index_dim: | |
zval_ptr_dtor(offset); | |
} | |
break; | |
+ case IS_BIGINT: | |
+ { | |
+ zend_string *temp_str = zend_bigint_to_zend_string(Z_BIG_P(offset), 0); | |
+ if (ZEND_HANDLE_NUMERIC(temp_str, hval)) { | |
+ zend_hash_index_del(ht, hval); | |
+ } else { | |
+ if (ht == &EG(symbol_table).ht) { | |
+ zend_delete_global_variable(temp_str TSRMLS_CC); | |
+ } else { | |
+ zend_hash_del(ht, temp_str); | |
+ } | |
+ } | |
+ STR_RELEASE(temp_str); | |
+ } | |
+ break; | |
numeric_index_dim: | |
zend_hash_index_del(ht, hval); | |
if (IS_CV == IS_CV || IS_CV == IS_VAR) { | |
@@ -40004,6 +40568,17 @@ num_index_prop: | |
case IS_DOUBLE: | |
hval = zend_dval_to_lval(Z_DVAL_P(offset)); | |
goto num_index_prop; | |
+ case IS_BIGINT: | |
+ { | |
+ char *temp_str = zend_bigint_to_string(Z_BIG_P(offset)); | |
+ if (ZEND_HANDLE_NUMERIC_STR(temp_str, strlen(temp_str), hval)) { | |
+ value = zend_hash_index_find(ht, hval); | |
+ } else { | |
+ value = zend_hash_str_find_ind(ht, temp_str, strlen(temp_str)); | |
+ } | |
+ efree(temp_str); | |
+ } | |
+ break; | |
case IS_NULL: | |
str = STR_EMPTY_ALLOC(); | |
goto str_index_prop; | |
@@ -40053,6 +40628,9 @@ num_index_prop: | |
ZVAL_DUP(&tmp, offset); | |
convert_to_long(&tmp); | |
offset = &tmp; | |
+ } else if (Z_TYPE_P(offset) == IS_BIGINT) { | |
+ ZVAL_LONG(&tmp, zend_bigint_to_long(Z_BIG_P(offset))); | |
+ offset = &tmp; | |
} | |
} | |
if (Z_TYPE_P(offset) == IS_LONG) { | |
diff --git a/configure.in b/configure.in | |
index 8781cbc..ccbc2cb 100644 | |
--- a/configure.in | |
+++ b/configure.in | |
@@ -1476,7 +1476,7 @@ PHP_ADD_SOURCES(Zend, \ | |
zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ | |
zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \ | |
zend_closures.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ | |
- zend_virtual_cwd.c zend_ast.c) | |
+ zend_virtual_cwd.c zend_ast.c zend_bigint.c) | |
if test -r "$abs_srcdir/Zend/zend_objects.c"; then | |
PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_default_classes.c) | |
diff --git a/ext/standard/type.c b/ext/standard/type.c | |
index a42dd0b..99c6a6e 100644 | |
--- a/ext/standard/type.c | |
+++ b/ext/standard/type.c | |
@@ -42,6 +42,7 @@ PHP_FUNCTION(gettype) | |
break; | |
case IS_LONG: | |
+ case IS_BIGINT: | |
RETVAL_STRING("integer"); | |
break; | |
@@ -324,6 +325,7 @@ PHP_FUNCTION(is_numeric) | |
switch (Z_TYPE_P(arg)) { | |
case IS_LONG: | |
case IS_DOUBLE: | |
+ case IS_BIGINT: | |
RETURN_TRUE; | |
break; | |
@@ -357,6 +359,7 @@ PHP_FUNCTION(is_scalar) | |
case IS_TRUE: | |
case IS_DOUBLE: | |
case IS_LONG: | |
+ case IS_BIGINT: | |
case IS_STRING: | |
RETURN_TRUE; | |
break; | |
diff --git a/ext/standard/var.c b/ext/standard/var.c | |
index 1a6a165..9df93ca 100644 | |
--- a/ext/standard/var.c | |
+++ b/ext/standard/var.c | |
@@ -103,6 +103,7 @@ PHPAPI void php_var_dump(zval *struc, int level TSRMLS_DC) /* {{{ */ | |
ulong num; | |
zend_string *key; | |
zval *val; | |
+ char *temp_str; | |
if (level > 1) { | |
php_printf("%*c", level - 1, ' '); | |
@@ -122,6 +123,11 @@ again: | |
case IS_LONG: | |
php_printf("%sint(%ld)\n", COMMON, Z_LVAL_P(struc)); | |
break; | |
+ case IS_BIGINT: | |
+ temp_str = zend_bigint_to_string(Z_BIG_P(struc)); | |
+ php_printf("%sint(%s)\n", COMMON, temp_str); | |
+ efree(temp_str); | |
+ break; | |
case IS_DOUBLE: | |
php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_P(struc)); | |
break; | |
diff --git a/win32/build/config.w32 b/win32/build/config.w32 | |
index 3fe8469..16f8248 100644 | |
--- a/win32/build/config.w32 | |
+++ b/win32/build/config.w32 | |
@@ -362,7 +362,7 @@ ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ | |
zend_stream.c zend_iterators.c zend_interfaces.c zend_objects.c \ | |
zend_object_handlers.c zend_objects_API.c \ | |
zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c \ | |
- zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c"); | |
+ zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c zend_bigint.c"); | |
if (VCVERS == 1200) { | |
AC_DEFINE('ZEND_DVAL_TO_LVAL_CAST_OK', 1); | |
-- | |
1.8.5.2 (Apple Git-48) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment