diff options
| author | Philipp Stephani | 2019-11-02 10:54:57 +0100 |
|---|---|---|
| committer | Philipp Stephani | 2019-12-04 21:17:10 +0100 |
| commit | 096be9c4541329af259273fe604dc4f8669fbd8a (patch) | |
| tree | 9a93e99ec78c598bfa42b73c30e7ff349a3bb489 /doc/lispref | |
| parent | 0ca32d1270bd5d494e365f3525fa65ac423f6658 (diff) | |
| download | emacs-096be9c4541329af259273fe604dc4f8669fbd8a.tar.gz emacs-096be9c4541329af259273fe604dc4f8669fbd8a.zip | |
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
Diffstat (limited to 'doc/lispref')
| -rw-r--r-- | doc/lispref/internals.texi | 218 |
1 files changed, 158 insertions, 60 deletions
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index e870d6e06e8..f1062a2f4d0 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi | |||
| @@ -1475,6 +1475,42 @@ the widest integral data type supported by the C compiler, typically | |||
| 1475 | @code{overflow-error}. | 1475 | @code{overflow-error}. |
| 1476 | @end deftypefn | 1476 | @end deftypefn |
| 1477 | 1477 | ||
| 1478 | @deftypefn Function bool extract_big_integer (emacs_env *@var{env}, emacs_value @var{arg}, int *@var{sign}, ptrdiff_t *@var{count}, emacs_limb_t *@var{magnitude}) | ||
| 1479 | This function, which is available since Emacs 27, extracts the | ||
| 1480 | integral value of @var{arg}. The value of @var{arg} must be an | ||
| 1481 | integer (fixnum or bignum). If @var{sign} is not @code{NULL}, it | ||
| 1482 | stores the sign of @var{arg} (-1, 0, or +1) into @code{*sign}. The | ||
| 1483 | magnitude is stored into @var{magnitude} as follows. If @var{count} | ||
| 1484 | and @var{magnitude} are bot non-@code{NULL}, then @var{magnitude} must | ||
| 1485 | point to an array of at least @code{*count} @code{unsigned long} | ||
| 1486 | elements. If @var{magnitude} is large enough to hold the magnitude of | ||
| 1487 | @var{arg}, then this function writes the magnitude into the | ||
| 1488 | @var{magnitude} array in little-endian form, stores the number of | ||
| 1489 | array elements written into @code{*count}, and returns @code{true}. | ||
| 1490 | If @var{magnitude} is not large enough, it stores the required array | ||
| 1491 | size into @code{*count}, signals an error, and returns @code{false}. | ||
| 1492 | If @var{count} is not @code{NULL} and @var{magnitude} is @code{NULL}, | ||
| 1493 | then the function stores the required array size into @code{*count} | ||
| 1494 | and returns @code{true}. | ||
| 1495 | |||
| 1496 | Emacs guarantees that the maximum required value of @code{*count} | ||
| 1497 | never exceeds @code{min (PTRDIFF_MAX, SIZE_MAX) / sizeof | ||
| 1498 | (emacs_limb_t)}. This implies that you can use e.g. @code{malloc | ||
| 1499 | ((size_t) (*count * sizeof (emacs_limb_t)))} to allocate the | ||
| 1500 | @code{magnitude} array without integer overflow. | ||
| 1501 | @end deftypefn | ||
| 1502 | |||
| 1503 | @deftp {Type alias} emacs_limb_t | ||
| 1504 | This type is an alias to an otherwise unspecified unsigned integral | ||
| 1505 | type. It is used as element type for the magnitude arrays for the big | ||
| 1506 | integer conversion functions. | ||
| 1507 | @end deftp | ||
| 1508 | |||
| 1509 | @defvr Macro EMACS_LIMB_MAX | ||
| 1510 | This macro expands to an integer literal specifying the maximum | ||
| 1511 | possible value for an @code{emacs_limb_t} object. | ||
| 1512 | @end defvr | ||
| 1513 | |||
| 1478 | @deftypefn Function double extract_float (emacs_env *@var{env}, emacs_value @var{arg}) | 1514 | @deftypefn Function double extract_float (emacs_env *@var{env}, emacs_value @var{arg}) |
| 1479 | This function returns the value of a Lisp float specified by | 1515 | This function returns the value of a Lisp float specified by |
| 1480 | @var{arg}, as a C @code{double} value. | 1516 | @var{arg}, as a C @code{double} value. |
| @@ -1572,6 +1608,128 @@ limits set by @code{most-negative-fixnum} and | |||
| 1572 | @code{most-positive-fixnum} (@pxref{Integer Basics}). | 1608 | @code{most-positive-fixnum} (@pxref{Integer Basics}). |
| 1573 | @end deftypefn | 1609 | @end deftypefn |
| 1574 | 1610 | ||
| 1611 | @deftypefn Function emacs_value make_big_integer (emacs_env *@var{env}, int sign, ptrdiff_t count, const emacs_limb_t *magnitude) | ||
| 1612 | This function, which is available since Emacs 27, takes an | ||
| 1613 | arbitrary-sized integer argument and returns a corresponding | ||
| 1614 | @code{emacs_value} object. The @var{sign} argument gives the sign of | ||
| 1615 | the return value. If @var{sign} is nonzero, then @var{magnitude} must | ||
| 1616 | point to an array of at least @var{count} elements specifying the | ||
| 1617 | little-endian magnitude of the return value. | ||
| 1618 | @end deftypefn | ||
| 1619 | |||
| 1620 | The following example uses the GNU Multiprecision Library (GMP) to | ||
| 1621 | calculate the next probable prime after a given integer. | ||
| 1622 | @xref{Top,,,gmp} for a general overview of GMP, and @pxref{Integer | ||
| 1623 | Import and Export,,,gmp} for how to convert the @code{magnitude} array | ||
| 1624 | to and from GMP @code{mpz_t} values. | ||
| 1625 | |||
| 1626 | @example | ||
| 1627 | #include <assert.h> | ||
| 1628 | #include <limits.h> | ||
| 1629 | #include <stdint.h> | ||
| 1630 | #include <stdlib.h> | ||
| 1631 | #include <string.h> | ||
| 1632 | |||
| 1633 | #include <gmp.h> | ||
| 1634 | |||
| 1635 | #include <emacs-module.h> | ||
| 1636 | |||
| 1637 | static void | ||
| 1638 | memory_full (emacs_env *env) | ||
| 1639 | @{ | ||
| 1640 | const char *message = "Memory exhausted"; | ||
| 1641 | emacs_value data = env->make_string (env, message, strlen (message)); | ||
| 1642 | env->non_local_exit_signal (env, env->intern (env, "error"), | ||
| 1643 | env->funcall (env, env->intern (env, "list"), 1, | ||
| 1644 | &data)); | ||
| 1645 | @} | ||
| 1646 | |||
| 1647 | enum | ||
| 1648 | @{ | ||
| 1649 | max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX) | ||
| 1650 | / sizeof (emacs_limb_t)) | ||
| 1651 | @}; | ||
| 1652 | |||
| 1653 | static bool | ||
| 1654 | extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result) | ||
| 1655 | @{ | ||
| 1656 | int sign; | ||
| 1657 | ptrdiff_t count; | ||
| 1658 | bool success = env->extract_big_integer (env, arg, &sign, &count, NULL); | ||
| 1659 | if (!success) | ||
| 1660 | return false; | ||
| 1661 | if (sign == 0) | ||
| 1662 | @{ | ||
| 1663 | mpz_set_ui (result, 0); | ||
| 1664 | return true; | ||
| 1665 | @} | ||
| 1666 | enum @{ order = -1, size = sizeof (emacs_limb_t), endian = 0, nails = 0 @}; | ||
| 1667 | assert (0 < count && count <= max_count); | ||
| 1668 | emacs_limb_t *magnitude = malloc ((size_t) (count * size)); | ||
| 1669 | if (magnitude == NULL) | ||
| 1670 | @{ | ||
| 1671 | memory_full (env); | ||
| 1672 | return false; | ||
| 1673 | @} | ||
| 1674 | success = env->extract_big_integer (env, arg, NULL, &count, magnitude); | ||
| 1675 | assert (success); | ||
| 1676 | mpz_import (result, count, order, size, endian, nails, magnitude); | ||
| 1677 | free (magnitude); | ||
| 1678 | if (sign < 0) | ||
| 1679 | mpz_neg (result, result); | ||
| 1680 | return true; | ||
| 1681 | @} | ||
| 1682 | |||
| 1683 | static emacs_value | ||
| 1684 | make_big_integer (emacs_env *env, const mpz_t value) | ||
| 1685 | @{ | ||
| 1686 | if (mpz_sgn (value) == 0) | ||
| 1687 | return env->make_integer (env, 0); | ||
| 1688 | enum | ||
| 1689 | @{ | ||
| 1690 | order = -1, | ||
| 1691 | size = sizeof (emacs_limb_t), | ||
| 1692 | endian = 0, | ||
| 1693 | nails = 0, | ||
| 1694 | numb = 8 * size - nails | ||
| 1695 | @}; | ||
| 1696 | size_t count = (mpz_sizeinbase (value, 2) + numb - 1) / numb; | ||
| 1697 | if (max_count < count) | ||
| 1698 | @{ | ||
| 1699 | memory_full (env); | ||
| 1700 | return NULL; | ||
| 1701 | @} | ||
| 1702 | emacs_limb_t *magnitude = malloc (count * size); | ||
| 1703 | if (magnitude == NULL) | ||
| 1704 | @{ | ||
| 1705 | memory_full (env); | ||
| 1706 | return NULL; | ||
| 1707 | @} | ||
| 1708 | size_t written; | ||
| 1709 | mpz_export (magnitude, &written, order, size, endian, nails, value); | ||
| 1710 | assert (written == count); | ||
| 1711 | assert (count <= PTRDIFF_MAX); | ||
| 1712 | emacs_value result = env->make_big_integer (env, mpz_sgn (value), | ||
| 1713 | (ptrdiff_t) count, magnitude); | ||
| 1714 | free (magnitude); | ||
| 1715 | return result; | ||
| 1716 | @} | ||
| 1717 | |||
| 1718 | static emacs_value | ||
| 1719 | next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | ||
| 1720 | void *data) | ||
| 1721 | @{ | ||
| 1722 | assert (nargs == 1); | ||
| 1723 | emacs_mpz p; | ||
| 1724 | mpz_init (p); | ||
| 1725 | extract_big_integer (env, args[0], p); | ||
| 1726 | mpz_nextprime (p, p); | ||
| 1727 | emacs_value result = make_big_integer (env, p); | ||
| 1728 | mpz_clear (p); | ||
| 1729 | return result; | ||
| 1730 | @} | ||
| 1731 | @end example | ||
| 1732 | |||
| 1575 | @deftypefn Function emacs_value make_float (emacs_env *@var{env}, double @var{d}) | 1733 | @deftypefn Function emacs_value make_float (emacs_env *@var{env}, double @var{d}) |
| 1576 | This function takes a @code{double} argument @var{d} and returns the | 1734 | This function takes a @code{double} argument @var{d} and returns the |
| 1577 | corresponding Emacs floating-point value. | 1735 | corresponding Emacs floating-point value. |
| @@ -1601,66 +1759,6 @@ function raises the @code{overflow-error} error condition if | |||
| 1601 | string. | 1759 | string. |
| 1602 | @end deftypefn | 1760 | @end deftypefn |
| 1603 | 1761 | ||
| 1604 | If you define the preprocessor macro @code{EMACS_MODULE_GMP} before | ||
| 1605 | including the header @file{emacs-module.h}, you can also convert | ||
| 1606 | between Emacs integers and GMP @code{mpz_t} values. @xref{GMP | ||
| 1607 | Basics,,,gmp}. If @code{EMACS_MODULE_GMP} is defined, | ||
| 1608 | @file{emacs-module.h} wraps @code{mpz_t} in the following structure: | ||
| 1609 | |||
| 1610 | @deftp struct emacs_mpz value | ||
| 1611 | struct emacs_mpz @{ mpz_t value; @}; | ||
| 1612 | @end deftp | ||
| 1613 | |||
| 1614 | @noindent | ||
| 1615 | Then you can use the following additional functions: | ||
| 1616 | |||
| 1617 | @deftypefn Function bool extract_big_integer (emacs_env *@var{env}, emacs_value @var{arg}, struct emacs_mpz *@var{result}) | ||
| 1618 | This function, which is available since Emacs 27, extracts the | ||
| 1619 | integral value of @var{arg} into @var{result}. @var{result} must not | ||
| 1620 | be @code{NULL}. @code{@var{result}->value} must be an initialized | ||
| 1621 | @code{mpz_t} object. @xref{Initializing Integers,,,gmp}. If | ||
| 1622 | @var{arg} is an integer, Emacs will store its value into | ||
| 1623 | @code{@var{result}->value}. After you have finished using | ||
| 1624 | @code{@var{result}->value}, you should free it using @code{mpz_clear} | ||
| 1625 | or similar. | ||
| 1626 | @end deftypefn | ||
| 1627 | |||
| 1628 | @deftypefn Function emacs_value make_big_integer (emacs_env *@var{env}, const struct emacs_mpz *@var{value}) | ||
| 1629 | This function, which is available since Emacs 27, takes an | ||
| 1630 | arbitrary-sized integer argument and returns a corresponding | ||
| 1631 | @code{emacs_value} object. @var{value} must not be @code{NULL}. | ||
| 1632 | @code{@var{value}->value} must be an initialized @code{mpz_t} object. | ||
| 1633 | @xref{Initializing Integers,,,gmp}. Emacs will return a corresponding | ||
| 1634 | integral object. After you have finished using | ||
| 1635 | @code{@var{value}->value}, you should free it using @code{mpz_clear} | ||
| 1636 | or similar. | ||
| 1637 | @end deftypefn | ||
| 1638 | |||
| 1639 | The following example uses GMP to calculate the next probable prime | ||
| 1640 | after a given integer: | ||
| 1641 | |||
| 1642 | @example | ||
| 1643 | #include <assert.h> | ||
| 1644 | #include <gmp.h> | ||
| 1645 | |||
| 1646 | #define EMACS_MODULE_GMP | ||
| 1647 | #include <emacs-module.h> | ||
| 1648 | |||
| 1649 | static emacs_value | ||
| 1650 | next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | ||
| 1651 | void *data) | ||
| 1652 | @{ | ||
| 1653 | assert (nargs == 1); | ||
| 1654 | emacs_mpz p; | ||
| 1655 | mpz_init (p.value); | ||
| 1656 | env->extract_big_integer (env, args[0], &p); | ||
| 1657 | mpz_nextprime (p.value, p.value); | ||
| 1658 | emacs_value result = env->make_big_integer (env, &p); | ||
| 1659 | mpz_clear (p.value); | ||
| 1660 | return result; | ||
| 1661 | @} | ||
| 1662 | @end example | ||
| 1663 | |||
| 1664 | The @acronym{API} does not provide functions to manipulate Lisp data | 1762 | The @acronym{API} does not provide functions to manipulate Lisp data |
| 1665 | structures, for example, create lists with @code{cons} and @code{list} | 1763 | structures, for example, create lists with @code{cons} and @code{list} |
| 1666 | (@pxref{Building Lists}), extract list members with @code{car} and | 1764 | (@pxref{Building Lists}), extract list members with @code{car} and |