From 10f516146a79e8181d50b926079b0d9c02efb266 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 21:40:17 +0000 Subject: [PATCH 01/22] ext/gmp: Split out non-existent inverse modulo cases --- ext/gmp/tests/gmp_invert.phpt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ext/gmp/tests/gmp_invert.phpt b/ext/gmp/tests/gmp_invert.phpt index 22b22577db0dc..e2cd5c252abc7 100644 --- a/ext/gmp/tests/gmp_invert.phpt +++ b/ext/gmp/tests/gmp_invert.phpt @@ -6,7 +6,6 @@ gmp getMessage() . \PHP_EOL; } -var_dump(gmp_strval(gmp_invert(0,28347))); -var_dump(gmp_strval(gmp_invert(-12,456456))); -var_dump(gmp_strval(gmp_invert(234234,-435345))); +echo "No inverse modulo\n"; +var_dump(gmp_invert(123123,"3333334345467624")); +var_dump(gmp_invert(0,28347)); +var_dump(gmp_invert(-12,456456)); +var_dump(gmp_invert(234234,-435345)); $n = gmp_init("349827349623423452345"); $n1 = gmp_init("3498273496234234523451"); @@ -52,13 +53,14 @@ echo "Done\n"; ?> --EXPECT-- string(7) "2293131" -string(1) "0" string(4) "5827" Division by zero Division by zero -string(1) "0" -string(1) "0" -string(1) "0" +No inverse modulo +bool(false) +bool(false) +bool(false) +bool(false) string(22) "3498273496234234523441" string(1) "1" gmp_invert(): Argument #1 ($num1) must be of type GMP|string|int, array given From 5b5af60f1643be4dfe3310b12f685b4f4c92ee2e Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 18:17:24 +0000 Subject: [PATCH 02/22] ext/gmp: Use Fast ZPP for GMP functions --- ext/gmp/gmp.c | 232 +++++++++++++++++++++++++++++--------------------- 1 file changed, 133 insertions(+), 99 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index c3386bc3a9389..84bd75d729107 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -888,9 +888,10 @@ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op { zval *a_arg, *b_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + ZEND_PARSE_PARAMETERS_END(); gmp_zval_binary_ui_op( return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero, /* is_operator */ false); @@ -919,9 +920,9 @@ static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gm { zval *a_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); gmp_zval_unary_op(return_value, a_arg, gmp_op); } @@ -934,9 +935,9 @@ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); RETVAL_LONG(gmp_op(gmpnum_a)); @@ -1071,9 +1072,12 @@ ZEND_FUNCTION(gmp_export) mpz_ptr gmpnumber; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", &gmpnumber_arg, &size, &options) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_ZVAL(gmpnumber_arg) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(size) + Z_PARAM_LONG(options) + ZEND_PARSE_PARAMETERS_END(); if (!gmp_import_export_validate(size, options, &order, &endian)) { RETURN_THROWS(); @@ -1111,9 +1115,9 @@ ZEND_FUNCTION(gmp_intval) mpz_ptr gmpnum; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &gmpnumber_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(gmpnumber_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a, 1); RETVAL_LONG(mpz_get_si(gmpnum)); @@ -1129,9 +1133,11 @@ ZEND_FUNCTION(gmp_strval) mpz_ptr gmpnum; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &base) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(gmpnumber_arg) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(base) + ZEND_PARSE_PARAMETERS_END(); /* Although the maximum base in general in GMP is 62, mpz_get_str() * is explicitly limited to -36 when dealing with negative bases. */ @@ -1175,9 +1181,12 @@ ZEND_FUNCTION(gmp_div_qr) zval *a_arg, *b_arg; zend_long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(round) + ZEND_PARSE_PARAMETERS_END(); switch (round) { case GMP_ROUND_ZERO: @@ -1202,9 +1211,12 @@ ZEND_FUNCTION(gmp_div_r) zval *a_arg, *b_arg; zend_long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(round) + ZEND_PARSE_PARAMETERS_END(); switch (round) { case GMP_ROUND_ZERO: @@ -1232,9 +1244,12 @@ ZEND_FUNCTION(gmp_div_q) zval *a_arg, *b_arg; zend_long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(round) + ZEND_PARSE_PARAMETERS_END(); switch (round) { case GMP_ROUND_ZERO: @@ -1291,9 +1306,9 @@ ZEND_FUNCTION(gmp_fact) zval *a_arg; mpz_ptr gmpnum_result; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE_P(a_arg) == IS_LONG) { if (Z_LVAL_P(a_arg) < 0) { @@ -1325,9 +1340,10 @@ ZEND_FUNCTION(gmp_binomial) zend_long k; mpz_ptr gmpnum_result; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &n_arg, &k) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(n_arg) + Z_PARAM_LONG(k) + ZEND_PARSE_PARAMETERS_END(); if (k < 0) { zend_argument_value_error(2, "must be greater than or equal to 0"); @@ -1355,9 +1371,10 @@ ZEND_FUNCTION(gmp_pow) gmp_temp_t temp_base; zend_long exp; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &base_arg, &exp) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(base_arg) + Z_PARAM_LONG(exp) + ZEND_PARSE_PARAMETERS_END(); if (exp < 0) { zend_argument_value_error(2, "must be greater than or equal to 0"); @@ -1398,9 +1415,11 @@ ZEND_FUNCTION(gmp_powm) int use_ui = 0; gmp_temp_t temp_base, temp_exp, temp_mod; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_ZVAL(base_arg) + Z_PARAM_ZVAL(exp_arg) + Z_PARAM_ZVAL(mod_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base, 1); @@ -1446,9 +1465,9 @@ ZEND_FUNCTION(gmp_sqrt) mpz_ptr gmpnum_a, gmpnum_result; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); @@ -1472,9 +1491,9 @@ ZEND_FUNCTION(gmp_sqrtrem) gmp_temp_t temp_a; zval result1, result2; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); @@ -1504,9 +1523,10 @@ ZEND_FUNCTION(gmp_root) mpz_ptr gmpnum_a, gmpnum_result; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_LONG(nth) + ZEND_PARSE_PARAMETERS_END(); if (nth <= 0) { zend_argument_value_error(2, "must be greater than 0"); @@ -1536,9 +1556,10 @@ ZEND_FUNCTION(gmp_rootrem) gmp_temp_t temp_a; zval result1, result2; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_LONG(nth) + ZEND_PARSE_PARAMETERS_END(); if (nth <= 0) { zend_argument_value_error(2, "must be greater than or equal to 1"); @@ -1581,9 +1602,9 @@ ZEND_FUNCTION(gmp_perfect_square) mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); @@ -1599,9 +1620,9 @@ ZEND_FUNCTION(gmp_perfect_power) mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); @@ -1618,9 +1639,11 @@ ZEND_FUNCTION(gmp_prob_prime) zend_long reps = 10; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &reps) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(gmpnumber_arg) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(reps) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a, 1); @@ -1651,9 +1674,10 @@ ZEND_FUNCTION(gmp_gcdext) gmp_temp_t temp_a, temp_b; zval result_g, result_s, result_t; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); @@ -1681,9 +1705,10 @@ ZEND_FUNCTION(gmp_invert) gmp_temp_t temp_a, temp_b; int res; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) == 0) { zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); @@ -1718,9 +1743,10 @@ ZEND_FUNCTION(gmp_jacobi) mpz_ptr gmpnum_a, gmpnum_b; gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); @@ -1739,9 +1765,10 @@ ZEND_FUNCTION(gmp_legendre) mpz_ptr gmpnum_a, gmpnum_b; gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); @@ -1762,9 +1789,10 @@ ZEND_FUNCTION(gmp_kronecker) bool use_a_si = 0, use_b_si = 0; int result; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE_P(a_arg) == IS_LONG && Z_TYPE_P(b_arg) != IS_LONG) { use_a_si = 1; @@ -1801,9 +1829,10 @@ ZEND_FUNCTION(gmp_cmp) { zval *a_arg, *b_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + ZEND_PARSE_PARAMETERS_END(); gmp_cmp(return_value, a_arg, b_arg, /* is_operator */ false); } @@ -1817,9 +1846,9 @@ ZEND_FUNCTION(gmp_sign) mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); @@ -1850,9 +1879,9 @@ ZEND_FUNCTION(gmp_random_seed) zval *seed; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &seed) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(seed) + ZEND_PARSE_PARAMETERS_END(); gmp_init_random(); @@ -1907,9 +1936,10 @@ ZEND_FUNCTION(gmp_random_range) mpz_t gmpnum_range; gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &min_arg, &max_arg) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(min_arg) + Z_PARAM_ZVAL(max_arg) + ZEND_PARSE_PARAMETERS_END(); gmp_init_random(); @@ -2061,9 +2091,10 @@ ZEND_FUNCTION(gmp_testbit) mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &index) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_LONG(index) + ZEND_PARSE_PARAMETERS_END(); if (index < 0) { zend_argument_value_error(2, "must be greater than or equal to 0"); @@ -2090,9 +2121,10 @@ ZEND_FUNCTION(gmp_hamdist) mpz_ptr gmpnum_a, gmpnum_b; gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_ZVAL(b_arg) + ZEND_PARSE_PARAMETERS_END(); FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); @@ -2112,9 +2144,10 @@ ZEND_FUNCTION(gmp_scan0) gmp_temp_t temp_a; zend_long start; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_LONG(start) + ZEND_PARSE_PARAMETERS_END(); if (start < 0) { zend_argument_value_error(2, "must be greater than or equal to 0"); @@ -2136,9 +2169,10 @@ ZEND_FUNCTION(gmp_scan1) gmp_temp_t temp_a; zend_long start; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(a_arg) + Z_PARAM_LONG(start) + ZEND_PARSE_PARAMETERS_END(); if (start < 0) { zend_argument_value_error(2, "must be greater than or equal to 0"); From 4181a1e4ea828e445a4d10a9ac8da7d276fef0a3 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 22:16:41 +0000 Subject: [PATCH 03/22] Inline gmp_unary_opl() as it was only used once That use being gmp_popcount() --- ext/gmp/gmp.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 84bd75d729107..c5e49aecbd800 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -194,7 +194,6 @@ static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operat * include parameter parsing. */ typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); -typedef mp_bitcnt_t (*gmp_unary_opl_t)(mpz_srcptr); typedef void (*gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong); @@ -241,7 +240,6 @@ static void gmp_mpz_gcd_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { /* Unary operations */ #define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) -#define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) static void gmp_free_object_storage(zend_object *obj) /* {{{ */ { @@ -928,23 +926,6 @@ static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gm } /* }}} */ -/* {{{ _gmp_unary_opl */ -static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op) -{ - zval *a_arg; - mpz_ptr gmpnum_a; - gmp_temp_t temp_a; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) - ZEND_PARSE_PARAMETERS_END(); - - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - RETVAL_LONG(gmp_op(gmpnum_a)); - FREE_GMP_TEMP(temp_a); -} -/* }}} */ - static bool gmp_verify_base(zend_long base, uint32_t arg_num) { if (base && (base < 2 || base > GMP_MAX_BASE)) { @@ -1841,7 +1822,6 @@ ZEND_FUNCTION(gmp_cmp) /* {{{ Gets the sign of the number */ ZEND_FUNCTION(gmp_sign) { - /* Can't use gmp_unary_opl here, because mpz_sgn is a macro */ zval *a_arg; mpz_ptr gmpnum_a; gmp_temp_t temp_a; @@ -2110,7 +2090,17 @@ ZEND_FUNCTION(gmp_testbit) /* {{{ Calculates the population count of a */ ZEND_FUNCTION(gmp_popcount) { - gmp_unary_opl(mpz_popcount); + zval *a_arg; + mpz_ptr gmpnum_a; + gmp_temp_t temp_a; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(a_arg) + ZEND_PARSE_PARAMETERS_END(); + + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); + RETVAL_LONG(mpz_popcount(gmpnum_a)); + FREE_GMP_TEMP(temp_a); } /* }}} */ From 282142f3e1e91ad13932e857878d67c8a30b4240 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 3 Nov 2024 13:10:24 +0000 Subject: [PATCH 04/22] ext/gmp: Create custom Fast ZPP specifier to parse into mpz_ptr We define module globals to be used with ZPP, which also avoids excessive initializing and clearing of variables, something recommended by the GMP documentation. --- ext/gmp/gmp.c | 54 +++++++++++++++++++++++++++++++++++++++++++---- ext/gmp/php_gmp.h | 1 + 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index c5e49aecbd800..2349c545d87c0 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -55,6 +55,7 @@ ZEND_DECLARE_MODULE_GLOBALS(gmp) static ZEND_GINIT_FUNCTION(gmp); +static ZEND_GSHUTDOWN_FUNCTION(gmp); /* {{{ gmp_module_entry */ zend_module_entry gmp_module_entry = { @@ -69,7 +70,7 @@ zend_module_entry gmp_module_entry = { PHP_GMP_VERSION, ZEND_MODULE_GLOBALS(gmp), ZEND_GINIT(gmp), - NULL, + ZEND_GSHUTDOWN(gmp), NULL, STANDARD_MODULE_PROPERTIES_EX }; @@ -179,14 +180,49 @@ if (IS_GMP(zval)) { \ gmpnumber = temp.num; \ } -#define INIT_GMP_RETVAL(gmpnumber) \ - gmp_create(return_value, &gmpnumber) - static void gmp_strval(zval *result, mpz_t gmpnum, int base); static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos); static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos); static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator); +static bool gmp_zend_parse_arg_into_mpz( + zval *arg, + mpz_ptr *destination_mpz_ptr, + uint32_t arg_num +) { + if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { + if (EXPECTED(instanceof_function(Z_OBJCE_P(arg), gmp_ce))) { + *destination_mpz_ptr = GET_GMP_FROM_ZVAL(arg); + return true; + } + return false; + } + + *destination_mpz_ptr = GMPG(zpp_arg[arg_num-1]); + if (Z_TYPE_P(arg) == IS_STRING) { + return convert_zstr_to_gmp(*destination_mpz_ptr, Z_STR_P(arg), /* base */ 0, arg_num) != FAILURE; + } + + if (Z_TYPE_P(arg) == IS_LONG) { + mpz_set_si(*destination_mpz_ptr, Z_LVAL_P(arg)); + return true; + } + return false; +} + +#define GMP_Z_PARAM_INTO_MPZ_PTR(destination_mpz_ptr) \ + Z_PARAM_PROLOGUE(0, 0); \ + if (UNEXPECTED(!gmp_zend_parse_arg_into_mpz(_arg, &destination_mpz_ptr, _i))) { \ + _error_code = ZPP_ERROR_FAILURE; \ + if (!EG(exception)) { \ + zend_argument_type_error(_i, "must be of type GMP|string|int, %s given", zend_zval_value_name(_arg)); \ + } \ + break; \ + } + +#define INIT_GMP_RETVAL(gmpnumber) \ + gmp_create(return_value, &gmpnumber) + /* * The gmp_*_op functions provide an implementation for several common types * of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually @@ -591,9 +627,19 @@ static ZEND_GINIT_FUNCTION(gmp) ZEND_TSRMLS_CACHE_UPDATE(); #endif gmp_globals->rand_initialized = 0; + mpz_init(gmp_globals->zpp_arg[0]); + mpz_init(gmp_globals->zpp_arg[1]); + mpz_init(gmp_globals->zpp_arg[2]); } /* }}} */ +static ZEND_GSHUTDOWN_FUNCTION(gmp) +{ + mpz_clear(gmp_globals->zpp_arg[0]); + mpz_clear(gmp_globals->zpp_arg[1]); + mpz_clear(gmp_globals->zpp_arg[2]); +} + /* {{{ ZEND_MINIT_FUNCTION */ ZEND_MINIT_FUNCTION(gmp) { diff --git a/ext/gmp/php_gmp.h b/ext/gmp/php_gmp.h index 1c03a6ee8ceb2..597c7a9146c24 100644 --- a/ext/gmp/php_gmp.h +++ b/ext/gmp/php_gmp.h @@ -32,6 +32,7 @@ ZEND_MODULE_INFO_D(gmp); ZEND_BEGIN_MODULE_GLOBALS(gmp) bool rand_initialized; gmp_randstate_t rand_state; + mpz_t zpp_arg[3]; ZEND_END_MODULE_GLOBALS(gmp) #define GMPG(v) ZEND_MODULE_GLOBALS_ACCESSOR(gmp, v) From 54419721101bb81adac16ff0fbc478b1be741248 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 21:46:17 +0000 Subject: [PATCH 05/22] ext/gmp: Use new custom ZPP specifier --- ext/gmp/gmp.c | 335 ++++++---------------------------- ext/gmp/tests/gmp_strval.phpt | 2 +- 2 files changed, 61 insertions(+), 276 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 2349c545d87c0..fcba59ad0a003 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1092,15 +1092,13 @@ ZEND_FUNCTION(gmp_import) /* {{{ Exports a GMP number to a binary string */ ZEND_FUNCTION(gmp_export) { - zval *gmpnumber_arg; zend_long size = 1; zend_long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN; int order, endian; mpz_ptr gmpnumber; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 3) - Z_PARAM_ZVAL(gmpnumber_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnumber) Z_PARAM_OPTIONAL Z_PARAM_LONG(size) Z_PARAM_LONG(options) @@ -1110,8 +1108,6 @@ ZEND_FUNCTION(gmp_export) RETURN_THROWS(); } - FETCH_GMP_ZVAL(gmpnumber, gmpnumber_arg, temp_a, 1); - if (mpz_sgn(gmpnumber) == 0) { RETVAL_EMPTY_STRING(); } else { @@ -1130,38 +1126,30 @@ ZEND_FUNCTION(gmp_export) RETVAL_NEW_STR(out_string); } - - FREE_GMP_TEMP(temp_a); } /* }}} */ /* {{{ Gets signed long value of GMP number */ ZEND_FUNCTION(gmp_intval) { - zval *gmpnumber_arg; mpz_ptr gmpnum; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(gmpnumber_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a, 1); RETVAL_LONG(mpz_get_si(gmpnum)); - FREE_GMP_TEMP(temp_a); } /* }}} */ /* {{{ Gets string representation of GMP number */ ZEND_FUNCTION(gmp_strval) { - zval *gmpnumber_arg; zend_long base = 10; mpz_ptr gmpnum; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ZVAL(gmpnumber_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum) Z_PARAM_OPTIONAL Z_PARAM_LONG(base) ZEND_PARSE_PARAMETERS_END(); @@ -1173,11 +1161,7 @@ ZEND_FUNCTION(gmp_strval) RETURN_THROWS(); } - FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a, 1); - gmp_strval(return_value, gmpnum, (int)base); - - FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -1363,12 +1347,12 @@ ZEND_FUNCTION(gmp_fact) /* {{{ Calculates binomial coefficient */ ZEND_FUNCTION(gmp_binomial) { - zval *n_arg; + mpz_ptr gmpnum_n; zend_long k; mpz_ptr gmpnum_result; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(n_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_n) Z_PARAM_LONG(k) ZEND_PARSE_PARAMETERS_END(); @@ -1378,28 +1362,19 @@ ZEND_FUNCTION(gmp_binomial) } INIT_GMP_RETVAL(gmpnum_result); - if (Z_TYPE_P(n_arg) == IS_LONG && Z_LVAL_P(n_arg) >= 0) { - mpz_bin_uiui(gmpnum_result, (gmp_ulong) Z_LVAL_P(n_arg), (gmp_ulong) k); - } else { - mpz_ptr gmpnum_n; - gmp_temp_t temp_n; - FETCH_GMP_ZVAL(gmpnum_n, n_arg, temp_n, 1); - mpz_bin_ui(gmpnum_result, gmpnum_n, (gmp_ulong) k); - FREE_GMP_TEMP(temp_n); - } + mpz_bin_ui(gmpnum_result, gmpnum_n, (gmp_ulong) k); } /* }}} */ /* {{{ Raise base to power exp */ ZEND_FUNCTION(gmp_pow) { - zval *base_arg; mpz_ptr gmpnum_result; - gmp_temp_t temp_base; + mpz_ptr gmpnum_base; zend_long exp; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(base_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_base) Z_PARAM_LONG(exp) ZEND_PARSE_PARAMETERS_END(); @@ -1410,123 +1385,73 @@ ZEND_FUNCTION(gmp_pow) double powmax = log((double)ZEND_LONG_MAX); - if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) { - INIT_GMP_RETVAL(gmpnum_result); - if ((log(Z_LVAL_P(base_arg)) * exp) > powmax) { - zend_value_error("base and exponent overflow"); - RETURN_THROWS(); - } - mpz_ui_pow_ui(gmpnum_result, Z_LVAL_P(base_arg), exp); - } else { - mpz_ptr gmpnum_base; - zend_ulong gmpnum; - FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base, 1); - INIT_GMP_RETVAL(gmpnum_result); - gmpnum = mpz_get_ui(gmpnum_base); - if ((log(gmpnum) * exp) > powmax) { - FREE_GMP_TEMP(temp_base); - zend_value_error("base and exponent overflow"); - RETURN_THROWS(); - } - mpz_pow_ui(gmpnum_result, gmpnum_base, exp); - FREE_GMP_TEMP(temp_base); + INIT_GMP_RETVAL(gmpnum_result); + zend_ulong gmpnum = mpz_get_ui(gmpnum_base); + if ((log(gmpnum) * exp) > powmax) { + zend_value_error("base and exponent overflow"); + RETURN_THROWS(); } + mpz_pow_ui(gmpnum_result, gmpnum_base, exp); } /* }}} */ /* {{{ Raise base to power exp and take result modulo mod */ ZEND_FUNCTION(gmp_powm) { - zval *base_arg, *exp_arg, *mod_arg; mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result; - int use_ui = 0; - gmp_temp_t temp_base, temp_exp, temp_mod; ZEND_PARSE_PARAMETERS_START(3, 3) - Z_PARAM_ZVAL(base_arg) - Z_PARAM_ZVAL(exp_arg) - Z_PARAM_ZVAL(mod_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_base) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_exp) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_mod) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base, 1); - - if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) { - use_ui = 1; - temp_exp.is_used = 0; - } else { - FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base, 2); - if (mpz_sgn(gmpnum_exp) < 0) { - zend_argument_value_error(2, "must be greater than or equal to 0"); - FREE_GMP_TEMP(temp_base); - FREE_GMP_TEMP(temp_exp); - RETURN_THROWS(); - } + if (mpz_sgn(gmpnum_exp) < 0) { + zend_argument_value_error(2, "must be greater than or equal to 0"); + RETURN_THROWS(); } - FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base, 3); if (!mpz_cmp_ui(gmpnum_mod, 0)) { zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero"); - FREE_GMP_TEMP(temp_base); - FREE_GMP_TEMP(temp_exp); - FREE_GMP_TEMP(temp_mod); RETURN_THROWS(); } INIT_GMP_RETVAL(gmpnum_result); - if (use_ui) { - mpz_powm_ui(gmpnum_result, gmpnum_base, (zend_ulong) Z_LVAL_P(exp_arg), gmpnum_mod); - } else { - mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod); - FREE_GMP_TEMP(temp_exp); - } - - FREE_GMP_TEMP(temp_base); - FREE_GMP_TEMP(temp_mod); + mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod); } /* }}} */ /* {{{ Takes integer part of square root of a */ ZEND_FUNCTION(gmp_sqrt) { - zval *a_arg; mpz_ptr gmpnum_a, gmpnum_result; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - if (mpz_sgn(gmpnum_a) < 0) { zend_argument_value_error(1, "must be greater than or equal to 0"); - FREE_GMP_TEMP(temp_a); RETURN_THROWS(); } INIT_GMP_RETVAL(gmpnum_result); mpz_sqrt(gmpnum_result, gmpnum_a); - FREE_GMP_TEMP(temp_a); } /* }}} */ /* {{{ Square root with remainder */ ZEND_FUNCTION(gmp_sqrtrem) { - zval *a_arg; mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2; - gmp_temp_t temp_a; zval result1, result2; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - if (mpz_sgn(gmpnum_a) < 0) { zend_argument_value_error(1, "must be greater than or equal to 0"); - FREE_GMP_TEMP(temp_a); RETURN_THROWS(); } @@ -1538,20 +1463,17 @@ ZEND_FUNCTION(gmp_sqrtrem) add_next_index_zval(return_value, &result2); mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a); - FREE_GMP_TEMP(temp_a); } /* }}} */ /* {{{ Takes integer part of nth root */ ZEND_FUNCTION(gmp_root) { - zval *a_arg; zend_long nth; mpz_ptr gmpnum_a, gmpnum_result; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) Z_PARAM_LONG(nth) ZEND_PARSE_PARAMETERS_END(); @@ -1560,31 +1482,25 @@ ZEND_FUNCTION(gmp_root) RETURN_THROWS(); } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) { zend_argument_value_error(2, "must be odd if argument #1 ($a) is negative"); - FREE_GMP_TEMP(temp_a); RETURN_THROWS(); } INIT_GMP_RETVAL(gmpnum_result); mpz_root(gmpnum_result, gmpnum_a, (gmp_ulong) nth); - FREE_GMP_TEMP(temp_a); } /* }}} */ /* {{{ Calculates integer part of nth root and remainder */ ZEND_FUNCTION(gmp_rootrem) { - zval *a_arg; zend_long nth; mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2; - gmp_temp_t temp_a; zval result1, result2; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) Z_PARAM_LONG(nth) ZEND_PARSE_PARAMETERS_END(); @@ -1593,11 +1509,8 @@ ZEND_FUNCTION(gmp_rootrem) RETURN_THROWS(); } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) { zend_argument_value_error(2, "must be odd if argument #1 ($a) is negative"); - FREE_GMP_TEMP(temp_a); RETURN_THROWS(); } @@ -1617,65 +1530,48 @@ ZEND_FUNCTION(gmp_rootrem) mpz_pow_ui(gmpnum_result2, gmpnum_result1, (gmp_ulong) nth); mpz_sub(gmpnum_result2, gmpnum_a, gmpnum_result2); #endif - - FREE_GMP_TEMP(temp_a); } /* }}} */ /* {{{ Checks if a is an exact square */ ZEND_FUNCTION(gmp_perfect_square) { - zval *a_arg; mpz_ptr gmpnum_a; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - - RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0)); - FREE_GMP_TEMP(temp_a); + RETURN_BOOL((mpz_perfect_square_p(gmpnum_a) != 0)); } /* }}} */ /* {{{ Checks if a is a perfect power */ ZEND_FUNCTION(gmp_perfect_power) { - zval *a_arg; mpz_ptr gmpnum_a; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - - RETVAL_BOOL((mpz_perfect_power_p(gmpnum_a) != 0)); - FREE_GMP_TEMP(temp_a); + RETURN_BOOL((mpz_perfect_power_p(gmpnum_a) != 0)); } /* }}} */ /* {{{ Checks if a is "probably prime" */ ZEND_FUNCTION(gmp_prob_prime) { - zval *gmpnumber_arg; mpz_ptr gmpnum_a; zend_long reps = 10; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ZVAL(gmpnumber_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) Z_PARAM_OPTIONAL Z_PARAM_LONG(reps) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a, 1); - - RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, (int)reps)); - FREE_GMP_TEMP(temp_a); + RETURN_LONG(mpz_probab_prime_p(gmpnum_a, (int)reps)); } /* }}} */ @@ -1696,19 +1592,14 @@ ZEND_FUNCTION(gmp_lcm) /* {{{ Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */ ZEND_FUNCTION(gmp_gcdext) { - zval *a_arg, *b_arg; mpz_ptr gmpnum_a, gmpnum_b, gmpnum_t, gmpnum_s, gmpnum_g; - gmp_temp_t temp_a, temp_b; zval result_g, result_s, result_t; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); - gmp_create(&result_g, &gmpnum_g); gmp_create(&result_s, &gmpnum_s); gmp_create(&result_t, &gmpnum_t); @@ -1719,43 +1610,27 @@ ZEND_FUNCTION(gmp_gcdext) add_assoc_zval(return_value, "t", &result_t); mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b); - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); } /* }}} */ /* {{{ Computes the inverse of a modulo b */ ZEND_FUNCTION(gmp_invert) { - zval *a_arg, *b_arg; mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; - gmp_temp_t temp_a, temp_b; int res; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) == 0) { - zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); - RETURN_THROWS(); - } - - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); - if (!mpz_cmp_ui(gmpnum_b, 0)) { zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); RETURN_THROWS(); } INIT_GMP_RETVAL(gmpnum_result); res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b); - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); if (!res) { zval_ptr_dtor(return_value); RETURN_FALSE; @@ -1766,88 +1641,42 @@ ZEND_FUNCTION(gmp_invert) /* {{{ Computes Jacobi symbol */ ZEND_FUNCTION(gmp_jacobi) { - zval *a_arg, *b_arg; mpz_ptr gmpnum_a, gmpnum_b; - gmp_temp_t temp_a, temp_b; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); - - RETVAL_LONG(mpz_jacobi(gmpnum_a, gmpnum_b)); - - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); + RETURN_LONG(mpz_jacobi(gmpnum_a, gmpnum_b)); } /* }}} */ /* {{{ Computes Legendre symbol */ ZEND_FUNCTION(gmp_legendre) { - zval *a_arg, *b_arg; mpz_ptr gmpnum_a, gmpnum_b; - gmp_temp_t temp_a, temp_b; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); - - RETVAL_LONG(mpz_legendre(gmpnum_a, gmpnum_b)); - - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); + RETURN_LONG(mpz_legendre(gmpnum_a, gmpnum_b)); } /* }}} */ /* {{{ Computes the Kronecker symbol */ ZEND_FUNCTION(gmp_kronecker) { - zval *a_arg, *b_arg; mpz_ptr gmpnum_a, gmpnum_b; - gmp_temp_t temp_a, temp_b; - bool use_a_si = 0, use_b_si = 0; - int result; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(a_arg) == IS_LONG && Z_TYPE_P(b_arg) != IS_LONG) { - use_a_si = 1; - temp_a.is_used = 0; - } else { - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - } - - if (Z_TYPE_P(b_arg) == IS_LONG) { - use_b_si = 1; - temp_b.is_used = 0; - } else { - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); - } - - if (use_a_si) { - ZEND_ASSERT(use_b_si == 0); - result = mpz_si_kronecker((gmp_long) Z_LVAL_P(a_arg), gmpnum_b); - } else if (use_b_si) { - result = mpz_kronecker_si(gmpnum_a, (gmp_long) Z_LVAL_P(b_arg)); - } else { - result = mpz_kronecker(gmpnum_a, gmpnum_b); - } - - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); - - RETURN_LONG(result); + RETURN_LONG(mpz_kronecker(gmpnum_a, gmpnum_b)); } /* }}} */ @@ -1868,18 +1697,13 @@ ZEND_FUNCTION(gmp_cmp) /* {{{ Gets the sign of the number */ ZEND_FUNCTION(gmp_sign) { - zval *a_arg; mpz_ptr gmpnum_a; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - - RETVAL_LONG(mpz_sgn(gmpnum_a)); - FREE_GMP_TEMP(temp_a); + RETURN_LONG(mpz_sgn(gmpnum_a)); } /* }}} */ @@ -1902,27 +1726,14 @@ static void gmp_init_random(void) /* {{{ Seed the RNG */ ZEND_FUNCTION(gmp_random_seed) { - zval *seed; - gmp_temp_t temp_a; + mpz_ptr gmpnum_seed; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(seed) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_seed) ZEND_PARSE_PARAMETERS_END(); gmp_init_random(); - - if (Z_TYPE_P(seed) == IS_LONG && Z_LVAL_P(seed) >= 0) { - gmp_randseed_ui(GMPG(rand_state), Z_LVAL_P(seed)); - } - else { - mpz_ptr gmpnum_seed; - - FETCH_GMP_ZVAL(gmpnum_seed, seed, temp_a, 1); - - gmp_randseed(GMPG(rand_state), gmpnum_seed); - - FREE_GMP_TEMP(temp_a); - } + gmp_randseed(GMPG(rand_state), gmpnum_seed); } /* }}} */ @@ -2112,13 +1923,11 @@ ZEND_FUNCTION(gmp_clrbit) /* {{{ Tests if bit is set in a */ ZEND_FUNCTION(gmp_testbit) { - zval *a_arg; zend_long index; mpz_ptr gmpnum_a; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) Z_PARAM_LONG(index) ZEND_PARSE_PARAMETERS_END(); @@ -2127,61 +1936,45 @@ ZEND_FUNCTION(gmp_testbit) RETURN_THROWS(); } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - RETVAL_BOOL(mpz_tstbit(gmpnum_a, index)); - FREE_GMP_TEMP(temp_a); + RETURN_BOOL(mpz_tstbit(gmpnum_a, index)); } /* }}} */ /* {{{ Calculates the population count of a */ ZEND_FUNCTION(gmp_popcount) { - zval *a_arg; mpz_ptr gmpnum_a; - gmp_temp_t temp_a; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - RETVAL_LONG(mpz_popcount(gmpnum_a)); - FREE_GMP_TEMP(temp_a); + RETURN_LONG(mpz_popcount(gmpnum_a)); } /* }}} */ /* {{{ Calculates hamming distance between a and b */ ZEND_FUNCTION(gmp_hamdist) { - zval *a_arg, *b_arg; mpz_ptr gmpnum_a, gmpnum_b; - gmp_temp_t temp_a, temp_b; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); - - RETVAL_LONG(mpz_hamdist(gmpnum_a, gmpnum_b)); - - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); + RETURN_LONG(mpz_hamdist(gmpnum_a, gmpnum_b)); } /* }}} */ /* {{{ Finds first zero bit */ ZEND_FUNCTION(gmp_scan0) { - zval *a_arg; mpz_ptr gmpnum_a; - gmp_temp_t temp_a; zend_long start; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) Z_PARAM_LONG(start) ZEND_PARSE_PARAMETERS_END(); @@ -2190,23 +1983,18 @@ ZEND_FUNCTION(gmp_scan0) RETURN_THROWS(); } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - - RETVAL_LONG(mpz_scan0(gmpnum_a, start)); - FREE_GMP_TEMP(temp_a); + RETURN_LONG(mpz_scan0(gmpnum_a, start)); } /* }}} */ /* {{{ Finds first non-zero bit */ ZEND_FUNCTION(gmp_scan1) { - zval *a_arg; mpz_ptr gmpnum_a; - gmp_temp_t temp_a; zend_long start; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) Z_PARAM_LONG(start) ZEND_PARSE_PARAMETERS_END(); @@ -2215,10 +2003,7 @@ ZEND_FUNCTION(gmp_scan1) RETURN_THROWS(); } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - - RETVAL_LONG(mpz_scan1(gmpnum_a, start)); - FREE_GMP_TEMP(temp_a); + RETURN_LONG(mpz_scan1(gmpnum_a, start)); } /* }}} */ diff --git a/ext/gmp/tests/gmp_strval.phpt b/ext/gmp/tests/gmp_strval.phpt index a4d0a9b149b37..1221d04b3b1d4 100644 --- a/ext/gmp/tests/gmp_strval.phpt +++ b/ext/gmp/tests/gmp_strval.phpt @@ -66,7 +66,7 @@ echo "Done\n"; ?> --EXPECT-- gmp_strval(): Argument #1 ($num) is not an integer string -gmp_strval(): Argument #2 ($base) must be between 2 and 62, or -2 and -36 +gmp_strval(): Argument #1 ($num) is not an integer string gmp_strval(): Argument #1 ($num) must be of type GMP|string|int, resource given string(7) "9765456" gmp_strval(): Argument #2 ($base) must be between 2 and 62, or -2 and -36 From 76033e1141c954ac4cc6ec85b4ad97d026d23330 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 22:41:58 +0000 Subject: [PATCH 06/22] ext/gmp: Refactor generation of unary GMP functions --- ext/gmp/gmp.c | 57 +++++++++++++++------------------------------------ 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index fcba59ad0a003..230c1b6dfeb30 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -231,6 +231,16 @@ static bool gmp_zend_parse_arg_into_mpz( */ typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); +#define GMP_UNARY_OP_FUNCTION(name) \ + ZEND_FUNCTION(gmp_##name) { \ + mpz_ptr gmpnum_a, gmpnum_result; \ + ZEND_PARSE_PARAMETERS_START(1, 1) \ + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) \ + ZEND_PARSE_PARAMETERS_END(); \ + INIT_GMP_RETVAL(gmpnum_result); \ + mpz_##name(gmpnum_result, gmpnum_a); \ + } + typedef void (*gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong); typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); @@ -274,9 +284,6 @@ static void gmp_mpz_gcd_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { #define gmp_binary_ui_op_no_zero(op, uop) \ _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1) -/* Unary operations */ -#define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) - static void gmp_free_object_storage(zend_object *obj) /* {{{ */ { gmp_object *intern = GET_GMP_OBJECT_FROM_OBJ(obj); @@ -959,19 +966,6 @@ static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_ } /* }}} */ -/* {{{ _gmp_unary_op */ -static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op) -{ - zval *a_arg; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) - ZEND_PARSE_PARAMETERS_END(); - - gmp_zval_unary_op(return_value, a_arg, gmp_op); -} -/* }}} */ - static bool gmp_verify_base(zend_long base, uint32_t arg_num) { if (base && (base < 2 || base > GMP_MAX_BASE)) { @@ -1298,18 +1292,13 @@ ZEND_FUNCTION(gmp_divexact) /* }}} */ /* {{{ Negates a number */ -ZEND_FUNCTION(gmp_neg) -{ - gmp_unary_op(mpz_neg); -} -/* }}} */ - +GMP_UNARY_OP_FUNCTION(neg); /* {{{ Calculates absolute value */ -ZEND_FUNCTION(gmp_abs) -{ - gmp_unary_op(mpz_abs); -} -/* }}} */ +GMP_UNARY_OP_FUNCTION(abs); +/* {{{ Calculates one's complement of a */ +GMP_UNARY_OP_FUNCTION(com); +/* {{{ Finds next prime of a */ +GMP_UNARY_OP_FUNCTION(nextprime); /* {{{ Calculates factorial function */ ZEND_FUNCTION(gmp_fact) @@ -1847,20 +1836,6 @@ ZEND_FUNCTION(gmp_or) } /* }}} */ -/* {{{ Calculates one's complement of a */ -ZEND_FUNCTION(gmp_com) -{ - gmp_unary_op(mpz_com); -} -/* }}} */ - -/* {{{ Finds next prime of a */ -ZEND_FUNCTION(gmp_nextprime) -{ - gmp_unary_op(mpz_nextprime); -} -/* }}} */ - /* {{{ Calculates logical exclusive OR of a and b */ ZEND_FUNCTION(gmp_xor) { From 602dd27acacf19cc4fc79ea9d723eaa470520049 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 23:02:58 +0000 Subject: [PATCH 07/22] ext/gmp: Refactor generation of some binary GMP functions --- ext/gmp/gmp.c | 95 ++++++++++++++++++--------------------------------- 1 file changed, 34 insertions(+), 61 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 230c1b6dfeb30..b5f2b787caec6 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -231,6 +231,9 @@ static bool gmp_zend_parse_arg_into_mpz( */ typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); +#define GMP_FN_NAME(name) gmp_##name +#define GMP_MPZ_FN_NAME(name) mpz_##name + #define GMP_UNARY_OP_FUNCTION(name) \ ZEND_FUNCTION(gmp_##name) { \ mpz_ptr gmpnum_a, gmpnum_result; \ @@ -238,9 +241,22 @@ typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) \ ZEND_PARSE_PARAMETERS_END(); \ INIT_GMP_RETVAL(gmpnum_result); \ - mpz_##name(gmpnum_result, gmpnum_a); \ + GMP_MPZ_FN_NAME(name)(gmpnum_result, gmpnum_a); \ + } + +#define GMP_BINARY_OP_FUNCTION_EX(gmp_name, mpz_name) \ + ZEND_FUNCTION(gmp_name) { \ + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; \ + ZEND_PARSE_PARAMETERS_START(2, 2) \ + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) \ + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) \ + ZEND_PARSE_PARAMETERS_END(); \ + INIT_GMP_RETVAL(gmpnum_result); \ + mpz_name(gmpnum_result, gmpnum_a, gmpnum_b); \ } +#define GMP_BINARY_OP_FUNCTION(name) GMP_BINARY_OP_FUNCTION_EX(GMP_FN_NAME(name), GMP_MPZ_FN_NAME(name)) + typedef void (*gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong); typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); @@ -274,12 +290,8 @@ static void gmp_mpz_cdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { static void gmp_mpz_mod_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { mpz_mod_ui(a, b, c); } -static void gmp_mpz_gcd_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { - mpz_gcd_ui(a, b, c); -} /* Binary operations */ -#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0) #define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0) #define gmp_binary_ui_op_no_zero(op, uop) \ _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1) @@ -1159,27 +1171,6 @@ ZEND_FUNCTION(gmp_strval) } /* }}} */ -/* {{{ Add a and b */ -ZEND_FUNCTION(gmp_add) -{ - gmp_binary_ui_op(mpz_add, mpz_add_ui); -} -/* }}} */ - -/* {{{ Subtract b from a */ -ZEND_FUNCTION(gmp_sub) -{ - gmp_binary_ui_op(mpz_sub, mpz_sub_ui); -} -/* }}} */ - -/* {{{ Multiply a and b */ -ZEND_FUNCTION(gmp_mul) -{ - gmp_binary_ui_op(mpz_mul, mpz_mul_ui); -} -/* }}} */ - /* {{{ Divide a by b, returns quotient and reminder */ ZEND_FUNCTION(gmp_div_qr) { @@ -1300,6 +1291,23 @@ GMP_UNARY_OP_FUNCTION(com); /* {{{ Finds next prime of a */ GMP_UNARY_OP_FUNCTION(nextprime); +/* Add a and b */ +GMP_BINARY_OP_FUNCTION(add); +/* Subtract b from a */ +GMP_BINARY_OP_FUNCTION(sub); +/* Multiply a and b */ +GMP_BINARY_OP_FUNCTION(mul); +/* Computes greatest common denominator (gcd) of a and b */ +GMP_BINARY_OP_FUNCTION(gcd); +/* Computes least common multiple (lcm) of a and b */ +GMP_BINARY_OP_FUNCTION(lcm); +/* {Calculates logical AND of a and b */ +GMP_BINARY_OP_FUNCTION(and); +/* Calculates logical exclusive OR of a and b */ +GMP_BINARY_OP_FUNCTION(xor); +/* Calculates logical OR of a and b */ +GMP_BINARY_OP_FUNCTION_EX(gmp_or, mpz_ior); + /* {{{ Calculates factorial function */ ZEND_FUNCTION(gmp_fact) { @@ -1564,20 +1572,6 @@ ZEND_FUNCTION(gmp_prob_prime) } /* }}} */ -/* {{{ Computes greatest common denominator (gcd) of a and b */ -ZEND_FUNCTION(gmp_gcd) -{ - gmp_binary_ui_op(mpz_gcd, gmp_mpz_gcd_ui); -} -/* }}} */ - -/* {{{ Computes least common multiple (lcm) of a and b */ -ZEND_FUNCTION(gmp_lcm) -{ - gmp_binary_ui_op(mpz_lcm, mpz_lcm_ui); -} -/* }}} */ - /* {{{ Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */ ZEND_FUNCTION(gmp_gcdext) { @@ -1822,27 +1816,6 @@ ZEND_FUNCTION(gmp_random_range) } /* }}} */ -/* {{{ Calculates logical AND of a and b */ -ZEND_FUNCTION(gmp_and) -{ - gmp_binary_op(mpz_and); -} -/* }}} */ - -/* {{{ Calculates logical OR of a and b */ -ZEND_FUNCTION(gmp_or) -{ - gmp_binary_op(mpz_ior); -} -/* }}} */ - -/* {{{ Calculates logical exclusive OR of a and b */ -ZEND_FUNCTION(gmp_xor) -{ - gmp_binary_op(mpz_xor); -} -/* }}} */ - /* {{{ Sets or clear bit in a */ ZEND_FUNCTION(gmp_setbit) { From de20a29fa1e0cbd3d9c40e298b1d400c703a1195 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 23:09:54 +0000 Subject: [PATCH 08/22] ext/gmp: Use new specifier for gmp_cmp() It seems that this also now normalizes the return value --- ext/gmp/gmp.c | 8 ++++---- ext/gmp/tests/gmp_cmp.phpt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index b5f2b787caec6..d5ef3dc4d98c4 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1666,14 +1666,14 @@ ZEND_FUNCTION(gmp_kronecker) /* {{{ Compares two numbers */ ZEND_FUNCTION(gmp_cmp) { - zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - gmp_cmp(return_value, a_arg, b_arg, /* is_operator */ false); + RETURN_LONG(mpz_cmp(gmpnum_a, gmpnum_b)); } /* }}} */ diff --git a/ext/gmp/tests/gmp_cmp.phpt b/ext/gmp/tests/gmp_cmp.phpt index f84bcfe9f5218..3154b68064ade 100644 --- a/ext/gmp/tests/gmp_cmp.phpt +++ b/ext/gmp/tests/gmp_cmp.phpt @@ -26,7 +26,7 @@ try { echo "Done\n"; ?> --EXPECT-- -int(2) +int(1) int(0) int(-1) int(0) From 4278aee720f715e131fe64074ea9e6d9d2371b1d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 23:19:20 +0000 Subject: [PATCH 09/22] ext/gmp: Refactor gmp_random_range() to use new ZPP specifier --- ext/gmp/gmp.c | 69 +++++++++++---------------------------------------- 1 file changed, 14 insertions(+), 55 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index d5ef3dc4d98c4..3a8c6a292052b 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1751,68 +1751,27 @@ ZEND_FUNCTION(gmp_random_bits) /* {{{ Gets a random number in the range min to max */ ZEND_FUNCTION(gmp_random_range) { - zval *min_arg, *max_arg; - mpz_ptr gmpnum_max, gmpnum_result; - mpz_t gmpnum_range; - gmp_temp_t temp_a, temp_b; + mpz_ptr gmpnum_min, gmpnum_max, gmpnum_result; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(min_arg) - Z_PARAM_ZVAL(max_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_min) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_max) ZEND_PARSE_PARAMETERS_END(); gmp_init_random(); + if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) { + zend_argument_value_error(1, "must be less than argument #2 ($maximum)"); + RETURN_THROWS(); + } - FETCH_GMP_ZVAL(gmpnum_max, max_arg, temp_a, 2); - - if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) { - if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) { - FREE_GMP_TEMP(temp_a); - zend_argument_value_error(1, "must be less than argument #2 ($maximum)"); - RETURN_THROWS(); - } - - INIT_GMP_RETVAL(gmpnum_result); - mpz_init(gmpnum_range); - - if (Z_LVAL_P(min_arg) != 0) { - mpz_sub_ui(gmpnum_range, gmpnum_max, Z_LVAL_P(min_arg) - 1); - } else { - mpz_add_ui(gmpnum_range, gmpnum_max, 1); - } - - mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range); - - if (Z_LVAL_P(min_arg) != 0) { - mpz_add_ui(gmpnum_result, gmpnum_result, Z_LVAL_P(min_arg)); - } - - mpz_clear(gmpnum_range); - FREE_GMP_TEMP(temp_a); - } else { - mpz_ptr gmpnum_min; - - FETCH_GMP_ZVAL_DEP(gmpnum_min, min_arg, temp_b, temp_a, 1); - - if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) { - FREE_GMP_TEMP(temp_b); - FREE_GMP_TEMP(temp_a); - zend_argument_value_error(1, "must be less than argument #2 ($maximum)"); - RETURN_THROWS(); - } - - INIT_GMP_RETVAL(gmpnum_result); - mpz_init(gmpnum_range); - - mpz_sub(gmpnum_range, gmpnum_max, gmpnum_min); - mpz_add_ui(gmpnum_range, gmpnum_range, 1); - mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range); - mpz_add(gmpnum_result, gmpnum_result, gmpnum_min); + INIT_GMP_RETVAL(gmpnum_result); - mpz_clear(gmpnum_range); - FREE_GMP_TEMP(temp_b); - FREE_GMP_TEMP(temp_a); - } + /* Use available 3rd ZPP slot for range num to prevent allocation and freeing */ + mpz_ptr gmpnum_range = GMPG(zpp_arg[2]); + mpz_sub(gmpnum_range, gmpnum_max, gmpnum_min); + mpz_add_ui(gmpnum_range, gmpnum_range, 1); + mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range); + mpz_add(gmpnum_result, gmpnum_result, gmpnum_min); } /* }}} */ From 69c835a08ac9b30709f68855f3f480f88c14ee41 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 23:37:21 +0000 Subject: [PATCH 10/22] ext/gmp: Refactor gmp_div_qr() to use new ZPP specifier --- ext/gmp/gmp.c | 99 +++++++++++------------------------ ext/gmp/tests/bug32773.phpt | 2 +- ext/gmp/tests/gmp_div_qr.phpt | 4 +- 3 files changed, 34 insertions(+), 71 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 3a8c6a292052b..d8c1291f939fc 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -266,7 +266,6 @@ typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); typedef gmp_ulong (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong); static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, bool check_b_zero, bool is_operator); -static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero); static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op); static void gmp_mpz_tdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { @@ -894,58 +893,6 @@ static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval * } /* }}} */ -/* {{{ gmp_zval_binary_ui_op2 - Execute GMP binary operation which returns 2 values. -*/ -static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero) -{ - mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2; - gmp_temp_t temp_a, temp_b; - zval result1, result2; - - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - - if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) { - gmpnum_b = NULL; - temp_b.is_used = 0; - } else { - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2); - } - - if (check_b_zero) { - int b_is_zero = 0; - if (!gmpnum_b) { - b_is_zero = (Z_LVAL_P(b_arg) == 0); - } else { - b_is_zero = !mpz_cmp_ui(gmpnum_b, 0); - } - - if (b_is_zero) { - zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); - RETURN_THROWS(); - } - } - - gmp_create(&result1, &gmpnum_result1); - gmp_create(&result2, &gmpnum_result2); - - array_init(return_value); - add_next_index_zval(return_value, &result1); - add_next_index_zval(return_value, &result2); - - if (!gmpnum_b) { - gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg)); - } else { - gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b); - } - - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); -} -/* }}} */ - /* {{{ _gmp_binary_ui_op */ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero) { @@ -1174,32 +1121,48 @@ ZEND_FUNCTION(gmp_strval) /* {{{ Divide a by b, returns quotient and reminder */ ZEND_FUNCTION(gmp_div_qr) { - zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b; zend_long round = GMP_ROUND_ZERO; ZEND_PARSE_PARAMETERS_START(2, 3) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) Z_PARAM_OPTIONAL Z_PARAM_LONG(round) ZEND_PARSE_PARAMETERS_END(); - switch (round) { - case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, mpz_tdiv_qr_ui, 1); - break; - case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, mpz_cdiv_qr_ui, 1); - break; - case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, mpz_fdiv_qr_ui, 1); - break; - default: + if (mpz_cmp_ui(gmpnum_b, 0) == 0) { + zend_argument_error(zend_ce_division_by_zero_error, 2, "Division by zero"); + RETURN_THROWS(); + } + + if (round != GMP_ROUND_ZERO && round != GMP_ROUND_PLUSINF && round != GMP_ROUND_MINUSINF) { zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF"); RETURN_THROWS(); } + + zval result1, result2; + mpz_ptr gmpnum_result1, gmpnum_result2; + gmp_create(&result1, &gmpnum_result1); + gmp_create(&result2, &gmpnum_result2); + + array_init(return_value); + add_next_index_zval(return_value, &result1); + add_next_index_zval(return_value, &result2); + + switch (round) { + case GMP_ROUND_ZERO: + mpz_tdiv_qr(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b); + break; + case GMP_ROUND_PLUSINF: + mpz_cdiv_qr(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b); + break; + case GMP_ROUND_MINUSINF: + mpz_fdiv_qr(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } } -/* }}} */ /* {{{ Divide a by b, returns reminder only */ ZEND_FUNCTION(gmp_div_r) diff --git a/ext/gmp/tests/bug32773.phpt b/ext/gmp/tests/bug32773.phpt index a0977a14ec076..6b60780a4d42c 100644 --- a/ext/gmp/tests/bug32773.phpt +++ b/ext/gmp/tests/bug32773.phpt @@ -23,4 +23,4 @@ try { 10 + 0 = 10 10 + "0" = 10 Division by zero -Division by zero +gmp_div_qr(): Argument #2 ($num2) Division by zero diff --git a/ext/gmp/tests/gmp_div_qr.phpt b/ext/gmp/tests/gmp_div_qr.phpt index a5e6af87633c1..f7649b0208c22 100644 --- a/ext/gmp/tests/gmp_div_qr.phpt +++ b/ext/gmp/tests/gmp_div_qr.phpt @@ -60,8 +60,8 @@ array(2) { string(1) "0" } } -Division by zero -Division by zero +gmp_div_qr(): Argument #2 ($num2) Division by zero +gmp_div_qr(): Argument #2 ($num2) Division by zero array(2) { [0]=> object(GMP)#2 (1) { From 440e9fdf725050cedf9df8c66d0ddcf94f9a91bb Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 23:43:55 +0000 Subject: [PATCH 11/22] ext/gmp: Refactor gmp_div_(q|r)() to use new ZPP specifier --- ext/gmp/gmp.c | 108 +++++++++++++++++------------------ ext/gmp/tests/bug32773.phpt | 2 +- ext/gmp/tests/gmp_div_q.phpt | 2 +- ext/gmp/tests/gmp_div_r.phpt | 2 +- 4 files changed, 56 insertions(+), 58 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index d8c1291f939fc..dbd27f011d91d 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -271,21 +271,6 @@ static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_ static void gmp_mpz_tdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { mpz_tdiv_q_ui(a, b, c); } -static void gmp_mpz_tdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { - mpz_tdiv_r_ui(a, b, c); -} -static void gmp_mpz_fdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { - mpz_fdiv_q_ui(a, b, c); -} -static void gmp_mpz_fdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { - mpz_fdiv_r_ui(a, b, c); -} -static void gmp_mpz_cdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { - mpz_cdiv_r_ui(a, b, c); -} -static void gmp_mpz_cdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { - mpz_cdiv_q_ui(a, b, c); -} static void gmp_mpz_mod_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { mpz_mod_ui(a, b, c); } @@ -1164,72 +1149,85 @@ ZEND_FUNCTION(gmp_div_qr) } } -/* {{{ Divide a by b, returns reminder only */ +/* Divide a by b, returns reminder only */ ZEND_FUNCTION(gmp_div_r) { - zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; zend_long round = GMP_ROUND_ZERO; ZEND_PARSE_PARAMETERS_START(2, 3) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) Z_PARAM_OPTIONAL Z_PARAM_LONG(round) ZEND_PARSE_PARAMETERS_END(); - switch (round) { - case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op( - return_value, a_arg, b_arg, mpz_tdiv_r, gmp_mpz_tdiv_r_ui, 1, /* is_operator */ false); - break; - case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op( - return_value, a_arg, b_arg, mpz_cdiv_r, gmp_mpz_cdiv_r_ui, 1, /* is_operator */ false); - break; - case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op( - return_value, a_arg, b_arg, mpz_fdiv_r, gmp_mpz_fdiv_r_ui, 1, /* is_operator */ false); - break; - default: - zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF"); + if (mpz_cmp_ui(gmpnum_b, 0) == 0) { + zend_argument_error(zend_ce_division_by_zero_error, 2, "Division by zero"); RETURN_THROWS(); } + + switch (round) { + case GMP_ROUND_ZERO: { + INIT_GMP_RETVAL(gmpnum_result); + mpz_tdiv_r(gmpnum_result, gmpnum_a, gmpnum_b); + return; + } + case GMP_ROUND_PLUSINF: { + INIT_GMP_RETVAL(gmpnum_result); + mpz_cdiv_r(gmpnum_result, gmpnum_a, gmpnum_b); + return; + } + case GMP_ROUND_MINUSINF: { + INIT_GMP_RETVAL(gmpnum_result); + mpz_fdiv_r(gmpnum_result, gmpnum_a, gmpnum_b); + return; + } + default: + zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF"); + RETURN_THROWS(); + } } -/* }}} */ -/* {{{ Divide a by b, returns quotient only */ +/* Divide a by b, returns quotient only */ ZEND_FUNCTION(gmp_div_q) { - zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; zend_long round = GMP_ROUND_ZERO; ZEND_PARSE_PARAMETERS_START(2, 3) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) Z_PARAM_OPTIONAL Z_PARAM_LONG(round) ZEND_PARSE_PARAMETERS_END(); - switch (round) { - case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op( - return_value, a_arg, b_arg, mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1, /* is_operator */ false); - break; - case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op( - return_value, a_arg, b_arg, mpz_cdiv_q, gmp_mpz_cdiv_q_ui, 1, /* is_operator */ false); - break; - case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op( - return_value, a_arg, b_arg, mpz_fdiv_q, gmp_mpz_fdiv_q_ui, 1, /* is_operator */ false); - break; - default: - zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF"); + if (mpz_cmp_ui(gmpnum_b, 0) == 0) { + zend_argument_error(zend_ce_division_by_zero_error, 2, "Division by zero"); RETURN_THROWS(); } + switch (round) { + case GMP_ROUND_ZERO: { + INIT_GMP_RETVAL(gmpnum_result); + mpz_tdiv_q(gmpnum_result, gmpnum_a, gmpnum_b); + return; + } + case GMP_ROUND_PLUSINF: { + INIT_GMP_RETVAL(gmpnum_result); + mpz_cdiv_q(gmpnum_result, gmpnum_a, gmpnum_b); + return; + } + case GMP_ROUND_MINUSINF: { + INIT_GMP_RETVAL(gmpnum_result); + mpz_fdiv_q(gmpnum_result, gmpnum_a, gmpnum_b); + return; + } + default: + zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF"); + RETURN_THROWS(); + } } -/* }}} */ /* {{{ Computes a modulo b */ ZEND_FUNCTION(gmp_mod) diff --git a/ext/gmp/tests/bug32773.phpt b/ext/gmp/tests/bug32773.phpt index 6b60780a4d42c..3df59e67faff0 100644 --- a/ext/gmp/tests/bug32773.phpt +++ b/ext/gmp/tests/bug32773.phpt @@ -22,5 +22,5 @@ try { --EXPECT-- 10 + 0 = 10 10 + "0" = 10 -Division by zero +gmp_div(): Argument #2 ($num2) Division by zero gmp_div_qr(): Argument #2 ($num2) Division by zero diff --git a/ext/gmp/tests/gmp_div_q.phpt b/ext/gmp/tests/gmp_div_q.phpt index c3bc4f37097f2..8d892c3ff0adb 100644 --- a/ext/gmp/tests/gmp_div_q.phpt +++ b/ext/gmp/tests/gmp_div_q.phpt @@ -46,7 +46,7 @@ object(GMP)#1 (1) { ["num"]=> string(1) "0" } -Division by zero +gmp_div_q(): Argument #2 ($num2) Division by zero object(GMP)#2 (1) { ["num"]=> string(1) "0" diff --git a/ext/gmp/tests/gmp_div_r.phpt b/ext/gmp/tests/gmp_div_r.phpt index 47d43dfcedc9b..501284ad47f82 100644 --- a/ext/gmp/tests/gmp_div_r.phpt +++ b/ext/gmp/tests/gmp_div_r.phpt @@ -46,7 +46,7 @@ object(GMP)#1 (1) { ["num"]=> string(1) "0" } -Division by zero +gmp_div_r(): Argument #2 ($num2) Division by zero object(GMP)#3 (1) { ["num"]=> string(5) "12653" From fd21bb4c0c59d57ce3f73d732b72e9421737b354 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 23:48:22 +0000 Subject: [PATCH 12/22] ext/gmp: Refactor gmp_divexact() and gmp_mod() to use custom ZPP specifier --- ext/gmp/gmp.c | 50 ++++++++++++++++++--------------- ext/gmp/tests/gmp_divexact.phpt | 2 +- ext/gmp/tests/gmp_mod.phpt | 2 +- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index dbd27f011d91d..68af3cfaa233b 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -275,11 +275,6 @@ static void gmp_mpz_mod_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { mpz_mod_ui(a, b, c); } -/* Binary operations */ -#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0) -#define gmp_binary_ui_op_no_zero(op, uop) \ - _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1) - static void gmp_free_object_storage(zend_object *obj) /* {{{ */ { gmp_object *intern = GET_GMP_OBJECT_FROM_OBJ(obj); @@ -878,21 +873,6 @@ static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval * } /* }}} */ -/* {{{ _gmp_binary_ui_op */ -static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero) -{ - zval *a_arg, *b_arg; - - ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(a_arg) - Z_PARAM_ZVAL(b_arg) - ZEND_PARSE_PARAMETERS_END(); - - gmp_zval_binary_ui_op( - return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero, /* is_operator */ false); -} -/* }}} */ - /* Unary operations */ /* {{{ gmp_zval_unary_op */ @@ -1232,14 +1212,40 @@ ZEND_FUNCTION(gmp_div_q) /* {{{ Computes a modulo b */ ZEND_FUNCTION(gmp_mod) { - gmp_binary_ui_op_no_zero(mpz_mod, gmp_mpz_mod_ui); + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; + + ZEND_PARSE_PARAMETERS_START(2, 2) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) + ZEND_PARSE_PARAMETERS_END(); + + if (mpz_cmp_ui(gmpnum_b, 0) == 0) { + zend_argument_error(zend_ce_division_by_zero_error, 2, "Modulo by zero"); + RETURN_THROWS(); + } + + INIT_GMP_RETVAL(gmpnum_result); + mpz_mod(gmpnum_result, gmpnum_a, gmpnum_b); } /* }}} */ /* {{{ Divide a by b using exact division algorithm */ ZEND_FUNCTION(gmp_divexact) { - gmp_binary_ui_op_no_zero(mpz_divexact, NULL); + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; + + ZEND_PARSE_PARAMETERS_START(2, 2) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) + ZEND_PARSE_PARAMETERS_END(); + + if (mpz_cmp_ui(gmpnum_b, 0) == 0) { + zend_argument_error(zend_ce_division_by_zero_error, 2, "Division by zero"); + RETURN_THROWS(); + } + + INIT_GMP_RETVAL(gmpnum_result); + mpz_divexact(gmpnum_result, gmpnum_a, gmpnum_b); } /* }}} */ diff --git a/ext/gmp/tests/gmp_divexact.phpt b/ext/gmp/tests/gmp_divexact.phpt index ced6dc34836a5..ecd7df4fef23a 100644 --- a/ext/gmp/tests/gmp_divexact.phpt +++ b/ext/gmp/tests/gmp_divexact.phpt @@ -42,7 +42,7 @@ echo "Done\n"; ?> --EXPECT-- string(1) "0" -Division by zero +gmp_divexact(): Argument #2 ($num2) Division by zero string(2) "10" string(3) "512" string(19) "5000000000000000000" diff --git a/ext/gmp/tests/gmp_mod.phpt b/ext/gmp/tests/gmp_mod.phpt index 8581e66376f76..af2e5936d5cfc 100644 --- a/ext/gmp/tests/gmp_mod.phpt +++ b/ext/gmp/tests/gmp_mod.phpt @@ -42,7 +42,7 @@ object(GMP)#2 (1) { ["num"]=> string(1) "0" } -Modulo by zero +gmp_mod(): Argument #2 ($num2) Modulo by zero gmp_mod(): Argument #1 ($num1) must be of type GMP|string|int, array given object(GMP)#4 (1) { ["num"]=> From da912d262490d2caef359973173f7d0f794a8540 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 23:49:26 +0000 Subject: [PATCH 13/22] ext/gmp: Remove now unused FETCH_GMP_ZVAL_DEP_DEP macro --- ext/gmp/gmp.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 68af3cfaa233b..21568862bd145 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -135,22 +135,6 @@ typedef struct _gmp_temp { mpz_clear(temp.num); \ } -#define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2, arg_pos) \ -if (IS_GMP(zval)) { \ - gmpnumber = GET_GMP_FROM_ZVAL(zval); \ - temp.is_used = 0; \ -} else { \ - mpz_init(temp.num); \ - if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \ - mpz_clear(temp.num); \ - FREE_GMP_TEMP(dep1); \ - FREE_GMP_TEMP(dep2); \ - RETURN_THROWS(); \ - } \ - temp.is_used = 1; \ - gmpnumber = temp.num; \ -} - #define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep, arg_pos) \ if (IS_GMP(zval)) { \ gmpnumber = GET_GMP_FROM_ZVAL(zval); \ From 18a16db497d98f737ac3a95778f4a41dc25c7a57 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 2 Nov 2024 23:58:34 +0000 Subject: [PATCH 14/22] ext/gmp: Refactor gmp_fact() to use new ZPP specifier Not sure it is the best approach to do this one however --- ext/gmp/gmp.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 21568862bd145..edbf7b5466e4b 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1262,33 +1262,23 @@ GMP_BINARY_OP_FUNCTION_EX(gmp_or, mpz_ior); /* {{{ Calculates factorial function */ ZEND_FUNCTION(gmp_fact) { - zval *a_arg; + mpz_ptr gmpnum; mpz_ptr gmpnum_result; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(a_arg) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(a_arg) == IS_LONG) { - if (Z_LVAL_P(a_arg) < 0) { - zend_argument_value_error(1, "must be greater than or equal to 0"); - RETURN_THROWS(); - } - } else { - mpz_ptr gmpnum; - gmp_temp_t temp_a; - - FETCH_GMP_ZVAL(gmpnum, a_arg, temp_a, 1); - FREE_GMP_TEMP(temp_a); - - if (mpz_sgn(gmpnum) < 0) { - zend_argument_value_error(1, "must be greater than or equal to 0"); - RETURN_THROWS(); - } + if (mpz_sgn(gmpnum) < 0) { + zend_argument_value_error(1, "must be greater than or equal to 0"); + RETURN_THROWS(); } + // TODO: Check that we don't an int that is larger than an unsigned long? + // Could use mpz_fits_slong_p() if we revert to using mpz_get_si() + INIT_GMP_RETVAL(gmpnum_result); - mpz_fac_ui(gmpnum_result, zval_get_long(a_arg)); + mpz_fac_ui(gmpnum_result, mpz_get_ui(gmpnum)); } /* }}} */ From 84c41142a599460a03fb0418ac5009ae0b2b7c06 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 3 Nov 2024 00:19:20 +0000 Subject: [PATCH 15/22] ext/gmp: Start refactoring operator overloading to use new parsing mechanism --- ext/gmp/gmp.c | 48 ++++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index edbf7b5466e4b..61b973a2f1406 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -169,10 +169,11 @@ static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos); static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator); -static bool gmp_zend_parse_arg_into_mpz( +static bool gmp_zend_parse_arg_into_mpz_ex( zval *arg, mpz_ptr *destination_mpz_ptr, - uint32_t arg_num + uint32_t arg_num, + bool is_operator ) { if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { if (EXPECTED(instanceof_function(Z_OBJCE_P(arg), gmp_ce))) { @@ -184,7 +185,7 @@ static bool gmp_zend_parse_arg_into_mpz( *destination_mpz_ptr = GMPG(zpp_arg[arg_num-1]); if (Z_TYPE_P(arg) == IS_STRING) { - return convert_zstr_to_gmp(*destination_mpz_ptr, Z_STR_P(arg), /* base */ 0, arg_num) != FAILURE; + return convert_zstr_to_gmp(*destination_mpz_ptr, Z_STR_P(arg), /* base */ 0, is_operator ? 0 : arg_num) != FAILURE; } if (Z_TYPE_P(arg) == IS_LONG) { @@ -194,6 +195,11 @@ static bool gmp_zend_parse_arg_into_mpz( return false; } +static bool gmp_zend_parse_arg_into_mpz(zval *arg, mpz_ptr *destination_mpz_ptr, uint32_t arg_num) +{ + return gmp_zend_parse_arg_into_mpz_ex(arg, destination_mpz_ptr, arg_num, false); +} + #define GMP_Z_PARAM_INTO_MPZ_PTR(destination_mpz_ptr) \ Z_PARAM_PROLOGUE(0, 0); \ if (UNEXPECTED(!gmp_zend_parse_arg_into_mpz(_arg, &destination_mpz_ptr, _i))) { \ @@ -250,7 +256,6 @@ typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); typedef gmp_ulong (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong); static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, bool check_b_zero, bool is_operator); -static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op); static void gmp_mpz_tdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { mpz_tdiv_q_ui(a, b, c); @@ -452,15 +457,9 @@ typeof_op_failure: ; #define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0) #define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0) -#define DO_UNARY_OP(op) \ - gmp_zval_unary_op(result, op1, op); \ - if (UNEXPECTED(EG(exception))) { \ - return FAILURE; \ - } \ - return SUCCESS; - static zend_result gmp_do_operation_ex(uint8_t opcode, zval *result, zval *op1, zval *op2) /* {{{ */ { + mpz_ptr gmp_op1, gmp_result; switch (opcode) { case ZEND_ADD: DO_BINARY_UI_OP(mpz_add); @@ -484,8 +483,14 @@ static zend_result gmp_do_operation_ex(uint8_t opcode, zval *result, zval *op1, DO_BINARY_OP(mpz_and); case ZEND_BW_XOR: DO_BINARY_OP(mpz_xor); - case ZEND_BW_NOT: - DO_UNARY_OP(mpz_com); + case ZEND_BW_NOT: { + if (!gmp_zend_parse_arg_into_mpz_ex(op1, &gmp_op1, 1, false)) { + return FAILURE; + } + gmp_create(result, &gmp_result); + mpz_com(gmp_result, gmp_op1); + return SUCCESS; + } default: return FAILURE; @@ -857,23 +862,6 @@ static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval * } /* }}} */ -/* Unary operations */ - -/* {{{ gmp_zval_unary_op */ -static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op) -{ - mpz_ptr gmpnum_a, gmpnum_result; - gmp_temp_t temp_a; - - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1); - - INIT_GMP_RETVAL(gmpnum_result); - gmp_op(gmpnum_result, gmpnum_a); - - FREE_GMP_TEMP(temp_a); -} -/* }}} */ - static bool gmp_verify_base(zend_long base, uint32_t arg_num) { if (base && (base < 2 || base > GMP_MAX_BASE)) { From 80407a8bf193d6c828587597923f71dc486f9fd1 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 3 Nov 2024 01:33:46 +0000 Subject: [PATCH 16/22] ext/gmp: Convert GMP operator overloading to new parsing mechanism --- ext/gmp/gmp.c | 133 ++++++++++++++++---------------------------------- 1 file changed, 41 insertions(+), 92 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 61b973a2f1406..ac019a7bdcfbe 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -213,14 +213,6 @@ static bool gmp_zend_parse_arg_into_mpz(zval *arg, mpz_ptr *destination_mpz_ptr, #define INIT_GMP_RETVAL(gmpnumber) \ gmp_create(return_value, &gmpnumber) -/* - * The gmp_*_op functions provide an implementation for several common types - * of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually - * passed zvals to work on, whereas the gmp_(unary|binary)_*_op macros already - * include parameter parsing. - */ -typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); - #define GMP_FN_NAME(name) gmp_##name #define GMP_MPZ_FN_NAME(name) mpz_##name @@ -247,23 +239,6 @@ typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); #define GMP_BINARY_OP_FUNCTION(name) GMP_BINARY_OP_FUNCTION_EX(GMP_FN_NAME(name), GMP_MPZ_FN_NAME(name)) -typedef void (*gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong); - -typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); - -typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, gmp_ulong); -typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); -typedef gmp_ulong (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong); - -static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, bool check_b_zero, bool is_operator); - -static void gmp_mpz_tdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { - mpz_tdiv_q_ui(a, b, c); -} -static void gmp_mpz_mod_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) { - mpz_mod_ui(a, b, c); -} - static void gmp_free_object_storage(zend_object *obj) /* {{{ */ { gmp_object *intern = GET_GMP_OBJECT_FROM_OBJ(obj); @@ -363,6 +338,39 @@ static zend_object *gmp_clone_obj(zend_object *obj) /* {{{ */ } /* }}} */ +typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); + +static zend_result binop_operator_helper(gmp_binary_op_t gmp_op, zval *return_value, zval *op1, zval *op2) { + mpz_ptr gmp_op1, gmp_op2, gmp_result; + if (!gmp_zend_parse_arg_into_mpz_ex(op1, &gmp_op1, 1, true)) { + if (!EG(exception)) { + zend_type_error("Number must be of type GMP|string|int, %s given", zend_zval_value_name(op1)); + } + return FAILURE; + } + if (!gmp_zend_parse_arg_into_mpz_ex(op2, &gmp_op2, 2, true)) { + if (!EG(exception)) { + zend_type_error("Number must be of type GMP|string|int, %s given", zend_zval_value_name(op2)); + } + return FAILURE; + } + /* Check special requirements for op2 */ + if (gmp_op == mpz_tdiv_q && mpz_cmp_ui(gmp_op2, 0) == 0) { + zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); + return FAILURE; + } + if (gmp_op == mpz_mod && mpz_cmp_ui(gmp_op2, 0) == 0) { + zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero"); + return FAILURE; + } + + gmp_create(return_value, &gmp_result); + gmp_op(gmp_result, gmp_op1, gmp_op2); + return SUCCESS; +} + +typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, gmp_ulong); + static zend_result shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2, uint8_t opcode) { zend_long shift = 0; @@ -448,41 +456,32 @@ typeof_op_failure: ; return FAILURE; } -#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \ - gmp_zval_binary_ui_op( \ - result, op1, op2, op, uop, check_b_zero, /* is_operator */ true); \ - if (UNEXPECTED(EG(exception))) { return FAILURE; } \ - return SUCCESS; - -#define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0) -#define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0) - static zend_result gmp_do_operation_ex(uint8_t opcode, zval *result, zval *op1, zval *op2) /* {{{ */ { mpz_ptr gmp_op1, gmp_result; switch (opcode) { case ZEND_ADD: - DO_BINARY_UI_OP(mpz_add); + return binop_operator_helper(mpz_add, result, op1, op2); case ZEND_SUB: - DO_BINARY_UI_OP(mpz_sub); + return binop_operator_helper(mpz_sub, result, op1, op2); case ZEND_MUL: - DO_BINARY_UI_OP(mpz_mul); + return binop_operator_helper(mpz_mul, result, op1, op2); case ZEND_POW: return shift_operator_helper(mpz_pow_ui, result, op1, op2, opcode); case ZEND_DIV: - DO_BINARY_UI_OP_EX(mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1); + return binop_operator_helper(mpz_tdiv_q, result, op1, op2); case ZEND_MOD: - DO_BINARY_UI_OP_EX(mpz_mod, gmp_mpz_mod_ui, 1); + return binop_operator_helper(mpz_mod, result, op1, op2); case ZEND_SL: return shift_operator_helper(mpz_mul_2exp, result, op1, op2, opcode); case ZEND_SR: return shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2, opcode); case ZEND_BW_OR: - DO_BINARY_OP(mpz_ior); + return binop_operator_helper(mpz_ior, result, op1, op2); case ZEND_BW_AND: - DO_BINARY_OP(mpz_and); + return binop_operator_helper(mpz_and, result, op1, op2); case ZEND_BW_XOR: - DO_BINARY_OP(mpz_xor); + return binop_operator_helper(mpz_xor, result, op1, op2); case ZEND_BW_NOT: { if (!gmp_zend_parse_arg_into_mpz_ex(op1, &gmp_op1, 1, false)) { return FAILURE; @@ -812,56 +811,6 @@ static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operat } /* }}} */ -/* {{{ gmp_zval_binary_ui_op - Execute GMP binary operation. -*/ -static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, bool check_b_zero, bool is_operator) -{ - mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; - gmp_temp_t temp_a, temp_b; - - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, is_operator ? 0 : 1); - - if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) { - gmpnum_b = NULL; - temp_b.is_used = 0; - } else { - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, is_operator ? 0 : 2); - } - - if (check_b_zero) { - int b_is_zero = 0; - if (!gmpnum_b) { - b_is_zero = (Z_LVAL_P(b_arg) == 0); - } else { - b_is_zero = !mpz_cmp_ui(gmpnum_b, 0); - } - - if (b_is_zero) { - if ((gmp_binary_op_t) mpz_mod == gmp_op) { - zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero"); - } else { - zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); - } - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); - RETURN_THROWS(); - } - } - - INIT_GMP_RETVAL(gmpnum_result); - - if (!gmpnum_b) { - gmp_ui_op(gmpnum_result, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg)); - } else { - gmp_op(gmpnum_result, gmpnum_a, gmpnum_b); - } - - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); -} -/* }}} */ - static bool gmp_verify_base(zend_long base, uint32_t arg_num) { if (base && (base < 2 || base > GMP_MAX_BASE)) { From fc66ec2c5be5ec2b146603726865b3fed75b3427 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 3 Nov 2024 01:53:59 +0000 Subject: [PATCH 17/22] ext/gmp: Add weak mode support for parsing --- ext/gmp/gmp.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index ac019a7bdcfbe..023fa78f18ff9 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -192,6 +192,24 @@ static bool gmp_zend_parse_arg_into_mpz_ex( mpz_set_si(*destination_mpz_ptr, Z_LVAL_P(arg)); return true; } + + /* This function is also used by the do_operation object hook, + * but operator overloading with objects should behave as if a + * method was called, thus strict types should apply. */ + if (!ZEND_ARG_USES_STRICT_TYPES()) { + zend_long lval = 0; + if (is_operator && Z_TYPE_P(arg) == IS_NULL) { + return false; + } + if (!zend_parse_arg_long_weak(arg, &lval, arg_num)) { + return false; + } + + mpz_set_si(*destination_mpz_ptr, lval); + + return true; + } + return false; } From 29a167c03936cc2cb58b6b80a7c52699885619f5 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 3 Nov 2024 01:58:15 +0000 Subject: [PATCH 18/22] ext/gmp: Use new parsing API in shift helper --- ext/gmp/gmp.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 023fa78f18ff9..be2625b33bf66 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -427,25 +427,13 @@ static zend_result shift_operator_helper(gmp_binary_ui_op_t op, zval *return_val return FAILURE; } else { mpz_ptr gmpnum_op, gmpnum_result; - gmp_temp_t temp; - /* We do not use FETCH_GMP_ZVAL(...); here as we don't use convert_to_gmp() - * as we want to handle the emitted exception ourself. */ - if (UNEXPECTED(!IS_GMP(op1))) { - if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { - goto typeof_op_failure; - } - mpz_init(temp.num); - mpz_set_si(temp.num, Z_LVAL_P(op1)); - temp.is_used = 1; - gmpnum_op = temp.num; - } else { - gmpnum_op = GET_GMP_FROM_ZVAL(op1); - temp.is_used = 0; + if (!gmp_zend_parse_arg_into_mpz_ex(op1, &gmpnum_op, 1, true)) { + goto typeof_op_failure; } + INIT_GMP_RETVAL(gmpnum_result); op(gmpnum_result, gmpnum_op, (gmp_ulong) shift); - FREE_GMP_TEMP(temp); return SUCCESS; } From f15f78e5caab462d5de8669631f32439e66a3447 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 3 Nov 2024 02:06:17 +0000 Subject: [PATCH 19/22] ext/gmp: Use new parsing mechanism in comparison operator overloading This removes the last usages of the old GMP_FETCH API --- ext/gmp/gmp.c | 153 ++++++-------------------------------------------- 1 file changed, 16 insertions(+), 137 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index be2625b33bf66..ef13e6fc405b0 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -90,11 +90,6 @@ PHP_GMP_API zend_class_entry *php_gmp_class_entry(void) { return gmp_ce; } -typedef struct _gmp_temp { - mpz_t num; - bool is_used; -} gmp_temp_t; - #define GMP_MAX_BASE 62 #define GMP_51_OR_NEWER \ @@ -111,63 +106,8 @@ typedef struct _gmp_temp { #define GET_GMP_FROM_ZVAL(zval) \ GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num -/* The FETCH_GMP_ZVAL_* family of macros is used to fetch a gmp number - * (mpz_ptr) from a zval. If the zval is not a GMP instance, then we - * try to convert the value to a temporary gmp number using convert_to_gmp. - * This temporary number is stored in the temp argument, which is of type - * gmp_temp_t. This temporary value needs to be freed lateron using the - * FREE_GMP_TEMP macro. - * - * If the conversion to a gmp number fails, the macros RETURN_THROWS() due to TypeError. - * The _DEP / _DEP_DEP variants additionally free the temporary values - * passed in the last / last two arguments. - * - * If one zval can sometimes be fetched as a long you have to set the - * is_used member of the corresponding gmp_temp_t value to 0, otherwise - * the FREE_GMP_TEMP and *_DEP macros will not work properly. - * - * The three FETCH_GMP_ZVAL_* macros below are mostly copy & paste code - * as I couldn't find a way to combine them. - */ - -#define FREE_GMP_TEMP(temp) \ - if (temp.is_used) { \ - mpz_clear(temp.num); \ - } - -#define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep, arg_pos) \ -if (IS_GMP(zval)) { \ - gmpnumber = GET_GMP_FROM_ZVAL(zval); \ - temp.is_used = 0; \ -} else { \ - mpz_init(temp.num); \ - if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \ - mpz_clear(temp.num); \ - FREE_GMP_TEMP(dep); \ - RETURN_THROWS(); \ - } \ - temp.is_used = 1; \ - gmpnumber = temp.num; \ -} - -#define FETCH_GMP_ZVAL(gmpnumber, zval, temp, arg_pos) \ -if (IS_GMP(zval)) { \ - gmpnumber = GET_GMP_FROM_ZVAL(zval); \ - temp.is_used = 0; \ -} else { \ - mpz_init(temp.num); \ - if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \ - mpz_clear(temp.num); \ - RETURN_THROWS(); \ - } \ - temp.is_used = 1; \ - gmpnumber = temp.num; \ -} - static void gmp_strval(zval *result, mpz_t gmpnum, int base); static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos); -static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos); -static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator); static bool gmp_zend_parse_arg_into_mpz_ex( zval *arg, @@ -524,18 +464,24 @@ static zend_result gmp_do_operation(uint8_t opcode, zval *result, zval *op1, zva static int gmp_compare(zval *op1, zval *op2) /* {{{ */ { - zval result; - - gmp_cmp(&result, op1, op2, /* is_operator */ true); + mpz_ptr gmp_op1, gmp_op2; + bool status = false; - /* An error/exception occurs if one of the operands is not a numeric string - * or an object which is different from GMP */ - if (EG(exception)) { - return 1; + status = gmp_zend_parse_arg_into_mpz_ex(op1, &gmp_op1, 1, true); + if (!status) { + if (!EG(exception)) { + zend_type_error("Number must be of type GMP|string|int, %s given", zend_zval_value_name(op1)); + } + return ZEND_UNCOMPARABLE; + } + status = gmp_zend_parse_arg_into_mpz_ex(op2, &gmp_op2, 2, true); + if (!status) { + if (!EG(exception)) { + zend_type_error("Number must be of type GMP|string|int, %s given", zend_zval_value_name(op2)); + } + return ZEND_UNCOMPARABLE; } - /* result can only be a zend_long if gmp_cmp hasn't thrown an Error */ - ZEND_ASSERT(Z_TYPE(result) == IS_LONG); - return Z_LVAL(result); + return mpz_cmp(gmp_op1, gmp_op2); } /* }}} */ @@ -719,44 +665,6 @@ static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, return SUCCESS; } -/* {{{ convert_to_gmp - * Convert zval to be gmp number */ -static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos) -{ - switch (Z_TYPE_P(val)) { - case IS_LONG: - mpz_set_si(gmpnumber, Z_LVAL_P(val)); - return SUCCESS; - case IS_STRING: { - return convert_zstr_to_gmp(gmpnumber, Z_STR_P(val), base, arg_pos); - } - case IS_NULL: - /* Just reject null for operator overloading */ - if (arg_pos == 0) { - zend_type_error("Number must be of type GMP|string|int, %s given", zend_zval_type_name(val)); - return FAILURE; - } - ZEND_FALLTHROUGH; - default: { - zend_long lval; - if (!zend_parse_arg_long_slow(val, &lval, arg_pos)) { - if (arg_pos == 0) { - zend_type_error( - "Number must be of type GMP|string|int, %s given", zend_zval_value_name(val)); - } else { - zend_argument_type_error(arg_pos, - "must be of type GMP|string|int, %s given", zend_zval_value_name(val)); - } - return FAILURE; - } - - mpz_set_si(gmpnumber, lval); - return SUCCESS; - } - } -} -/* }}} */ - static void gmp_strval(zval *result, mpz_t gmpnum, int base) /* {{{ */ { size_t num_len; @@ -788,35 +696,6 @@ static void gmp_strval(zval *result, mpz_t gmpnum, int base) /* {{{ */ } /* }}} */ -static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator) /* {{{ */ -{ - mpz_ptr gmpnum_a, gmpnum_b; - gmp_temp_t temp_a, temp_b; - bool use_si = 0; - zend_long res; - - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, is_operator ? 0 : 1); - - if (Z_TYPE_P(b_arg) == IS_LONG) { - use_si = 1; - temp_b.is_used = 0; - } else { - FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, is_operator ? 0 : 2); - } - - if (use_si) { - res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg)); - } else { - res = mpz_cmp(gmpnum_a, gmpnum_b); - } - - FREE_GMP_TEMP(temp_a); - FREE_GMP_TEMP(temp_b); - - RETURN_LONG(res); -} -/* }}} */ - static bool gmp_verify_base(zend_long base, uint32_t arg_num) { if (base && (base < 2 || base > GMP_MAX_BASE)) { From 837c04df45bc6f51e2619b292af52f87a7ed1448 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 3 Nov 2024 13:32:01 +0000 Subject: [PATCH 20/22] ext/gmp: Refactor gmp_cmp() test --- ext/gmp/tests/gmp_cmp.phpt | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/ext/gmp/tests/gmp_cmp.phpt b/ext/gmp/tests/gmp_cmp.phpt index 3154b68064ade..535d23cc4a204 100644 --- a/ext/gmp/tests/gmp_cmp.phpt +++ b/ext/gmp/tests/gmp_cmp.phpt @@ -5,17 +5,27 @@ gmp --FILE-- "equals\n", + $r < 0 => "right greater than left\n", + $r > 0 => "left greater than right\n", + }; +} + +cmp_helper(123123,-123123); +cmp_helper("12345678900987654321","12345678900987654321"); +cmp_helper("12345678900987654321","123456789009876543211"); +cmp_helper(0,0); +cmp_helper(1231222,0); +cmp_helper(0,345355); $n = gmp_init("827278512385463739"); var_dump(gmp_cmp(0,$n) < 0); $n1 = gmp_init("827278512385463739"); -var_dump(gmp_cmp($n1,$n)); +var_dump(gmp_cmp($n1,$n) === 0); try { var_dump(gmp_cmp(array(),array())); @@ -26,13 +36,13 @@ try { echo "Done\n"; ?> --EXPECT-- -int(1) -int(0) -int(-1) -int(0) -int(1) -int(-1) +gmp(123123, -123123): left greater than right +gmp('12345678900987654321', '12345678900987654321'): equals +gmp('12345678900987654321', '123456789009876543211'): right greater than left +gmp(0, 0): equals +gmp(1231222, 0): left greater than right +gmp(0, 345355): right greater than left +bool(true) bool(true) -int(0) gmp_cmp(): Argument #1 ($num1) must be of type GMP|string|int, array given Done From ff1eed39c8d7d455d8aa4529495b234d6f7e25ad Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 10 Nov 2024 20:30:05 +0000 Subject: [PATCH 21/22] Normalize gmp_cmp() to -1/0/+1 --- ext/gmp/gmp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index ef13e6fc405b0..b566c3e91bf8a 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -481,7 +481,8 @@ static int gmp_compare(zval *op1, zval *op2) /* {{{ */ } return ZEND_UNCOMPARABLE; } - return mpz_cmp(gmp_op1, gmp_op2); + + return ZEND_THREEWAY_COMPARE(mpz_cmp(gmp_op1, gmp_op2), 0); } /* }}} */ @@ -1436,7 +1437,7 @@ ZEND_FUNCTION(gmp_cmp) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - RETURN_LONG(mpz_cmp(gmpnum_a, gmpnum_b)); + RETURN_LONG(ZEND_THREEWAY_COMPARE(mpz_cmp(gmpnum_a, gmpnum_b), 0)); } /* }}} */ From 1b89878c8d2c2af28aecad1e271df66ff456b3ea Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 16 Nov 2024 16:47:30 +0000 Subject: [PATCH 22/22] ext/gmp: Remove redundant parenthesis --- ext/gmp/gmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index b566c3e91bf8a..1d87695c6e335 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1303,7 +1303,7 @@ ZEND_FUNCTION(gmp_perfect_square) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - RETURN_BOOL((mpz_perfect_square_p(gmpnum_a) != 0)); + RETURN_BOOL(mpz_perfect_square_p(gmpnum_a) != 0); } /* }}} */ @@ -1316,7 +1316,7 @@ ZEND_FUNCTION(gmp_perfect_power) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - RETURN_BOOL((mpz_perfect_power_p(gmpnum_a) != 0)); + RETURN_BOOL(mpz_perfect_power_p(gmpnum_a) != 0); } /* }}} */