Skip to content

Commit

Permalink
Merge branch 'small_int_immortal_v2_tst' of github.com:eendebakpt/cpy…
Browse files Browse the repository at this point in the history
…thon into small_int_immortal_v2_tst
  • Loading branch information
eendebakpt committed Dec 23, 2024
2 parents 58e9951 + 25cd2ea commit 6d535bd
Show file tree
Hide file tree
Showing 46 changed files with 1,817 additions and 1,152 deletions.
1 change: 1 addition & 0 deletions .github/workflows/reusable-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
brew link --overwrite tcl-tk@8
- name: Configure CPython
run: |
MACOSX_DEPLOYMENT_TARGET=10.15 \
GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \
GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \
./configure \
Expand Down
26 changes: 18 additions & 8 deletions Doc/library/enum.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ Module Contents
``KEEP`` which allows for more fine-grained control over how invalid values
are dealt with in an enumeration.

:class:`EnumDict`

A subclass of :class:`dict` for use when subclassing :class:`EnumType`.

:class:`auto`

Instances are replaced with an appropriate value for Enum members.
Expand Down Expand Up @@ -149,14 +153,10 @@ Module Contents

Return a list of all power-of-two integers contained in a flag.

:class:`EnumDict`

A subclass of :class:`dict` for use when subclassing :class:`EnumType`.


.. versionadded:: 3.6 ``Flag``, ``IntFlag``, ``auto``
.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``ReprEnum``, ``FlagBoundary``, ``property``, ``member``, ``nonmember``, ``global_enum``, ``show_flag_values``
.. versionadded:: 3.14 ``EnumDict``
.. versionadded:: 3.13 ``EnumDict``

---------------

Expand Down Expand Up @@ -830,13 +830,23 @@ Data Types

.. class:: EnumDict

*EnumDict* is a subclass of :class:`dict` for use when subclassing :class:`EnumType`.
*EnumDict* is a subclass of :class:`dict` that is used as the namespace
for defining enum classes (see :ref:`prepare`).
It is exposed to allow subclasses of :class:`EnumType` with advanced
behavior like having multiple values per member.
It should be called with the name of the enum class being created, otherwise
private names and internal classes will not be handled correctly.

Note that only the :class:`~collections.abc.MutableMapping` interface
(:meth:`~object.__setitem__` and :meth:`~dict.update`) is overridden.
It may be possible to bypass the checks using other :class:`!dict`
operations like :meth:`|= <object.__ior__>`.

.. attribute:: EnumDict.member_names

Return list of member names.
A list of member names.

.. versionadded:: 3.14
.. versionadded:: 3.13

---------------

Expand Down
7 changes: 5 additions & 2 deletions Doc/reference/compound_stmts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -534,15 +534,18 @@ is semantically equivalent to::
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False

try:
TARGET = value
SUITE
except:
hit_except = True
if not exit(manager, *sys.exc_info()):
raise
else:
exit(manager, None, None, None)
finally:
if not hit_except:
exit(manager, None, None, None)

With more than one item, the context managers are processed as if multiple
:keyword:`with` statements were nested::
Expand Down
2 changes: 1 addition & 1 deletion Doc/tutorial/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ Now what can we do with instance objects? The only operations understood by
instance objects are attribute references. There are two kinds of valid
attribute names: data attributes and methods.

*data attributes* correspond to "instance variables" in Smalltalk, and to "data
*Data attributes* correspond to "instance variables" in Smalltalk, and to "data
members" in C++. Data attributes need not be declared; like local variables,
they spring into existence when they are first assigned to. For example, if
``x`` is the instance of :class:`!MyClass` created above, the following piece of
Expand Down
6 changes: 4 additions & 2 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -879,11 +879,13 @@ email
(Contributed by Thomas Dwyer and Victor Stinner for :gh:`102988` to improve
the :cve:`2023-27043` fix.)


enum
----

* :class:`~enum.EnumDict` has been made public in :mod:`enum` to better support
subclassing :class:`~enum.EnumType`.
* :class:`~enum.EnumDict` has been made public to better support subclassing
:class:`~enum.EnumType`.


fractions
---------
Expand Down
6 changes: 6 additions & 0 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ extern "C" {
#include "pycore_optimizer.h" // _PyOptimizerObject
#include "pycore_obmalloc.h" // struct _obmalloc_state
#include "pycore_qsbr.h" // struct _qsbr_state
#include "pycore_stackref.h" // Py_STACKREF_DEBUG
#include "pycore_tstate.h" // _PyThreadStateImpl
#include "pycore_tuple.h" // struct _Py_tuple_state
#include "pycore_uniqueid.h" // struct _Py_unique_id_pool
Expand Down Expand Up @@ -285,6 +286,11 @@ struct _is {
_PyThreadStateImpl _initial_thread;
// _initial_thread should be the last field of PyInterpreterState.
// See https://github.com/python/cpython/issues/127117.

#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG)
uint64_t next_stackref;
_Py_hashtable_t *stackref_debug_table;
#endif
};


Expand Down
3 changes: 2 additions & 1 deletion Include/internal/pycore_magic_number.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ Known values:
Python 3.14a1 3607 (Add pseudo instructions JUMP_IF_TRUE/FALSE)
Python 3.14a1 3608 (Add support for slices)
Python 3.14a2 3609 (Add LOAD_SMALL_INT and LOAD_CONST_IMMORTAL instructions, remove RETURN_CONST)
Python 3.14a3 3610 (Add NOT_TAKEN instruction)
(3610 accidentally omitted)
Python 3.14a4 3611 (Add NOT_TAKEN instruction)
Python 3.15 will start with 3650
Expand Down
113 changes: 113 additions & 0 deletions Include/internal/pycore_stackref.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
extern "C" {
#endif

// Define this to get precise tracking of stackrefs.
// #define Py_STACKREF_DEBUG 1

#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif
Expand Down Expand Up @@ -49,6 +52,113 @@ extern "C" {
CPython refcounting operations on it!
*/


#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG)



typedef union _PyStackRef {
uint64_t index;
} _PyStackRef;

#define Py_TAG_BITS 0

PyAPI_FUNC(PyObject *) _Py_stackref_get_object(_PyStackRef ref);
PyAPI_FUNC(PyObject *) _Py_stackref_close(_PyStackRef ref);
PyAPI_FUNC(_PyStackRef) _Py_stackref_create(PyObject *obj, const char *filename, int linenumber);
PyAPI_FUNC(void) _Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber);
extern void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref);

static const _PyStackRef PyStackRef_NULL = { .index = 0 };

#define PyStackRef_None ((_PyStackRef){ .index = 1 } )
#define PyStackRef_False ((_PyStackRef){ .index = 2 })
#define PyStackRef_True ((_PyStackRef){ .index = 3 })

#define LAST_PREDEFINED_STACKREF_INDEX 3

static inline int
PyStackRef_IsNull(_PyStackRef ref)
{
return ref.index == 0;
}

static inline int
PyStackRef_IsTrue(_PyStackRef ref)
{
return _Py_stackref_get_object(ref) == Py_True;
}

static inline int
PyStackRef_IsFalse(_PyStackRef ref)
{
return _Py_stackref_get_object(ref) == Py_False;
}

static inline int
PyStackRef_IsNone(_PyStackRef ref)
{
return _Py_stackref_get_object(ref) == Py_None;
}

static inline PyObject *
_PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumber)
{
_Py_stackref_record_borrow(ref, filename, linenumber);
return _Py_stackref_get_object(ref);
}

#define PyStackRef_AsPyObjectBorrow(REF) _PyStackRef_AsPyObjectBorrow((REF), __FILE__, __LINE__)

static inline PyObject *
PyStackRef_AsPyObjectSteal(_PyStackRef ref)
{
return _Py_stackref_close(ref);
}

static inline _PyStackRef
_PyStackRef_FromPyObjectNew(PyObject *obj, const char *filename, int linenumber)
{
Py_INCREF(obj);
return _Py_stackref_create(obj, filename, linenumber);
}
#define PyStackRef_FromPyObjectNew(obj) _PyStackRef_FromPyObjectNew(_PyObject_CAST(obj), __FILE__, __LINE__)

static inline _PyStackRef
_PyStackRef_FromPyObjectSteal(PyObject *obj, const char *filename, int linenumber)
{
return _Py_stackref_create(obj, filename, linenumber);
}
#define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj), __FILE__, __LINE__)

static inline _PyStackRef
_PyStackRef_FromPyObjectImmortal(PyObject *obj, const char *filename, int linenumber)
{
assert(_Py_IsImmortal(obj));
return _Py_stackref_create(obj, filename, linenumber);
}
#define PyStackRef_FromPyObjectImmortal(obj) _PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj), __FILE__, __LINE__)

static inline void
PyStackRef_CLOSE(_PyStackRef ref)
{
PyObject *obj = _Py_stackref_close(ref);
Py_DECREF(obj);
}

static inline _PyStackRef
_PyStackRef_DUP(_PyStackRef ref, const char *filename, int linenumber)
{
PyObject *obj = _Py_stackref_get_object(ref);
Py_INCREF(obj);
return _Py_stackref_create(obj, filename, linenumber);
}
#define PyStackRef_DUP(REF) _PyStackRef_DUP(REF, __FILE__, __LINE__)

#define PyStackRef_CLOSE_SPECIALIZED(stackref, dealloc) PyStackRef_CLOSE(stackref)

#else

typedef union _PyStackRef {
uintptr_t bits;
} _PyStackRef;
Expand Down Expand Up @@ -200,12 +310,15 @@ static const _PyStackRef PyStackRef_NULL = { .bits = 0 };
#define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True)
#define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False)

#endif

// Converts a PyStackRef back to a PyObject *, converting the
// stackref to a new reference.
#define PyStackRef_AsPyObjectNew(stackref) Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref))

#define PyStackRef_TYPE(stackref) Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref))


#define PyStackRef_CLEAR(op) \
do { \
_PyStackRef *_tmp_op_ptr = &(op); \
Expand Down
8 changes: 4 additions & 4 deletions InternalDocs/interpreter.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ When the interpreter's
[`PyEval_EvalCode()`](https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalCode)
function is called to execute a `CodeObject`, it constructs a [`Frame`](frames.md) and calls
[`_PyEval_EvalFrame()`](https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalCode)
to execute the code object in this frame. The frame hold the dynamic state of the
to execute the code object in this frame. The frame holds the dynamic state of the
`CodeObject`'s execution, including the instruction pointer, the globals and builtins.
It also has a reference to the `CodeObject` itself.

Expand Down Expand Up @@ -153,9 +153,9 @@ More information about the use of inline caches can be found in
Most instructions read or write some data in the form of object references (`PyObject *`).
The CPython bytecode interpreter is a stack machine, meaning that its instructions operate
by pushing data onto and popping it off the stack.
The stack is forms part of the frame for the code object. Its maximum depth is calculated
The stack forms part of the frame for the code object. Its maximum depth is calculated
by the compiler and stored in the `co_stacksize` field of the code object, so that the
stack can be pre-allocated is a contiguous array of `PyObject*` pointers, when the frame
stack can be pre-allocated as a contiguous array of `PyObject*` pointers, when the frame
is created.

The stack effects of each instruction are also exposed through the
Expand Down Expand Up @@ -462,7 +462,7 @@ set of values that allows them to:
2. Perform the operation quickly.

This requires that the set of values is chosen such that membership can be
tested quickly and that membership is sufficient to allow the operation to
tested quickly and that membership is sufficient to allow the operation to be
performed quickly.

For example, `LOAD_GLOBAL_MODULE` is specialized for `globals()`
Expand Down
10 changes: 5 additions & 5 deletions Lib/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,12 +342,13 @@ class EnumDict(dict):
EnumType will use the names found in self._member_names as the
enumeration member names.
"""
def __init__(self):
def __init__(self, cls_name=None):
super().__init__()
self._member_names = {} # use a dict -- faster look-up than a list, and keeps insertion order since 3.7
self._last_values = []
self._ignore = []
self._auto_called = False
self._cls_name = cls_name

def __setitem__(self, key, value):
"""
Expand All @@ -358,7 +359,7 @@ def __setitem__(self, key, value):
Single underscore (sunder) names are reserved.
"""
if _is_private(self._cls_name, key):
if self._cls_name is not None and _is_private(self._cls_name, key):
# do nothing, name will be a normal attribute
pass
elif _is_sunder(key):
Expand Down Expand Up @@ -406,7 +407,7 @@ def __setitem__(self, key, value):
value = value.value
elif _is_descriptor(value):
pass
elif _is_internal_class(self._cls_name, value):
elif self._cls_name is not None and _is_internal_class(self._cls_name, value):
# do nothing, name will be a normal attribute
pass
else:
Expand Down Expand Up @@ -478,8 +479,7 @@ def __prepare__(metacls, cls, bases, **kwds):
# check that previous enum members do not exist
metacls._check_for_existing_members_(cls, bases)
# create the namespace dict
enum_dict = EnumDict()
enum_dict._cls_name = cls
enum_dict = EnumDict(cls)
# inherit previous flags and _generate_next_value_ function
member_type, first_enum = metacls._get_mixins_(cls, bases)
if first_enum is not None:
Expand Down
Loading

0 comments on commit 6d535bd

Please sign in to comment.