Blob Blame History Raw
diff -up src/sage/cpython/cython_metaclass.h.orig src/sage/cpython/cython_metaclass.h
--- src/sage/cpython/cython_metaclass.h.orig	2022-05-15 16:11:11.000000000 -0600
+++ src/sage/cpython/cython_metaclass.h	2022-06-29 11:07:37.296150769 -0600
@@ -66,7 +66,7 @@ static CYTHON_INLINE int Sage_PyType_Rea
         }
 
         /* Now, set t.__class__ to metaclass */
-        Py_TYPE(t) = metaclass;
+        Py_SET_TYPE(t, metaclass);
         PyType_Modified(t);
     }
     else
diff -up src/sage/cpython/dict_del_by_value.pyx.orig src/sage/cpython/dict_del_by_value.pyx
--- src/sage/cpython/dict_del_by_value.pyx.orig	2022-05-15 16:11:11.000000000 -0600
+++ src/sage/cpython/dict_del_by_value.pyx	2022-06-30 12:06:01.148346330 -0600
@@ -25,7 +25,7 @@ from weakref import KeyedRef
 from cpython.list cimport PyList_New
 from cpython cimport Py_XINCREF, Py_XDECREF
 
-from libc.stdint cimport int8_t, int16_t, int32_t, int64_t
+from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, uint8_t, uint32_t
 cdef extern from "Python.h":
     ctypedef struct PyDictKeysObject
 
@@ -45,8 +45,6 @@ cdef extern from "Python.h":
 #(this file is not exported from CPython, so we need to be
 #careful the definitions are in step with what happens there.
 
-ctypedef void* dict_lookup_func  # Precise definition not needed
-
 ctypedef union IndexBlock:
     int8_t as_1[8]
     int16_t as_2[4]
@@ -55,8 +53,10 @@ ctypedef union IndexBlock:
 
 ctypedef struct MyPyDictKeysObject:
     Py_ssize_t dk_refcnt
-    Py_ssize_t dk_size
-    dict_lookup_func dk_lookup
+    uint8_t dk_log2_size
+    uint8_t dk_log2_index_bytes
+    uint8_t dk_kind
+    uint32_t dk_version
     Py_ssize_t dk_usable
     Py_ssize_t dk_nentries
     IndexBlock dk_indices
@@ -66,46 +66,65 @@ ctypedef struct PyDictKeyEntry:
     PyObject * me_key
     PyObject * me_value
 
+ctypedef struct PyDictUnicodeEntry:
+    PyObject * me_key
+    PyObject * me_value
+
 cdef Py_ssize_t DKIX_EMPTY = -1
 cdef Py_ssize_t DKIX_DUMMY = -2
 cdef Py_ssize_t DKIX_ERROR = -3
+cdef Py_ssize_t DKIX_KEY_CHANGED = -4
+
+ctypedef enum DictKeysKind:
+    DICT_KEYS_GENERAL = 0,
+    DICT_KEYS_UNICODE = 1,
+    DICT_KEYS_SPLIT = 2
 
 #####
 #These routines are copied from CPython's Object/dictobject.c
 #in order to access PyDictKeysObject fields
 
+cdef inline Py_ssize_t DK_SIZE(MyPyDictKeysObject *keys):
+    return 1L << keys.dk_log2_size
+
 cdef inline int DK_IXSIZE(MyPyDictKeysObject *keys):
-    cdef Py_ssize_t s = keys.dk_size
-    if s <= 0xff:
+    cdef uint8_t s = keys.dk_log2_size
+    if s <= 7:
         return 1
-    elif s <= 0xffff:
+    if s <= 15:
         return 2
-    elif s <= 0xffffffff:
+    if sizeof(void *) <= 4 or s <= 31:
         return 4
     else:
         return 8
 
 cdef inline PyDictKeyEntry * DK_ENTRIES(MyPyDictKeysObject *keys):
-    return <PyDictKeyEntry*> &(keys.dk_indices.as_1[keys.dk_size * DK_IXSIZE(keys)])
+    return <PyDictKeyEntry*> &(keys.dk_indices.as_1[1UL << keys.dk_log2_index_bytes])
+
+cdef inline PyDictUnicodeEntry * DK_UNICODE_ENTRIES(MyPyDictKeysObject *keys):
+    return <PyDictUnicodeEntry*> &(keys.dk_indices.as_1[1UL << keys.dk_log2_index_bytes])
+
+cdef inline bint DK_IS_UNICODE(MyPyDictKeysObject *keys):
+    return keys.dk_kind != DICT_KEYS_GENERAL
 
 cdef inline Py_ssize_t dk_get_index(MyPyDictKeysObject *keys, Py_ssize_t i):
-    cdef Py_ssize_t s = keys.dk_size
-    if s <= 0xff:
+    cdef uint8_t s = keys.dk_log2_size
+    if s < 8:
         return keys.dk_indices.as_1[i]
-    elif s <= 0xffff:
+    elif s < 16:
         return keys.dk_indices.as_2[i]
-    elif s <= 0xffffffff:
+    elif sizeof(void *) <= 4 or s < 32:
         return keys.dk_indices.as_4[i]
     else:
         return keys.dk_indices.as_8[i]
 
 cdef inline void dk_set_index(MyPyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix):
-    cdef Py_ssize_t s = keys.dk_size
-    if s <= 0xff:
+    cdef uint8_t s = keys.dk_log2_size
+    if s < 8:
         keys.dk_indices.as_1[i] = ix
-    elif s <= 0xffff:
+    elif s < 16:
         keys.dk_indices.as_2[i] = ix
-    elif s <= 0xffffffff:
+    elif sizeof(void *) <= 4 or s < 32:
         keys.dk_indices.as_4[i] = ix
     else:
         keys.dk_indices.as_8[i] = ix
@@ -113,22 +132,7 @@ cdef inline void dk_set_index(MyPyDictKe
 #End of replication of Object/dictobject.c
 ######
 
-cdef dict_lookup_func lookdict
-
-cdef dict_lookup_func DK_LOOKUP(PyDictObject *mp):
-    return (<MyPyDictKeysObject *>(mp.ma_keys)).dk_lookup
-
-def init_lookdict():
-    global lookdict
-    # A dict which a non-string key uses the generic "lookdict"
-    # as lookup function
-    cdef object D = {}
-    D[0] = 0
-    lookdict = DK_LOOKUP(<PyDictObject *>D)
-
-init_lookdict()
-
-cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_t hash) except -1:
+cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_t hashval) except -1:
     """
     This is used in callbacks for the weak values of :class:`WeakValueDictionary`.
 
@@ -179,47 +183,72 @@ cdef int del_dictitem_by_exact_value(PyD
     """
     keys = <MyPyDictKeysObject *>(mp.ma_keys)
     cdef size_t perturb
-    cdef size_t mask = <size_t> keys.dk_size-1
-    cdef PyDictKeyEntry *entries = DK_ENTRIES(keys)
+    cdef size_t mask = <size_t> DK_SIZE(keys)-1
+    cdef PyDictUnicodeEntry *uc_entries
+    cdef PyDictUnicodeEntry *uc_ep
+    cdef PyDictKeyEntry *entries
     cdef PyDictKeyEntry *ep
-
+ 
     if mp.ma_values is not NULL:
         raise TypeError("del_dictitem_by_exact_value cannot be applied to a shared key dict")
 
-    cdef size_t i = <size_t>hash & mask
+    cdef size_t i = <size_t>hashval & mask
     ix = dk_get_index(keys, i)
 
     if ix == DKIX_EMPTY:
         # key not found
         return 0
 
-    ep = &(entries[ix])
-    perturb = hash
-    while (ep.me_value != value or ep.me_hash != hash):
-        perturb = perturb >> 5 #this is the value of PERTURB_SHIFT
-        i = mask & (i * 5 + perturb + 1)
-        ix = dk_get_index(keys, i)
-        if ix == DKIX_EMPTY:
-            # key not found
-            return 0
-        ep = &(entries[ix])
+    if DK_IS_UNICODE(keys):
+        uc_entries = DK_UNICODE_ENTRIES(keys)
+        uc_ep = &(uc_entries[ix])
+        perturb = hashval
+        while (uc_ep.me_value != value or hash(<object>uc_ep.me_key) != hashval):
+            perturb = perturb >> 5 #this is the value of PERTURB_SHIFT
+            i = mask & (i * 5 + perturb + 1)
+            ix = dk_get_index(keys, i)
+            if ix == DKIX_EMPTY:
+                # key not found
+                return 0
+            uc_ep = &(uc_entries[ix])
 
-    # We need the lookup function to be the generic lookdict, otherwise
-    # deletions may not work correctly
-    keys.dk_lookup = lookdict
+        T = PyList_New(2)
+        PyList_SetItem(T, 0, uc_ep.me_key)
+        PyList_SetItem(T, 1, uc_ep.me_value)
+        uc_ep.me_key = NULL
+        uc_ep.me_value = NULL
+        mp.ma_used -= 1
+        dk_set_index(keys, i, DKIX_DUMMY)
+        #We have transferred the to-be-deleted references to the list T
+        #we now delete the list so that the actual decref happens through a
+        #deallocation routine that uses the Python Trashcan macros to
+        #avoid stack overflow in deleting deep structures.
+        del T
+    else:
+        entries = DK_ENTRIES(keys)
+        ep = &(entries[ix])
+        perturb = hashval
+        while (ep.me_value != value or ep.me_hash != hashval):
+            perturb = perturb >> 5 #this is the value of PERTURB_SHIFT
+            i = mask & (i * 5 + perturb + 1)
+            ix = dk_get_index(keys, i)
+            if ix == DKIX_EMPTY:
+                # key not found
+                return 0
+            ep = &(entries[ix])
 
-    T = PyList_New(2)
-    PyList_SetItem(T, 0, ep.me_key)
-    PyList_SetItem(T, 1, ep.me_value)
-    ep.me_key = NULL
-    ep.me_value = NULL
-    mp.ma_used -= 1
-    dk_set_index(keys, i, DKIX_DUMMY)
-    #We have transferred the to-be-deleted references to the list T
-    #we now delete the list so that the actual decref happens through a
-    #deallocation routine that uses the Python Trashcan macros to
-    #avoid stack overflow in deleting deep structures.
-    del T
+        T = PyList_New(2)
+        PyList_SetItem(T, 0, ep.me_key)
+        PyList_SetItem(T, 1, ep.me_value)
+        ep.me_key = NULL
+        ep.me_value = NULL
+        mp.ma_used -= 1
+        dk_set_index(keys, i, DKIX_DUMMY)
+        #We have transferred the to-be-deleted references to the list T
+        #we now delete the list so that the actual decref happens through a
+        #deallocation routine that uses the Python Trashcan macros to
+        #avoid stack overflow in deleting deep structures.
+        del T
 
 def test_del_dictitem_by_exact_value(D, value, h):
     """
diff -up src/sage/libs/gmp/pylong.pyx.orig src/sage/libs/gmp/pylong.pyx
--- src/sage/libs/gmp/pylong.pyx.orig	2022-05-15 16:11:11.000000000 -0600
+++ src/sage/libs/gmp/pylong.pyx	2022-06-29 12:44:27.983218616 -0600
@@ -33,6 +33,7 @@ from .mpz cimport *
 
 cdef extern from *:
     Py_ssize_t* Py_SIZE_PTR "&Py_SIZE"(object)
+    void __Pyx_SET_SIZE(object, Py_ssize_t)
     int hash_bits """
         #ifdef _PyHASH_BITS
         _PyHASH_BITS         /* Python 3 */
@@ -57,10 +58,8 @@ cdef mpz_get_pylong_large(mpz_srcptr z):
     mpz_export(L.ob_digit, NULL,
             -1, sizeof(digit), 0, PyLong_nails, z)
     if mpz_sgn(z) < 0:
-        # Set correct size (use a pointer to hack around Cython's
-        # non-support for lvalues).
-        sizeptr = Py_SIZE_PTR(L)
-        sizeptr[0] = -pylong_size
+        # Set correct size
+        __Pyx_SET_SIZE(L, -pylong_size)
     return L
 
 
diff -up src/sage/misc/decorators.py.orig src/sage/misc/decorators.py
--- src/sage/misc/decorators.py.orig	2022-05-15 16:11:11.000000000 -0600
+++ src/sage/misc/decorators.py	2022-06-29 14:02:56.995436952 -0600
@@ -31,8 +31,7 @@ from functools import (partial, update_w
 from copy import copy
 
 from sage.misc.sageinspect import (sage_getsource, sage_getsourcelines,
-                                   sage_getargspec)
-from inspect import ArgSpec
+                                   sage_getargspec, ArgSpec)
 
 
 def sage_wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES):
diff -up src/sage/misc/sageinspect.py.orig src/sage/misc/sageinspect.py
--- src/sage/misc/sageinspect.py.orig	2022-05-15 16:11:11.000000000 -0600
+++ src/sage/misc/sageinspect.py	2022-06-29 14:07:56.804147321 -0600
@@ -119,6 +119,7 @@ import functools
 import os
 import tokenize
 import re
+from collections import namedtuple
 from sage.env import SAGE_LIB
 
 try:
@@ -126,6 +127,8 @@ try:
 except ImportError:
     pass
 
+ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
+
 
 def is_function_or_cython_function(obj):
     """
@@ -348,7 +351,7 @@ def _extract_embedded_signature(docstrin
         docstring = L[1] if len(L) > 1 else ''  # Remove first line, keep the rest
         def_string = "def " + name + signature + ": pass"
         try:
-            return docstring, inspect.ArgSpec(*_sage_getargspec_cython(def_string))
+            return docstring, ArgSpec(*_sage_getargspec_cython(def_string))
         except SyntaxError:
             docstring = os.linesep.join(L)
     return docstring, None
@@ -1092,7 +1095,7 @@ def _sage_getargspec_from_ast(source):
 
     OUTPUT:
 
-    - an instance of :obj:`inspect.ArgSpec`, i.e., a named tuple
+    - an instance of :obj:`ArgSpec`, i.e., a named tuple
 
     EXAMPLES::
 
@@ -1124,8 +1127,7 @@ def _sage_getargspec_from_ast(source):
     vararg = getattr(ast_args.vararg, 'arg', None)
     kwarg = getattr(ast_args.kwarg, 'arg', None)
 
-    return inspect.ArgSpec(args, vararg, kwarg,
-                           tuple(defaults) if defaults else None)
+    return ArgSpec(args, vararg, kwarg, tuple(defaults) if defaults else None)
 
 
 def _sage_getargspec_cython(source):
@@ -1141,7 +1143,7 @@ def _sage_getargspec_cython(source):
 
     OUTPUT:
 
-    - an instance of :obj:`inspect.ArgSpec`, i.e., a named tuple
+    - an instance of :obj:`ArgSpec`, i.e., a named tuple
 
     EXAMPLES::
 
@@ -1605,11 +1607,11 @@ def sage_getargspec(obj):
         return sage_getargspec(obj.__call__)
     if isinstance(obj, (lazy_attribute, AbstractMethod)):
         source = sage_getsource(obj)
-        return inspect.ArgSpec(*_sage_getargspec_cython(source))
+        return ArgSpec(*_sage_getargspec_cython(source))
     if not callable(obj):
         raise TypeError("obj is not a code object")
     try:
-        return inspect.ArgSpec(*obj._sage_argspec_())
+        return ArgSpec(*obj._sage_argspec_())
     except (AttributeError, TypeError):
         pass
     # If we are lucky, the function signature is embedded in the docstring.
@@ -1625,7 +1627,7 @@ def sage_getargspec(obj):
         # Note that this may give a wrong result for the constants!
         try:
             args, varargs, varkw = inspect.getargs(obj.__code__)
-            return inspect.ArgSpec(args, varargs, varkw, obj.__defaults__)
+            return ArgSpec(args, varargs, varkw, obj.__defaults__)
         except (TypeError, AttributeError):
             pass
     if isclassinstance(obj):
@@ -1660,7 +1662,7 @@ def sage_getargspec(obj):
         except TypeError: # happens for Python builtins
             source = ''
         if source:
-            return inspect.ArgSpec(*_sage_getargspec_cython(source))
+            return ArgSpec(*_sage_getargspec_cython(source))
         else:
             func_obj = obj
 
@@ -1673,7 +1675,7 @@ def sage_getargspec(obj):
         except TypeError: # arg is not a code object
             # The above "hopefully" was wishful thinking:
             try:
-                return inspect.ArgSpec(*_sage_getargspec_cython(sage_getsource(obj)))
+                return ArgSpec(*_sage_getargspec_cython(sage_getsource(obj)))
             except TypeError: # This happens for Python builtins
                 # The best we can do is to return a generic argspec
                 args = []
@@ -1683,7 +1685,7 @@ def sage_getargspec(obj):
         defaults = func_obj.__defaults__
     except AttributeError:
         defaults = None
-    return inspect.ArgSpec(args, varargs, varkw, defaults)
+    return ArgSpec(args, varargs, varkw, defaults)
 
 
 def formatannotation(annotation, base_module=None):
@@ -1754,19 +1756,7 @@ def sage_formatargspec(args, varargs=Non
     :func:`sage_getargspec`. Since :func:`sage_getargspec` works for
     Cython functions while Python's inspect module does not, it makes
     sense to keep this function for formatting instances of
-    ``inspect.ArgSpec``.
-
-    EXAMPLES::
-
-        sage: from sage.misc.sageinspect import sage_formatargspec
-        sage: from inspect import formatargspec # deprecated in Python 3
-        sage: args = ['a', 'b', 'c']
-        sage: defaults = [3]
-        sage: sage_formatargspec(args, defaults=defaults)
-        '(a, b, c=3)'
-        sage: import warnings; warnings.simplefilter('ignore')  # ignore DeprecationWarning
-        sage: formatargspec(args, defaults=defaults) == sage_formatargspec(args, defaults=defaults)
-        True
+    ``ArgSpec``.
     """
     def formatargandannotation(arg):
         result = formatarg(arg)
diff -up src/sage/symbolic/ginac/numeric.cpp.orig src/sage/symbolic/ginac/numeric.cpp
--- src/sage/symbolic/ginac/numeric.cpp.orig	2022-05-15 16:11:11.000000000 -0600
+++ src/sage/symbolic/ginac/numeric.cpp	2022-06-24 14:58:32.506790725 -0600
@@ -52,7 +52,6 @@
 #define register
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
-#include <longintrepr.h>
 #include "flint/fmpz.h"
 #include "flint/fmpz_factor.h"