[Python-checkins] gh-121459: Deferred LOAD_GLOBAL (GH-123128)
https://github.com/python/cpython/commit/8810e286fa48876422d1b230208911decbead294 commit: 8810e286fa48876422d1b230208911decbead294 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-09-14T00:23:51+08:00 summary: gh-121459: Deferred LOAD_GLOBAL (GH-123128) Co-authored-by: Bénédikt Tran <10796600+picn...@users.noreply.github.com> Co-authored-by: Sam Gross <655866+colesb...@users.noreply.github.com> files: M Include/internal/pycore_ceval.h M Include/internal/pycore_dict.h M Objects/dictobject.c M Python/bytecodes.c M Python/ceval.c M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/optimizer_cases.c.h diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index e4af731be0e87f..a97b53028c8f59 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -271,7 +271,7 @@ PyAPI_FUNC(PyObject **) _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_ PyAPI_FUNC(void) _PyObjectArray_Free(PyObject **array, PyObject **scratch); PyAPI_FUNC(PyObject *) _PyEval_GetANext(PyObject *aiter); -PyAPI_FUNC(PyObject *) _PyEval_LoadGlobal(PyObject *globals, PyObject *builtins, PyObject *name); +PyAPI_FUNC(void) _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject *name, _PyStackRef *writeto); PyAPI_FUNC(PyObject *) _PyEval_GetAwaitable(PyObject *iterable, int oparg); PyAPI_FUNC(PyObject *) _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *name); diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 100250928d2064..f9a043b0208c8f 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -10,6 +10,7 @@ extern "C" { #include "pycore_object.h" // PyManagedDictPointer #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_ACQUIRE +#include "pycore_stackref.h" // _PyStackRef // Unsafe flavor of PyDict_GetItemWithError(): no error checking extern PyObject* _PyDict_GetItemWithError(PyObject *dp, PyObject *key); @@ -100,10 +101,12 @@ extern void _PyDictKeys_DecRef(PyDictKeysObject *keys); */ extern Py_ssize_t _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr); extern Py_ssize_t _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr); +extern Py_ssize_t _Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr); extern Py_ssize_t _PyDict_LookupIndex(PyDictObject *, PyObject *); extern Py_ssize_t _PyDictKeys_StringLookup(PyDictKeysObject* dictkeys, PyObject *key); PyAPI_FUNC(PyObject *)_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *); +PyAPI_FUNC(void) _PyDict_LoadGlobalStackRef(PyDictObject *, PyDictObject *, PyObject *, _PyStackRef *); /* Consumes references to key and value */ PyAPI_FUNC(int) _PyDict_SetItem_Take2(PyDictObject *op, PyObject *key, PyObject *value); diff --git a/Objects/dictobject.c b/Objects/dictobject.c index b81ed189456ec1..006bc593c2a754 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1496,6 +1496,45 @@ _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyOb return ix; } +Py_ssize_t +_Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr) +{ +PyDictKeysObject *dk = _Py_atomic_load_ptr(&mp->ma_keys); +if (dk->dk_kind == DICT_KEYS_UNICODE && PyUnicode_CheckExact(key)) { +Py_ssize_t ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash); +if (ix == DKIX_EMPTY) { +*value_addr = PyStackRef_NULL; +return ix; +} +else if (ix >= 0) { +PyObject **addr_of_value = &DK_UNICODE_ENTRIES(dk)[ix].me_value; +PyObject *value = _Py_atomic_load_ptr(addr_of_value); +if (value == NULL) { +*value_addr = PyStackRef_NULL; +return DKIX_EMPTY; +} +if (_Py_IsImmortal(value) || _PyObject_HasDeferredRefcount(value)) { +*value_addr = (_PyStackRef){ .bits = (uintptr_t)value | Py_TAG_DEFERRED }; +return ix; +} +if (_Py_TryIncrefCompare(addr_of_value, value)) { +*value_addr = PyStackRef_FromPyObjectSteal(value); +return ix; +} +} +} + +PyObject *obj; +Py_ssize_t ix = _Py_dict_lookup_threadsafe(mp, key, hash, &obj); +if (ix >= 0 && obj != NULL) { +*value_addr = PyStackRef_FromPyObjectSteal(obj); +} +else { +*value_addr = PyStackRef_NULL; +} +return ix; +} + #else // Py_GIL_DISABLED Py_ssize_t @@ -1506,6 +1545,15 @@ _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyOb return ix; } +Py_ssize_t +_Py_d
[Python-checkins] gh-119258: Eliminate Type Guards in Tier 2 Optimizer with Watcher (GH-119365)
https://github.com/python/cpython/commit/55402d3232ca400ebafe4fe3bd70f252304ebe07 commit: 55402d3232ca400ebafe4fe3bd70f252304ebe07 branch: main author: Saul Shanabrook committer: Fidget-Spinner date: 2024-06-08T17:41:45+08:00 summary: gh-119258: Eliminate Type Guards in Tier 2 Optimizer with Watcher (GH-119365) Co-authored-by: parmeggiani Co-authored-by: dpdani Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Brandt Bucher Co-authored-by: Ken Jin files: A Misc/NEWS.d/next/Core and Builtins/2024-05-23-20-17-37.gh-issue-119258.wZFIpt.rst M Include/internal/pycore_optimizer.h M Include/internal/pycore_typeobject.h M Lib/test/test_capi/test_opt.py M Lib/test/test_capi/test_watchers.py M Lib/test/test_type_cache.py M Modules/_testcapimodule.c M Modules/_testinternalcapi.c M Objects/typeobject.c M Python/optimizer_analysis.c M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h M Python/optimizer_symbols.c diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 76123987ac99f5..fd7833fd231299 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -33,6 +33,7 @@ struct _Py_UopsSymbol { int flags; // 0 bits: Top; 2 or more bits: Bottom PyTypeObject *typ; // Borrowed reference PyObject *const_val; // Owned reference (!) +unsigned int type_version; // currently stores type version }; #define UOP_FORMAT_TARGET 0 @@ -123,9 +124,11 @@ extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *con extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx); extern bool _Py_uop_sym_has_type(_Py_UopsSymbol *sym); extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ); +extern bool _Py_uop_sym_matches_type_version(_Py_UopsSymbol *sym, unsigned int version); extern void _Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym); extern void _Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym); extern void _Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyTypeObject *typ); +extern bool _Py_uop_sym_set_type_version(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, unsigned int version); extern void _Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyObject *const_val); extern bool _Py_uop_sym_is_bottom(_Py_UopsSymbol *sym); extern int _Py_uop_sym_truthiness(_Py_UopsSymbol *sym); @@ -138,9 +141,9 @@ extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx); extern _Py_UOpsAbstractFrame *_Py_uop_frame_new( _Py_UOpsContext *ctx, PyCodeObject *co, -_Py_UopsSymbol **localsplus_start, -int n_locals_already_filled, -int curr_stackentries); +int curr_stackentries, +_Py_UopsSymbol **args, +int arg_len); extern int _Py_uop_frame_pop(_Py_UOpsContext *ctx); PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored); diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 8664ae0e44533f..bc295b1b066bd1 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -63,6 +63,8 @@ typedef struct { PyObject *tp_weaklist; } managed_static_type_state; +#define TYPE_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ + struct types_state { /* Used to set PyTypeObject.tp_version_tag. It starts at _Py_MAX_GLOBAL_TYPE_VERSION_TAG + 1, @@ -118,6 +120,12 @@ struct types_state { managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_EXT_TYPES]; } for_extensions; PyMutex mutex; + +// Borrowed references to type objects whose +// tp_version_tag % TYPE_VERSION_CACHE_SIZE +// once was equal to the index in the table. +// They are cleared when the type object is deallocated. +PyTypeObject *type_version_cache[TYPE_VERSION_CACHE_SIZE]; }; @@ -230,6 +238,9 @@ extern void _PyType_SetFlags(PyTypeObject *self, unsigned long mask, extern void _PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long flags); +extern unsigned int _PyType_GetVersionForCurrentState(PyTypeObject *tp); +PyAPI_FUNC(void) _PyType_SetVersion(PyTypeObject *tp, unsigned int version); +PyTypeObject *_PyType_LookupByVersion(unsigned int version); #ifdef __cplusplus } diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 0491ff9b84d486..fc6d8b0a3f01d2 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1333,6 +1333,153 @@ def test_modified_local_is_seen_by_optimized_code(self): self.assertIs(type(s), float) self.assertEqual(s, 1024.0) +def test_guard_type_version_removed(self): +def thing(a): +x = 0 +for _ in range(100): +x += a.attr +x += a.attr +return x + +
[Python-checkins] gh-117657: Make Py_TYPE and Py_SET_TYPE thread safe (GH-120165)
https://github.com/python/cpython/commit/e16aed63f64b18a26859eff3de976ded373e66b8 commit: e16aed63f64b18a26859eff3de976ded373e66b8 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-06-12T20:41:07+08:00 summary: gh-117657: Make Py_TYPE and Py_SET_TYPE thread safe (GH-120165) Co-authored-by: Bénédikt Tran <10796600+picn...@users.noreply.github.com> Co-authored-by: Nadeshiko Manju files: M Include/internal/pycore_interp.h M Include/object.h M Lib/test/test_free_threading/test_type.py M Objects/typeobject.c M Tools/tsan/suppressions_free_threading.txt diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 86dada5061e7b5..6b5f50b88f7b85 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -401,7 +401,10 @@ PyAPI_FUNC(PyStatus) _PyInterpreterState_New( #define RARE_EVENT_INTERP_INC(interp, name) \ do { \ /* saturating add */ \ -if (interp->rare_events.name < UINT8_MAX) interp->rare_events.name++; \ +int val = FT_ATOMIC_LOAD_UINT8_RELAXED(interp->rare_events.name); \ +if (val < UINT8_MAX) { \ +FT_ATOMIC_STORE_UINT8(interp->rare_events.name, val + 1); \ +} \ RARE_EVENT_STAT_INC(name); \ } while (0); \ diff --git a/Include/object.h b/Include/object.h index c8c63b9b2b1450..4a39ada8c7daa4 100644 --- a/Include/object.h +++ b/Include/object.h @@ -246,7 +246,11 @@ _Py_IsOwnedByCurrentThread(PyObject *ob) // bpo-39573: The Py_SET_TYPE() function must be used to set an object type. static inline PyTypeObject* Py_TYPE(PyObject *ob) { +#ifdef Py_GIL_DISABLED +return (PyTypeObject *)_Py_atomic_load_ptr_relaxed(&ob->ob_type); +#else return ob->ob_type; +#endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b # define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob)) @@ -274,7 +278,11 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { +#ifdef Py_GIL_DISABLED +_Py_atomic_store_ptr(&ob->ob_type, type); +#else ob->ob_type = type; +#endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b # define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 786336fa0cddce..1e84b2db2d4882 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -96,6 +96,32 @@ def reader_func(): self.run_one(writer_func, reader_func) +def test___class___modification(self): +class Foo: +pass + +class Bar: +pass + +thing = Foo() +def work(): +foo = thing +for _ in range(1): +foo.__class__ = Bar +type(foo) +foo.__class__ = Foo +type(foo) + + +threads = [] +for i in range(NTHREADS): +thread = threading.Thread(target=work) +thread.start() +threads.append(thread) + +for thread in threads: +thread.join() + def run_one(self, writer_func, reader_func): writer = Thread(target=writer_func) readers = [] diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 070e3d2f7bf2b4..8ecab555454cdc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6633,9 +6633,15 @@ object_set_class(PyObject *self, PyObject *value, void *closure) if (newto->tp_flags & Py_TPFLAGS_HEAPTYPE) { Py_INCREF(newto); } +Py_BEGIN_CRITICAL_SECTION(self); +// The real Py_TYPE(self) (`oldto`) may have changed from +// underneath us in another thread, so we re-fetch it here. +oldto = Py_TYPE(self); Py_SET_TYPE(self, newto); -if (oldto->tp_flags & Py_TPFLAGS_HEAPTYPE) +Py_END_CRITICAL_SECTION(); +if (oldto->tp_flags & Py_TPFLAGS_HEAPTYPE) { Py_DECREF(oldto); +} RARE_EVENT_INC(set_class); return 0; diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index cb48a30751ac7b..b10b297f50da81 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -37,7 +37,6 @@ race_top:set_contains_key # https://gist.github.com/colesbury/d13d033f413b4ad07929d044bed86c35 race_top:set_discard_entry race_top:set_inheritable -race_top:Py_SET_TYPE race_top:_PyDict_CheckConsistency race_top:_Py_dict_lookup_threadsafe race_top:_multiprocessing_SemLock_acquire_impl @@ -58,7 +57,6 @@ race_top:_PyFrame_Initialize race_top:PyInterpreterState_ThreadHead race_top:_PyObject_TryGetInstanceAttribute race_top:PyThreadState_Next -race_top:Py_TYPE race_top:PyUnstable_Inter
[Python-checkins] [3.13] gh-117657: Make Py_TYPE and Py_SET_TYPE thread safe (GH-120165) (GH-120403)
https://github.com/python/cpython/commit/91cd22a36119c83c9a21bfe0efe39d745086 commit: 91cd22a36119c83c9a21bfe0efe39d745086 branch: 3.13 author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com> committer: Fidget-Spinner date: 2024-06-12T21:37:26+08:00 summary: [3.13] gh-117657: Make Py_TYPE and Py_SET_TYPE thread safe (GH-120165) (GH-120403) gh-117657: Make Py_TYPE and Py_SET_TYPE thread safe (GH-120165) (cherry picked from commit e16aed63f64b18a26859eff3de976ded373e66b8) Co-authored-by: Ken Jin Co-authored-by: Bénédikt Tran <10796600+picn...@users.noreply.github.com> Co-authored-by: Nadeshiko Manju files: M Include/internal/pycore_interp.h M Include/object.h M Lib/test/test_free_threading/test_type.py M Objects/typeobject.c M Tools/tsan/suppressions_free_threading.txt diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 86dada5061e7b5..6b5f50b88f7b85 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -401,7 +401,10 @@ PyAPI_FUNC(PyStatus) _PyInterpreterState_New( #define RARE_EVENT_INTERP_INC(interp, name) \ do { \ /* saturating add */ \ -if (interp->rare_events.name < UINT8_MAX) interp->rare_events.name++; \ +int val = FT_ATOMIC_LOAD_UINT8_RELAXED(interp->rare_events.name); \ +if (val < UINT8_MAX) { \ +FT_ATOMIC_STORE_UINT8(interp->rare_events.name, val + 1); \ +} \ RARE_EVENT_STAT_INC(name); \ } while (0); \ diff --git a/Include/object.h b/Include/object.h index 9132784628a501..a687bf2f7cdd74 100644 --- a/Include/object.h +++ b/Include/object.h @@ -331,7 +331,11 @@ static inline Py_ssize_t Py_REFCNT(PyObject *ob) { // bpo-39573: The Py_SET_TYPE() function must be used to set an object type. static inline PyTypeObject* Py_TYPE(PyObject *ob) { +#ifdef Py_GIL_DISABLED +return (PyTypeObject *)_Py_atomic_load_ptr_relaxed(&ob->ob_type); +#else return ob->ob_type; +#endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b # define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob)) @@ -421,7 +425,11 @@ static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { +#ifdef Py_GIL_DISABLED +_Py_atomic_store_ptr(&ob->ob_type, type); +#else ob->ob_type = type; +#endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b # define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 786336fa0cddce..1e84b2db2d4882 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -96,6 +96,32 @@ def reader_func(): self.run_one(writer_func, reader_func) +def test___class___modification(self): +class Foo: +pass + +class Bar: +pass + +thing = Foo() +def work(): +foo = thing +for _ in range(1): +foo.__class__ = Bar +type(foo) +foo.__class__ = Foo +type(foo) + + +threads = [] +for i in range(NTHREADS): +thread = threading.Thread(target=work) +thread.start() +threads.append(thread) + +for thread in threads: +thread.join() + def run_one(self, writer_func, reader_func): writer = Thread(target=writer_func) readers = [] diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2d001b76e09775..eec25b0afaa86d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6474,9 +6474,15 @@ object_set_class(PyObject *self, PyObject *value, void *closure) if (newto->tp_flags & Py_TPFLAGS_HEAPTYPE) { Py_INCREF(newto); } +Py_BEGIN_CRITICAL_SECTION(self); +// The real Py_TYPE(self) (`oldto`) may have changed from +// underneath us in another thread, so we re-fetch it here. +oldto = Py_TYPE(self); Py_SET_TYPE(self, newto); -if (oldto->tp_flags & Py_TPFLAGS_HEAPTYPE) +Py_END_CRITICAL_SECTION(); +if (oldto->tp_flags & Py_TPFLAGS_HEAPTYPE) { Py_DECREF(oldto); +} RARE_EVENT_INC(set_class); return 0; diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index cb48a30751ac7b..b10b297f50da81 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -37,7 +37,6 @@ race_top:set_contains_key # https://gist.github.com/colesbury/d13d033f413b4ad07929d044bed86c35 race_top:set_discard_entry race_top:set_inheritable -race_top:Py_SET_TYPE race_top:_PyDict_CheckConsistency race_top:_Py_dict_lookup_threadsafe race_top:_multip
[Python-checkins] gh-117657: Fix some simple races in instrumentation.c (GH-120118)
https://github.com/python/cpython/commit/b1b61dc4cee43920ef2b08d5ac94ddf08119c507 commit: b1b61dc4cee43920ef2b08d5ac94ddf08119c507 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-06-13T17:31:21+08:00 summary: gh-117657: Fix some simple races in instrumentation.c (GH-120118) * stop the world when setting local events files: M Python/instrumentation.c diff --git a/Python/instrumentation.c b/Python/instrumentation.c index a5211ee5428cf8..ae790a1441b933 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1977,7 +1977,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent } int res; -LOCK_CODE(code); +_PyEval_StopTheWorld(interp); if (allocate_instrumentation_data(code)) { res = -1; goto done; @@ -1994,7 +1994,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent res = force_instrument_lock_held(code, interp); done: -UNLOCK_CODE(); +_PyEval_StartTheWorld(interp); return res; } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-117657: Make PyType_HasFeature atomic (GH-120210)
https://github.com/python/cpython/commit/eebae2c460dabdc70dc0d9b6e189368eb1abb716 commit: eebae2c460dabdc70dc0d9b6e189368eb1abb716 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-06-13T17:29:19+08:00 summary: gh-117657: Make PyType_HasFeature atomic (GH-120210) Make PyType_HasFeature atomic files: M Include/internal/pycore_object.h M Include/internal/pycore_pyatomic_ft_wrappers.h M Tools/tsan/suppressions_free_threading.txt diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 6f133014ce06e2..d1e2773a2473b0 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -262,7 +262,7 @@ extern int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, void*); // Fast inlined version of PyType_HasFeature() static inline int _PyType_HasFeature(PyTypeObject *type, unsigned long feature) { -return ((type->tp_flags & feature) != 0); +return ((FT_ATOMIC_LOAD_ULONG_RELAXED(type->tp_flags) & feature) != 0); } extern void _PyType_InitCache(PyInterpreterState *interp); diff --git a/Include/internal/pycore_pyatomic_ft_wrappers.h b/Include/internal/pycore_pyatomic_ft_wrappers.h index bc6aba56cf9fc7..a1bb383bcd22e9 100644 --- a/Include/internal/pycore_pyatomic_ft_wrappers.h +++ b/Include/internal/pycore_pyatomic_ft_wrappers.h @@ -45,6 +45,8 @@ extern "C" { _Py_atomic_load_uint16_relaxed(&value) #define FT_ATOMIC_LOAD_UINT32_RELAXED(value) \ _Py_atomic_load_uint32_relaxed(&value) +#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) \ +_Py_atomic_load_ulong_relaxed(&value) #define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) \ _Py_atomic_store_ptr_relaxed(&value, new_value) #define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) \ @@ -75,6 +77,7 @@ extern "C" { #define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value +#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) value #define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value #define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index b10b297f50da81..05ceaf438b6353 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -26,7 +26,6 @@ race:free_threadstate race_top:_add_to_weak_set race_top:_in_weak_set race_top:_PyEval_EvalFrameDefault -race_top:_PyType_HasFeature race_top:assign_version_tag race_top:insertdict race_top:lookup_tp_dict ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] [3.13] gh-117657: Fix some simple races in instrumentation.c (GH-120118) (#120444)
https://github.com/python/cpython/commit/17188270b6e6671ab721235745ad9f3ab0a7a8d8 commit: 17188270b6e6671ab721235745ad9f3ab0a7a8d8 branch: 3.13 author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com> committer: Fidget-Spinner date: 2024-06-13T18:23:19+08:00 summary: [3.13] gh-117657: Fix some simple races in instrumentation.c (GH-120118) (#120444) gh-117657: Fix some simple races in instrumentation.c (GH-120118) * stop the world when setting local events (cherry picked from commit b1b61dc4cee43920ef2b08d5ac94ddf08119c507) Co-authored-by: Ken Jin files: M Python/instrumentation.c diff --git a/Python/instrumentation.c b/Python/instrumentation.c index a5211ee5428cf8..ae790a1441b933 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1977,7 +1977,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent } int res; -LOCK_CODE(code); +_PyEval_StopTheWorld(interp); if (allocate_instrumentation_data(code)) { res = -1; goto done; @@ -1994,7 +1994,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent res = force_instrument_lock_held(code, interp); done: -UNLOCK_CODE(); +_PyEval_StartTheWorld(interp); return res; } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] [3.13] gh-117657: Make PyType_HasFeature atomic (GH-120210) (#120443)
https://github.com/python/cpython/commit/3067c62a34eb0a99a01af3e9edaaf082fb7fa0a2 commit: 3067c62a34eb0a99a01af3e9edaaf082fb7fa0a2 branch: 3.13 author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com> committer: Fidget-Spinner date: 2024-06-13T18:06:04+08:00 summary: [3.13] gh-117657: Make PyType_HasFeature atomic (GH-120210) (#120443) gh-117657: Make PyType_HasFeature atomic (GH-120210) Make PyType_HasFeature atomic (cherry picked from commit eebae2c460dabdc70dc0d9b6e189368eb1abb716) Co-authored-by: Ken Jin files: M Include/internal/pycore_object.h M Include/internal/pycore_pyatomic_ft_wrappers.h M Tools/tsan/suppressions_free_threading.txt diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 6f133014ce06e2..d1e2773a2473b0 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -262,7 +262,7 @@ extern int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, void*); // Fast inlined version of PyType_HasFeature() static inline int _PyType_HasFeature(PyTypeObject *type, unsigned long feature) { -return ((type->tp_flags & feature) != 0); +return ((FT_ATOMIC_LOAD_ULONG_RELAXED(type->tp_flags) & feature) != 0); } extern void _PyType_InitCache(PyInterpreterState *interp); diff --git a/Include/internal/pycore_pyatomic_ft_wrappers.h b/Include/internal/pycore_pyatomic_ft_wrappers.h index bc6aba56cf9fc7..a1bb383bcd22e9 100644 --- a/Include/internal/pycore_pyatomic_ft_wrappers.h +++ b/Include/internal/pycore_pyatomic_ft_wrappers.h @@ -45,6 +45,8 @@ extern "C" { _Py_atomic_load_uint16_relaxed(&value) #define FT_ATOMIC_LOAD_UINT32_RELAXED(value) \ _Py_atomic_load_uint32_relaxed(&value) +#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) \ +_Py_atomic_load_ulong_relaxed(&value) #define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) \ _Py_atomic_store_ptr_relaxed(&value, new_value) #define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) \ @@ -75,6 +77,7 @@ extern "C" { #define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value +#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) value #define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value #define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index b10b297f50da81..05ceaf438b6353 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -26,7 +26,6 @@ race:free_threadstate race_top:_add_to_weak_set race_top:_in_weak_set race_top:_PyEval_EvalFrameDefault -race_top:_PyType_HasFeature race_top:assign_version_tag race_top:insertdict race_top:lookup_tp_dict ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-117657: Add TSAN suppression for set_default_allocator_unlocked (#120500)
https://github.com/python/cpython/commit/2bacc2343c24c49292dea3461f6b7664fc2d33e2 commit: 2bacc2343c24c49292dea3461f6b7664fc2d33e2 branch: main author: AN Long committer: Fidget-Spinner date: 2024-06-15T00:10:18+08:00 summary: gh-117657: Add TSAN suppression for set_default_allocator_unlocked (#120500) Add TSAN suppression for set_default_allocator_unlocked files: M Tools/tsan/suppressions_free_threading.txt diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 05ceaf438b6353..4c8b0b8abd2963 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -63,6 +63,8 @@ race_top:tstate_is_freed race_top:type_modified_unlocked race_top:write_thread_id race_top:PyThreadState_Clear +# Only seen on macOS, sample: https://gist.github.com/aisk/dda53f5d494a4556c35dde1fce03259c +race_top:set_default_allocator_unlocked # https://gist.github.com/mpage/6962e8870606cfc960e159b407a0cb40 thread:pthread_create ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] [3.13] gh-117657: Add TSAN suppression for set_default_allocator_unlocked (GH-120500) (#120510)
https://github.com/python/cpython/commit/6e3e1124287858b6e22d10ac912e9b76afa3e41b commit: 6e3e1124287858b6e22d10ac912e9b76afa3e41b branch: 3.13 author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com> committer: Fidget-Spinner date: 2024-06-14T16:34:07Z summary: [3.13] gh-117657: Add TSAN suppression for set_default_allocator_unlocked (GH-120500) (#120510) gh-117657: Add TSAN suppression for set_default_allocator_unlocked (GH-120500) Add TSAN suppression for set_default_allocator_unlocked (cherry picked from commit 2bacc2343c24c49292dea3461f6b7664fc2d33e2) Co-authored-by: AN Long files: M Tools/tsan/suppressions_free_threading.txt diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 05ceaf438b6353..4c8b0b8abd2963 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -63,6 +63,8 @@ race_top:tstate_is_freed race_top:type_modified_unlocked race_top:write_thread_id race_top:PyThreadState_Clear +# Only seen on macOS, sample: https://gist.github.com/aisk/dda53f5d494a4556c35dde1fce03259c +race_top:set_default_allocator_unlocked # https://gist.github.com/mpage/6962e8870606cfc960e159b407a0cb40 thread:pthread_create ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-117657: Make PyType_HasFeature (exported version) atomic (#120484)
https://github.com/python/cpython/commit/6f63dfff6f493b405f3422210a168369e1e7a35d commit: 6f63dfff6f493b405f3422210a168369e1e7a35d branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-06-15T22:39:22+08:00 summary: gh-117657: Make PyType_HasFeature (exported version) atomic (#120484) Make PyType_HasFeature (exported version) atomic files: M Include/object.h M Objects/typeobject.c diff --git a/Include/object.h b/Include/object.h index 4a39ada8c7daa4..f71aaee7efe6ee 100644 --- a/Include/object.h +++ b/Include/object.h @@ -756,7 +756,11 @@ PyType_HasFeature(PyTypeObject *type, unsigned long feature) // PyTypeObject is opaque in the limited C API flags = PyType_GetFlags(type); #else -flags = type->tp_flags; +# ifdef Py_GIL_DISABLED +flags = _Py_atomic_load_ulong_relaxed(&type->tp_flags); +# else +flags = type->tp_flags; +# endif #endif return ((flags & feature) != 0); } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 98e00bd25c3205..eb296414bb7bef 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3599,7 +3599,7 @@ type_init(PyObject *cls, PyObject *args, PyObject *kwds) unsigned long PyType_GetFlags(PyTypeObject *type) { -return type->tp_flags; +return FT_ATOMIC_LOAD_ULONG_RELAXED(type->tp_flags); } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] [3.13] gh-117657: Make PyType_HasFeature (exported version) atomic (GH-120484) (#120554)
https://github.com/python/cpython/commit/cbcb5265bfaf80af386faa8858359bb6f15cb77d commit: cbcb5265bfaf80af386faa8858359bb6f15cb77d branch: 3.13 author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com> committer: Fidget-Spinner date: 2024-06-15T15:06:54Z summary: [3.13] gh-117657: Make PyType_HasFeature (exported version) atomic (GH-120484) (#120554) gh-117657: Make PyType_HasFeature (exported version) atomic (GH-120484) Make PyType_HasFeature (exported version) atomic (cherry picked from commit 6f63dfff6f493b405f3422210a168369e1e7a35d) Co-authored-by: Ken Jin files: M Include/object.h M Objects/typeobject.c diff --git a/Include/object.h b/Include/object.h index a687bf2f7cdd74..7aaa8da8e8d154 100644 --- a/Include/object.h +++ b/Include/object.h @@ -1238,7 +1238,11 @@ PyType_HasFeature(PyTypeObject *type, unsigned long feature) // PyTypeObject is opaque in the limited C API flags = PyType_GetFlags(type); #else -flags = type->tp_flags; +# ifdef Py_GIL_DISABLED +flags = _Py_atomic_load_ulong_relaxed(&type->tp_flags); +# else +flags = type->tp_flags; +# endif #endif return ((flags & feature) != 0); } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1f6c2828f1c697..1123ef6eb3d9b2 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3435,7 +3435,7 @@ type_init(PyObject *cls, PyObject *args, PyObject *kwds) unsigned long PyType_GetFlags(PyTypeObject *type) { -return type->tp_flags; +return FT_ATOMIC_LOAD_ULONG_RELAXED(type->tp_flags); } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-120437: Fix `_CHECK_STACK_SPACE` optimization problems introduced in gh-118322 (GH-120712)
https://github.com/python/cpython/commit/f385d99f57773e48285e0bcdbcd66dcbfdc647b3 commit: f385d99f57773e48285e0bcdbcd66dcbfdc647b3 branch: main author: Nadeshiko Manju committer: Fidget-Spinner date: 2024-06-19T23:34:39+08:00 summary: gh-120437: Fix `_CHECK_STACK_SPACE` optimization problems introduced in gh-118322 (GH-120712) Co-authored-by: Ken Jin files: A Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst new file mode 100644 index 00..8923f3fcefe3c1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst @@ -0,0 +1 @@ +Fix ``_CHECK_STACK_SPACE`` optimization problems introduced in :gh:`118322`. diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 35463f25246803..2ea839f5d6dc97 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -601,7 +601,6 @@ dummy_func(void) { (void)callable; (void)self_or_null; (void)args; -first_valid_check_stack = NULL; new_frame = NULL; ctx->done = true; } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 46501862ff2fb3..7274bd2a6fc02b 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1492,7 +1492,6 @@ (void)callable; (void)self_or_null; (void)args; -first_valid_check_stack = NULL; new_frame = NULL; ctx->done = true; stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame; ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] [3.13] gh-120437: Fix `_CHECK_STACK_SPACE` optimization problems introduced in gh-118322 (GH-120712) (#120747)
https://github.com/python/cpython/commit/ae04b6f63640606a3212c9da21b87ebc374136e1 commit: ae04b6f63640606a3212c9da21b87ebc374136e1 branch: 3.13 author: Nadeshiko Manju committer: Fidget-Spinner date: 2024-06-20T01:40:48+08:00 summary: [3.13] gh-120437: Fix `_CHECK_STACK_SPACE` optimization problems introduced in gh-118322 (GH-120712) (#120747) [3.13] gh-120437: Fix `_CHECK_STACK_SPACE` optimization problems introduced in gh-118322 (GH-120712) Signed-off-by: Manjusaka Co-authored-by: Ken Jin files: A Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst new file mode 100644 index 00..8923f3fcefe3c1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst @@ -0,0 +1 @@ +Fix ``_CHECK_STACK_SPACE`` optimization problems introduced in :gh:`118322`. diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 928bc03382b8fb..2d61fa3b8257f4 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -634,7 +634,6 @@ dummy_func(void) { (void)callable; (void)self_or_null; (void)args; -first_valid_check_stack = NULL; goto done; } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 6c2480d4fdfe89..621a48f2fc9105 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1565,7 +1565,6 @@ (void)callable; (void)self_or_null; (void)args; -first_valid_check_stack = NULL; goto done; stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame; stack_pointer += -1 - oparg; ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] [3.13] gh-119258: Backport optimizer frame fixes in GH-119365 (GH-120699)
https://github.com/python/cpython/commit/7c7aa5a99cce256ff726654038092a333a1f0531 commit: 7c7aa5a99cce256ff726654038092a333a1f0531 branch: 3.13 author: Ken Jin committer: Fidget-Spinner date: 2024-06-20T23:55:20+08:00 summary: [3.13] gh-119258: Backport optimizer frame fixes in GH-119365 (GH-120699) (cherry picked from commit 55402d3) files: M Include/internal/pycore_optimizer.h M Python/optimizer_analysis.c M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h M Python/optimizer_symbols.c diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index c0a76e85350541..c422e2f113d15d 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -107,9 +107,9 @@ extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx); extern _Py_UOpsAbstractFrame *_Py_uop_frame_new( _Py_UOpsContext *ctx, PyCodeObject *co, -_Py_UopsSymbol **localsplus_start, -int n_locals_already_filled, -int curr_stackentries); +int curr_stackentries, +_Py_UopsSymbol **args, +int arg_len); extern int _Py_uop_frame_pop(_Py_UOpsContext *ctx); PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 842b2e489239af..03148c23a82c46 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -411,7 +411,7 @@ optimize_uops( if (_Py_uop_abstractcontext_init(ctx) < 0) { goto out_of_space; } -_Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, co, ctx->n_consumed, 0, curr_stacklen); +_Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, co, curr_stacklen, NULL, 0); if (frame == NULL) { return -1; } diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 2d61fa3b8257f4..690c9b8bced984 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -616,17 +616,12 @@ dummy_func(void) { argcount++; } -_Py_UopsSymbol **localsplus_start = ctx->n_consumed; -int n_locals_already_filled = 0; -// Can determine statically, so we interleave the new locals -// and make the current stack the new locals. -// This also sets up for true call inlining. + if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) { -localsplus_start = args; -n_locals_already_filled = argcount; +OUT_OF_SPACE_IF_NULL(new_frame = frame_new(ctx, co, 0, args, argcount)); +} else { +OUT_OF_SPACE_IF_NULL(new_frame = frame_new(ctx, co, 0, NULL, 0)); } -OUT_OF_SPACE_IF_NULL(new_frame = - frame_new(ctx, co, localsplus_start, n_locals_already_filled, 0)); } op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 621a48f2fc9105..fb7f1edf498705 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1696,17 +1696,11 @@ args--; argcount++; } -_Py_UopsSymbol **localsplus_start = ctx->n_consumed; -int n_locals_already_filled = 0; -// Can determine statically, so we interleave the new locals -// and make the current stack the new locals. -// This also sets up for true call inlining. if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) { -localsplus_start = args; -n_locals_already_filled = argcount; +OUT_OF_SPACE_IF_NULL(new_frame = frame_new(ctx, co, 0, args, argcount)); +} else { +OUT_OF_SPACE_IF_NULL(new_frame = frame_new(ctx, co, 0, NULL, 0)); } -OUT_OF_SPACE_IF_NULL(new_frame = - frame_new(ctx, co, localsplus_start, n_locals_already_filled, 0)); stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame; stack_pointer += -1 - oparg; break; diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 4aeb04fe0405d2..e80d15b200d2f3 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -303,9 +303,9 @@ _Py_UOpsAbstractFrame * _Py_uop_frame_new( _Py_UOpsContext *ctx, PyCodeObject *co, -_Py_UopsSymbol **localsplus_start, -int n_locals_already_filled, -int curr_stackentries) +int curr_stackentries, +_Py_UopsSymbol **args, +int arg_len) { assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH); _Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth]; @@ -313,21 +313,21 @@ _Py_uop_frame_new( frame->stack_len = co->co_stacksize; frame->locals_len = co->co_nlocalsplus; -frame->locals = localsplus_start; +
[Python-checkins] gh-121082: Fix build failure when the developer use `--enable-pystats` arguments in configuration command after #118450 (#121083)
https://github.com/python/cpython/commit/223c03a43c010cf4404f2a42efafe587646a0619 commit: 223c03a43c010cf4404f2a42efafe587646a0619 branch: main author: Nadeshiko Manju committer: Fidget-Spinner date: 2024-06-27T19:35:25+08:00 summary: gh-121082: Fix build failure when the developer use `--enable-pystats` arguments in configuration command after #118450 (#121083) Signed-off-by: Manjusaka Co-authored-by: Ken Jin files: A Misc/NEWS.d/next/Build/2024-06-27-18-03-20.gh-issue-121082.w3AfRx.rst M Python/specialize.c diff --git a/Misc/NEWS.d/next/Build/2024-06-27-18-03-20.gh-issue-121082.w3AfRx.rst b/Misc/NEWS.d/next/Build/2024-06-27-18-03-20.gh-issue-121082.w3AfRx.rst new file mode 100644 index 00..7657672ba880c8 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-06-27-18-03-20.gh-issue-121082.w3AfRx.rst @@ -0,0 +1 @@ +Fix build failure when the developer use ``--enable-pystats`` arguments in configuration command after #118450. diff --git a/Python/specialize.c b/Python/specialize.c index dc0e319880b976..497feca06e4c7f 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2364,7 +2364,8 @@ _Py_Specialize_ForIter(_PyStackRef iter, _Py_CODEUNIT *instr, int oparg) assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER); _PyForIterCache *cache = (_PyForIterCache *)(instr + 1); -PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)); +PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); +PyTypeObject *tp = Py_TYPE(iter_o); if (tp == &PyListIter_Type) { instr->op.code = FOR_ITER_LIST; goto success; @@ -2389,7 +2390,7 @@ _Py_Specialize_ForIter(_PyStackRef iter, _Py_CODEUNIT *instr, int oparg) goto success; } SPECIALIZATION_FAIL(FOR_ITER, -_PySpecialization_ClassifyIterator(iter)); +_PySpecialization_ClassifyIterator(iter_o)); failure: STAT_INC(FOR_ITER, failure); instr->op.code = FOR_ITER; ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-117139: Fix a few wrong steals in bytecodes.c (GH-121127)
https://github.com/python/cpython/commit/e6543daf12051e9c660a5c0437683e8d2706a3c7 commit: e6543daf12051e9c660a5c0437683e8d2706a3c7 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-06-29T02:14:48+08:00 summary: gh-117139: Fix a few wrong steals in bytecodes.c (GH-121127) Fix a few wrong steals in bytecodes.c files: M Python/bytecodes.c M Python/ceval.c M Python/executor_cases.c.h M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8dfce77dfca297..50978a0dc87694 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -230,7 +230,7 @@ dummy_func( } replicate(8) pure inst(LOAD_FAST, (-- value)) { -assert(PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)) != NULL); +assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); } @@ -673,7 +673,7 @@ dummy_func( err = 1; } else { -err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectSteal(v)); +err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); Py_DECREF(slice); } PyStackRef_CLOSE(v); @@ -789,7 +789,7 @@ dummy_func( inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) { int err = PySet_Add(PyStackRef_AsPyObjectBorrow(set), -PyStackRef_AsPyObjectSteal(v)); +PyStackRef_AsPyObjectBorrow(v)); DECREF_INPUTS(); ERROR_IF(err, error); } @@ -813,7 +813,7 @@ dummy_func( op(_STORE_SUBSCR, (v, container, sub -- )) { /* container[sub] = v */ -int err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), PyStackRef_AsPyObjectSteal(sub), PyStackRef_AsPyObjectSteal(v)); +int err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), PyStackRef_AsPyObjectBorrow(sub), PyStackRef_AsPyObjectBorrow(v)); DECREF_INPUTS(); ERROR_IF(err, error); } @@ -1235,7 +1235,7 @@ dummy_func( inst(POP_EXCEPT, (exc_value -- )) { _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, -PyStackRef_AsPyObjectBorrow(exc_value) == Py_None + PyStackRef_Is(exc_value, PyStackRef_None) ? NULL : PyStackRef_AsPyObjectSteal(exc_value)); } @@ -1330,9 +1330,9 @@ dummy_func( ERROR_IF(true, error); } if (PyDict_CheckExact(ns)) -err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectSteal(v)); +err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); else -err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectSteal(v)); +err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); DECREF_INPUTS(); ERROR_IF(err, error); } @@ -1450,7 +1450,7 @@ dummy_func( op(_STORE_ATTR, (v, owner --)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(PyStackRef_AsPyObjectBorrow(owner), - name, PyStackRef_AsPyObjectSteal(v)); + name, PyStackRef_AsPyObjectBorrow(v)); DECREF_INPUTS(); ERROR_IF(err, error); } diff --git a/Python/ceval.c b/Python/ceval.c index 2412256ace8c8d..f4b3a417025c14 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1619,7 +1619,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func, goto kw_fail; } -if (PyDict_SetItem(kwdict, keyword, PyStackRef_AsPyObjectSteal(value_stackref)) == -1) { +if (PyDict_SetItem(kwdict, keyword, PyStackRef_AsPyObjectBorrow(value_stackref)) == -1) { goto kw_fail; } PyStackRef_CLOSE(value_stackref); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 38437c6f2c087c..76b7a9b4b15ae9 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -54,7 +54,7 @@ _PyStackRef value; oparg = 0; assert(oparg == CURRENT_OPARG()); -assert(PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)) != NULL); +assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); stack_pointer[0] = value; stack_pointer += 1; @@ -66,7 +66,7 @@ _PyStackRef value; oparg = 1; assert(oparg == CURRENT_OPARG()); -assert(PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)) != NULL); +assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GE
[Python-checkins] gh-121263: Macro-ify most stackref functions for MSVC (GH-121270)
https://github.com/python/cpython/commit/79e5dc1e499664966e50bb98065670033300 commit: 79e5dc1e499664966e50bb98065670033300 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-07-03T17:49:31+08:00 summary: gh-121263: Macro-ify most stackref functions for MSVC (GH-121270) Macro-ify most stackref functions for MSVC files: M Include/internal/pycore_stackref.h diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 4301c6a7cb40b0..8d3d559814bfd9 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -85,81 +85,67 @@ typedef union _PyStackRef { # define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) }) #endif +// Note: the following are all macros because MSVC (Windows) has trouble inlining them. -static inline int -PyStackRef_Is(_PyStackRef a, _PyStackRef b) { -return a.bits == b.bits; -} +#define PyStackRef_Is(a, b) ((a).bits == (b).bits) + +#define PyStackRef_IsDeferred(ref) (((ref).bits & Py_TAG_BITS) == Py_TAG_DEFERRED) -static inline int -PyStackRef_IsDeferred(_PyStackRef ref) -{ -return ((ref.bits & Py_TAG_BITS) == Py_TAG_DEFERRED); -} +#ifdef Py_GIL_DISABLED // Gets a PyObject * from a _PyStackRef static inline PyObject * PyStackRef_AsPyObjectBorrow(_PyStackRef stackref) { -#ifdef Py_GIL_DISABLED PyObject *cleared = ((PyObject *)((stackref).bits & (~Py_TAG_BITS))); return cleared; +} #else -return ((PyObject *)(stackref).bits); +# define PyStackRef_AsPyObjectBorrow(stackref) ((PyObject *)(stackref).bits) #endif -} // Converts a PyStackRef back to a PyObject *, stealing the // PyStackRef. +#ifdef Py_GIL_DISABLED static inline PyObject * PyStackRef_AsPyObjectSteal(_PyStackRef stackref) { -#ifdef Py_GIL_DISABLED if (!PyStackRef_IsNull(stackref) && PyStackRef_IsDeferred(stackref)) { return Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)); } return PyStackRef_AsPyObjectBorrow(stackref); +} #else -return PyStackRef_AsPyObjectBorrow(stackref); +# define PyStackRef_AsPyObjectSteal(stackref) PyStackRef_AsPyObjectBorrow(stackref) #endif -} // Converts a PyStackRef back to a PyObject *, converting the // stackref to a new reference. -static inline PyObject * -PyStackRef_AsPyObjectNew(_PyStackRef stackref) -{ -return Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)); -} +#define PyStackRef_AsPyObjectNew(stackref) Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)) -static inline PyTypeObject * -PyStackRef_TYPE(_PyStackRef stackref) -{ -return Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref)); -} +#define PyStackRef_TYPE(stackref) Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref)) // Converts a PyObject * to a PyStackRef, stealing the reference +#ifdef Py_GIL_DISABLED static inline _PyStackRef _PyStackRef_FromPyObjectSteal(PyObject *obj) { -#ifdef Py_GIL_DISABLED // Make sure we don't take an already tagged value. assert(((uintptr_t)obj & Py_TAG_BITS) == 0); int tag = (obj == NULL || _Py_IsImmortal(obj)) ? (Py_TAG_DEFERRED) : Py_TAG_PTR; return ((_PyStackRef){.bits = ((uintptr_t)(obj)) | tag}); +} +# define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj)) #else -return ((_PyStackRef){.bits = ((uintptr_t)(obj))}); +# define PyStackRef_FromPyObjectSteal(obj) ((_PyStackRef){.bits = ((uintptr_t)(obj))}) #endif -} - -#define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj)) // Converts a PyObject * to a PyStackRef, with a new reference +#ifdef Py_GIL_DISABLED static inline _PyStackRef PyStackRef_FromPyObjectNew(PyObject *obj) { -#ifdef Py_GIL_DISABLED // Make sure we don't take an already tagged value. assert(((uintptr_t)obj & Py_TAG_BITS) == 0); assert(obj != NULL); @@ -170,30 +156,27 @@ PyStackRef_FromPyObjectNew(PyObject *obj) else { return (_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) | Py_TAG_PTR }; } +} +# define PyStackRef_FromPyObjectNew(obj) PyStackRef_FromPyObjectNew(_PyObject_CAST(obj)) #else -return ((_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) }); +# define PyStackRef_FromPyObjectNew(obj) ((_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) }) #endif -} - -#define PyStackRef_FromPyObjectNew(obj) PyStackRef_FromPyObjectNew(_PyObject_CAST(obj)) +#ifdef Py_GIL_DISABLED // Same as PyStackRef_FromPyObjectNew but only for immortal objects. static inline _PyStackRef PyStackRef_FromPyObjectImmortal(PyObject *obj) { -#ifdef Py_GIL_DISABLED // Make sure we don't take an already tagged value. assert(((uintptr_t)obj & Py_TAG_BITS) == 0); assert(obj != NULL); assert(_Py_IsImmortal(obj)); return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED }; +} +# define PyStackRef_FromPyObjectImmortal(obj) PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj))
[Python-checkins] Add Fidget-Spinner to stackrefs CODEOWNERS (GH-121455)
https://github.com/python/cpython/commit/3bddd07c2ada7cdadb55ea23a15037bd650e20ef commit: 3bddd07c2ada7cdadb55ea23a15037bd650e20ef branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-07-07T21:45:06+08:00 summary: Add Fidget-Spinner to stackrefs CODEOWNERS (GH-121455) files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e8f4a4693a814c..95e30ac3001c9c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -72,6 +72,7 @@ Include/internal/pycore_freelist.h @ericsnowcurrently Include/internal/pycore_global_objects.h @ericsnowcurrently Include/internal/pycore_obmalloc.h @ericsnowcurrently Include/internal/pycore_pymem.h @ericsnowcurrently +Include/internal/pycore_stackref.h @Fidget-Spinner Modules/main.c@ericsnowcurrently Programs/_bootstrap_python.c @ericsnowcurrently Programs/python.c @ericsnowcurrently ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-120198: Stop the world when setting __class__ on free-threaded build (GH-120672)
https://github.com/python/cpython/commit/3bfc9c831ad9a3dcf4457e842f1e612e93014a17 commit: 3bfc9c831ad9a3dcf4457e842f1e612e93014a17 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-07-11T02:02:08+08:00 summary: gh-120198: Stop the world when setting __class__ on free-threaded build (GH-120672) files: M Include/internal/pycore_dict.h M Include/object.h M Lib/test/test_free_threading/test_type.py M Objects/dictobject.c M Objects/typeobject.c diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 9e0e1237915e82..56cc49432cc61e 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -322,6 +322,8 @@ _PyInlineValuesSize(PyTypeObject *tp) int _PyDict_DetachFromObject(PyDictObject *dict, PyObject *obj); +PyDictObject *_PyObject_MaterializeManagedDict_LockHeld(PyObject *); + #ifdef __cplusplus } #endif diff --git a/Include/object.h b/Include/object.h index a1e5b33b0fdaae..abfdb6ce24df21 100644 --- a/Include/object.h +++ b/Include/object.h @@ -249,11 +249,7 @@ PyAPI_FUNC(PyTypeObject*) Py_TYPE(PyObject *ob); #else static inline PyTypeObject* _Py_TYPE(PyObject *ob) { -#if defined(Py_GIL_DISABLED) -return (PyTypeObject *)_Py_atomic_load_ptr_relaxed(&ob->ob_type); -#else return ob->ob_type; -#endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b # define Py_TYPE(ob) _Py_TYPE(_PyObject_CAST(ob)) @@ -284,11 +280,7 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { -#ifdef Py_GIL_DISABLED -_Py_atomic_store_ptr(&ob->ob_type, type); -#else ob->ob_type = type; -#endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b # define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 75259795e81bcb..649676db9c08a5 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -106,7 +106,7 @@ class Bar: thing = Foo() def work(): foo = thing -for _ in range(1): +for _ in range(5000): foo.__class__ = Bar type(foo) foo.__class__ = Foo diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 2b11a01595b0bc..989c7bb624f488 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -158,6 +158,10 @@ ASSERT_DICT_LOCKED(PyObject *op) if (!_PyInterpreterState_GET()->stoptheworld.world_stopped) { \ ASSERT_DICT_LOCKED(op); \ } +#define ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(op) \ +if (!_PyInterpreterState_GET()->stoptheworld.world_stopped) { \ +_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); \ +} #define IS_DICT_SHARED(mp) _PyObject_GC_IS_SHARED(mp) #define SET_DICT_SHARED(mp) _PyObject_GC_SET_SHARED(mp) @@ -227,6 +231,7 @@ static inline void split_keys_entry_added(PyDictKeysObject *keys) #define ASSERT_DICT_LOCKED(op) #define ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op) +#define ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(op) #define LOCK_KEYS(keys) #define UNLOCK_KEYS(keys) #define ASSERT_KEYS_LOCKED(keys) @@ -6667,10 +6672,10 @@ make_dict_from_instance_attributes(PyInterpreterState *interp, return res; } -static PyDictObject * -materialize_managed_dict_lock_held(PyObject *obj) +PyDictObject * +_PyObject_MaterializeManagedDict_LockHeld(PyObject *obj) { -_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj); +ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj); PyDictValues *values = _PyObject_InlineValues(obj); PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -6699,7 +6704,7 @@ _PyObject_MaterializeManagedDict(PyObject *obj) goto exit; } #endif -dict = materialize_managed_dict_lock_held(obj); +dict = _PyObject_MaterializeManagedDict_LockHeld(obj); #ifdef Py_GIL_DISABLED exit: @@ -7132,7 +7137,7 @@ PyObject_ClearManagedDict(PyObject *obj) int _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj) { -_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj); +ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj); assert(_PyObject_ManagedDictPointer(obj)->dict == mp); assert(_PyObject_InlineValuesConsistencyCheck(obj)); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index df895bc65983c0..587632cecfba9d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6540,28 +6540,11 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* return 0; } -static int -object_set_class(PyObject *self, PyObject *value, void *closure) -{ - -if (value == NULL) { -PyErr_SetString(PyExc_TypeError, -"can't del
[Python-checkins] [3.13] gh-120198: Stop the world when setting __class__ on free-threaded build (#121591)
https://github.com/python/cpython/commit/cd74ed0a71f57e96bcd6c2a996587c58ef5da82d commit: cd74ed0a71f57e96bcd6c2a996587c58ef5da82d branch: 3.13 author: Ken Jin committer: Fidget-Spinner date: 2024-07-12T19:35:53+08:00 summary: [3.13] gh-120198: Stop the world when setting __class__ on free-threaded build (#121591) (cherry-picked from commit 3bfc9c8) files: M Include/internal/pycore_dict.h M Include/object.h M Lib/test/test_free_threading/test_type.py M Objects/dictobject.c M Objects/typeobject.c diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 8d8d3748edaea8..01f80e21ba2797 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -323,6 +323,8 @@ _PyInlineValuesSize(PyTypeObject *tp) int _PyDict_DetachFromObject(PyDictObject *dict, PyObject *obj); +PyDictObject *_PyObject_MaterializeManagedDict_LockHeld(PyObject *); + #ifdef __cplusplus } #endif diff --git a/Include/object.h b/Include/object.h index fa9c2a51a95e0d..b4db7fb204fd7d 100644 --- a/Include/object.h +++ b/Include/object.h @@ -327,11 +327,7 @@ static inline Py_ssize_t Py_REFCNT(PyObject *ob) { // bpo-39573: The Py_SET_TYPE() function must be used to set an object type. static inline PyTypeObject* Py_TYPE(PyObject *ob) { -#ifdef Py_GIL_DISABLED -return (PyTypeObject *)_Py_atomic_load_ptr_relaxed(&ob->ob_type); -#else return ob->ob_type; -#endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b # define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob)) @@ -421,11 +417,7 @@ static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { -#ifdef Py_GIL_DISABLED -_Py_atomic_store_ptr(&ob->ob_type, type); -#else ob->ob_type = type; -#endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b # define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 1e84b2db2d4882..29ca929994cb79 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -106,7 +106,7 @@ class Bar: thing = Foo() def work(): foo = thing -for _ in range(1): +for _ in range(5000): foo.__class__ = Bar type(foo) foo.__class__ = Foo diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 3cd267556342ec..48aed1e4da8ffc 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -158,6 +158,10 @@ ASSERT_DICT_LOCKED(PyObject *op) if (!_PyInterpreterState_GET()->stoptheworld.world_stopped) { \ ASSERT_DICT_LOCKED(op); \ } +#define ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(op) \ +if (!_PyInterpreterState_GET()->stoptheworld.world_stopped) { \ +_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); \ +} #define IS_DICT_SHARED(mp) _PyObject_GC_IS_SHARED(mp) #define SET_DICT_SHARED(mp) _PyObject_GC_SET_SHARED(mp) @@ -226,6 +230,7 @@ static inline void split_keys_entry_added(PyDictKeysObject *keys) #define ASSERT_DICT_LOCKED(op) #define ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op) +#define ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(op) #define LOCK_KEYS(keys) #define UNLOCK_KEYS(keys) #define ASSERT_KEYS_LOCKED(keys) @@ -6673,10 +6678,10 @@ make_dict_from_instance_attributes(PyInterpreterState *interp, return res; } -static PyDictObject * -materialize_managed_dict_lock_held(PyObject *obj) +PyDictObject * +_PyObject_MaterializeManagedDict_LockHeld(PyObject *obj) { -_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj); +ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj); PyDictValues *values = _PyObject_InlineValues(obj); PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -6705,7 +6710,7 @@ _PyObject_MaterializeManagedDict(PyObject *obj) goto exit; } #endif -dict = materialize_managed_dict_lock_held(obj); +dict = _PyObject_MaterializeManagedDict_LockHeld(obj); #ifdef Py_GIL_DISABLED exit: @@ -7138,7 +7143,7 @@ PyObject_ClearManagedDict(PyObject *obj) int _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj) { -_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj); +ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj); assert(_PyObject_ManagedDictPointer(obj)->dict == mp); assert(_PyObject_InlineValuesConsistencyCheck(obj)); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index edcdc6e9c4f5c2..1227f524a587bb 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6378,28 +6378,11 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* return 0; } -static int -object_set_class(PyObject *self, PyObject *value, void *closure) -{ - -if (value == NULL) { -
[Python-checkins] gh-121546: Disable contextvar caching on free-threading build (GH-121740)
https://github.com/python/cpython/commit/e904300882055bed71cae59f8ca9161066659b7c commit: e904300882055bed71cae59f8ca9161066659b7c branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-07-16T02:57:58+08:00 summary: gh-121546: Disable contextvar caching on free-threading build (GH-121740) files: M Include/internal/pycore_context.h M Python/context.c diff --git a/Include/internal/pycore_context.h b/Include/internal/pycore_context.h index ae5c47f195eb7f..10c1f1e52be040 100644 --- a/Include/internal/pycore_context.h +++ b/Include/internal/pycore_context.h @@ -35,9 +35,11 @@ struct _pycontextvarobject { PyObject_HEAD PyObject *var_name; PyObject *var_default; +#ifndef Py_GIL_DISABLED PyObject *var_cached; uint64_t var_cached_tsid; uint64_t var_cached_tsver; +#endif Py_hash_t var_hash; }; diff --git a/Python/context.c b/Python/context.c index a3830be17908fe..c32c15f5562f24 100644 --- a/Python/context.c +++ b/Python/context.c @@ -203,6 +203,7 @@ PyContextVar_Get(PyObject *ovar, PyObject *def, PyObject **val) goto not_found; } +#ifndef Py_GIL_DISABLED if (var->var_cached != NULL && var->var_cached_tsid == ts->id && var->var_cached_tsver == ts->context_ver) @@ -210,6 +211,7 @@ PyContextVar_Get(PyObject *ovar, PyObject *def, PyObject **val) *val = var->var_cached; goto found; } +#endif assert(PyContext_CheckExact(ts->context)); PyHamtObject *vars = ((PyContext *)ts->context)->ctx_vars; @@ -221,9 +223,11 @@ PyContextVar_Get(PyObject *ovar, PyObject *def, PyObject **val) } if (res == 1) { assert(found != NULL); +#ifndef Py_GIL_DISABLED var->var_cached = found; /* borrow */ var->var_cached_tsid = ts->id; var->var_cached_tsver = ts->context_ver; +#endif *val = found; goto found; @@ -723,8 +727,10 @@ PyTypeObject PyContext_Type = { static int contextvar_set(PyContextVar *var, PyObject *val) { +#ifndef Py_GIL_DISABLED var->var_cached = NULL; PyThreadState *ts = _PyThreadState_GET(); +#endif PyContext *ctx = context_get(); if (ctx == NULL) { @@ -739,16 +745,20 @@ contextvar_set(PyContextVar *var, PyObject *val) Py_SETREF(ctx->ctx_vars, new_vars); +#ifndef Py_GIL_DISABLED var->var_cached = val; /* borrow */ var->var_cached_tsid = ts->id; var->var_cached_tsver = ts->context_ver; +#endif return 0; } static int contextvar_del(PyContextVar *var) { +#ifndef Py_GIL_DISABLED var->var_cached = NULL; +#endif PyContext *ctx = context_get(); if (ctx == NULL) { @@ -823,9 +833,11 @@ contextvar_new(PyObject *name, PyObject *def) var->var_default = Py_XNewRef(def); +#ifndef Py_GIL_DISABLED var->var_cached = NULL; var->var_cached_tsid = 0; var->var_cached_tsver = 0; +#endif if (_PyObject_GC_MAY_BE_TRACKED(name) || (def != NULL && _PyObject_GC_MAY_BE_TRACKED(def))) @@ -863,9 +875,11 @@ contextvar_tp_clear(PyContextVar *self) { Py_CLEAR(self->var_name); Py_CLEAR(self->var_default); +#ifndef Py_GIL_DISABLED self->var_cached = NULL; self->var_cached_tsid = 0; self->var_cached_tsver = 0; +#endif return 0; } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-121621: Move asyncio running loop to thread state (GH-121695)
https://github.com/python/cpython/commit/69c68de43aef03dd52fabd21f99cb3b0f9329201 commit: 69c68de43aef03dd52fabd21f99cb3b0f9329201 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-07-17T01:09:58+08:00 summary: gh-121621: Move asyncio running loop to thread state (GH-121695) files: M Include/cpython/pystate.h M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Modules/_asynciomodule.c M Python/pystate.c diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index bb2af78a376d75..ce050424cccd49 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -68,6 +68,8 @@ struct _ts { pycore_ceval.h. */ uintptr_t eval_breaker; +PyObject *asyncio_running_loop; // Strong reference + struct { /* Has been initialized to a safe state. diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index c0840f9eb7eca2..d9b46df507dfd7 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -588,7 +588,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__annotate__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__annotations__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__args__)); -_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__asyncio_running_event_loop__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__await__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bases__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bool__)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 51735a8a726e11..10773d7a6c7e3f 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -77,7 +77,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(__annotate__) STRUCT_FOR_ID(__annotations__) STRUCT_FOR_ID(__args__) -STRUCT_FOR_ID(__asyncio_running_event_loop__) STRUCT_FOR_ID(__await__) STRUCT_FOR_ID(__bases__) STRUCT_FOR_ID(__bool__) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index c5be67c6d80b9d..618f8d0a36b6c3 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -586,7 +586,6 @@ extern "C" { INIT_ID(__annotate__), \ INIT_ID(__annotations__), \ INIT_ID(__args__), \ -INIT_ID(__asyncio_running_event_loop__), \ INIT_ID(__await__), \ INIT_ID(__bases__), \ INIT_ID(__bool__), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 0e0ad6518771e9..f848a002c3b5d1 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -108,10 +108,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); -string = &_Py_ID(__asyncio_running_event_loop__); -_PyUnicode_InternStatic(interp, &string); -assert(_PyUnicode_CheckConsistency(string, 1)); -assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__await__); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 5824c470699d88..31a45f8169be88 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -135,9 +135,6 @@ typedef struct { /* Imports from traceback. */ PyObject *traceback_extract_stack; -PyObject *cached_running_loop; // Borrowed reference -volatile uint64_t cached_running_loop_tsid; - /* Counter for autogenerated Task names */ uint64_t task_name_counter; @@ -321,101 +318,15 @@ get_future_loop(asyncio_state *state, PyObject *fut) return PyObject_GetAttr(fut, &_Py_ID(_loop)); } - -static int -get_running_loop(asyncio_state *state, PyObject **loop) -{ -PyObject *rl; - -PyThreadState *ts = _PyThreadState_GET(); -uint64_t ts_id = PyThreadState_GetID(ts); -if (state->cached_running_loop_tsid == ts_id && -state->cached_running_loop != NULL) -{ -// Fast path, check the cache. -rl = state->cached_running_loop; -} -else { -PyObject *ts_dict = _PyThreadState_GetDict(ts); // borrowed -if (ts_dict == NULL) { -goto not_found; -} - -rl = PyDict
[Python-checkins] [3.13] gh-121621: Move asyncio running loop to thread state (GH-121695) (GH-121864)
https://github.com/python/cpython/commit/06d76c4b94f87b0785a96dbfa0904afc0b459cb7 commit: 06d76c4b94f87b0785a96dbfa0904afc0b459cb7 branch: 3.13 author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com> committer: Fidget-Spinner date: 2024-07-17T01:57:37+08:00 summary: [3.13] gh-121621: Move asyncio running loop to thread state (GH-121695) (GH-121864) gh-121621: Move asyncio running loop to thread state (GH-121695) (cherry picked from commit 69c68de43aef03dd52fabd21f99cb3b0f9329201) Co-authored-by: Ken Jin files: M Include/cpython/pystate.h M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Modules/_asynciomodule.c M Python/pystate.c diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index bb2af78a376d75..ce050424cccd49 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -68,6 +68,8 @@ struct _ts { pycore_ceval.h. */ uintptr_t eval_breaker; +PyObject *asyncio_running_loop; // Strong reference + struct { /* Has been initialized to a safe state. diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 16cb4793ad1d08..006dd911b5a8ef 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -586,7 +586,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__anext__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__annotations__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__args__)); -_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__asyncio_running_event_loop__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__await__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bases__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bool__)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 1e76853297150b..a5436b6d689612 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -75,7 +75,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(__anext__) STRUCT_FOR_ID(__annotations__) STRUCT_FOR_ID(__args__) -STRUCT_FOR_ID(__asyncio_running_event_loop__) STRUCT_FOR_ID(__await__) STRUCT_FOR_ID(__bases__) STRUCT_FOR_ID(__bool__) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index f4d0ee4122ea2f..6e62ecd4b3a815 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -584,7 +584,6 @@ extern "C" { INIT_ID(__anext__), \ INIT_ID(__annotations__), \ INIT_ID(__args__), \ -INIT_ID(__asyncio_running_event_loop__), \ INIT_ID(__await__), \ INIT_ID(__bases__), \ INIT_ID(__bool__), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index e1bc9cf1c7bd6e..5337390309548b 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -104,10 +104,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); -string = &_Py_ID(__asyncio_running_event_loop__); -_PyUnicode_InternStatic(interp, &string); -assert(_PyUnicode_CheckConsistency(string, 1)); -assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__await__); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 92d0e6de0dfb93..ab72cc2fe55637 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -68,9 +68,6 @@ typedef struct { /* Imports from traceback. */ PyObject *traceback_extract_stack; -PyObject *cached_running_loop; // Borrowed reference -volatile uint64_t cached_running_loop_tsid; - /* Counter for autogenerated Task names */ uint64_t task_name_counter; @@ -262,101 +259,15 @@ get_future_loop(asyncio_state *state, PyObject *fut) return PyObject_GetAttr(fut, &_Py_ID(_loop)); } - -static int -get_running_loop(asyncio_state *state, PyObject **loop) -{ -PyObject *rl; - -PyThreadState *ts = _PyThreadState_GET(); -uint64_t ts_id = PyThreadState_GetID(ts); -if (state->cached_running_loop_tsid == ts_id && -state->cached_running_loop != NULL) -{ -// Fast path, check the cac
[Python-checkins] [3.12] Check for valid tp_version_tag in specializer (gh-89811) (gh-114216)
https://github.com/python/cpython/commit/ae2a25bf607410bb87d0b0c556adc7f56ec73fa9 commit: ae2a25bf607410bb87d0b0c556adc7f56ec73fa9 branch: 3.12 author: Peter Lazorchak committer: Fidget-Spinner date: 2024-01-20T04:45:33+08:00 summary: [3.12] Check for valid tp_version_tag in specializer (gh-89811) (gh-114216) files: A Misc/NEWS.d/next/Core and Builtins/2024-01-03-12-19-37.gh-issue-89811.cZOj6d.rst M Lib/test/test_type_cache.py M Modules/_testcapimodule.c M Python/specialize.c diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 72587ecc11b6f3..2ebaa47fd03a08 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -1,5 +1,6 @@ """ Tests for the internal type cache in CPython. """ import unittest +import dis from test import support from test.support import import_helper try: @@ -8,8 +9,11 @@ _clear_type_cache = None # Skip this test if the _testcapi module isn't available. -type_get_version = import_helper.import_module('_testcapi').type_get_version -type_assign_version = import_helper.import_module('_testcapi').type_assign_version +_testcapi = import_helper.import_module("_testcapi") +type_get_version = _testcapi.type_get_version +type_assign_specific_version_unsafe = _testcapi.type_assign_specific_version_unsafe +type_assign_version = _testcapi.type_assign_version +type_modified = _testcapi.type_modified @support.cpython_only @@ -56,6 +60,144 @@ class C: self.assertNotEqual(type_get_version(C), 0) self.assertNotEqual(type_get_version(C), c_ver) +def test_type_assign_specific_version(self): +"""meta-test for type_assign_specific_version_unsafe""" +class C: +pass + +type_assign_version(C) +orig_version = type_get_version(C) +if orig_version == 0: +self.skipTest("Could not assign a valid type version") + +type_modified(C) +type_assign_specific_version_unsafe(C, orig_version + 5) +type_assign_version(C) # this should do nothing + +new_version = type_get_version(C) +self.assertEqual(new_version, orig_version + 5) + +_clear_type_cache() + + +@support.cpython_only +class TypeCacheWithSpecializationTests(unittest.TestCase): +def tearDown(self): +_clear_type_cache() + +def _assign_valid_version_or_skip(self, type_): +type_modified(type_) +type_assign_version(type_) +if type_get_version(type_) == 0: +self.skipTest("Could not assign valid type version") + +def _assign_and_check_version_0(self, user_type): +type_modified(user_type) +type_assign_specific_version_unsafe(user_type, 0) +self.assertEqual(type_get_version(user_type), 0) + +def _all_opnames(self, func): +return set(instr.opname for instr in dis.Bytecode(func, adaptive=True)) + +def _check_specialization(self, func, arg, opname, *, should_specialize): +for _ in range(100): +func(arg) + +if should_specialize: +self.assertNotIn(opname, self._all_opnames(func)) +else: +self.assertIn(opname, self._all_opnames(func)) + +def test_class_load_attr_specialization_user_type(self): +class A: +def foo(self): +pass + +self._assign_valid_version_or_skip(A) + +def load_foo_1(type_): +type_.foo + +self._check_specialization(load_foo_1, A, "LOAD_ATTR", should_specialize=True) +del load_foo_1 + +self._assign_and_check_version_0(A) + +def load_foo_2(type_): +return type_.foo + +self._check_specialization(load_foo_2, A, "LOAD_ATTR", should_specialize=False) + +def test_class_load_attr_specialization_static_type(self): +self._assign_valid_version_or_skip(str) +self._assign_valid_version_or_skip(bytes) + +def get_capitalize_1(type_): +return type_.capitalize + +self._check_specialization(get_capitalize_1, str, "LOAD_ATTR", should_specialize=True) +self.assertEqual(get_capitalize_1(str)('hello'), 'Hello') +self.assertEqual(get_capitalize_1(bytes)(b'hello'), b'Hello') +del get_capitalize_1 + +# Permanently overflow the static type version counter, and force str and bytes +# to have tp_version_tag == 0 +for _ in range(2**16): +type_modified(str) +type_assign_version(str) +type_modified(bytes) +type_assign_version(bytes) + +self.assertEqual(type_get_version(str), 0) +self.assertEqual(type_get_version(bytes), 0) + +def get_capitalize_2(type_): +return type_.capitalize + +self._check_specialization(get_capitalize_2, str, &q
[Python-checkins] [3.11] gh-89811: Check for valid tp_version_tag in specializer (GH-115045)
https://github.com/python/cpython/commit/a11312456d05a06feed00ee9e530e50fcadb7011 commit: a11312456d05a06feed00ee9e530e50fcadb7011 branch: 3.11 author: Peter Lazorchak committer: Fidget-Spinner date: 2024-02-06T21:58:30+08:00 summary: [3.11] gh-89811: Check for valid tp_version_tag in specializer (GH-115045) * gh-89811: Check for valid tp_version_tag in specializer (GH-113558) * gh-113937 Fix failures in type cache tests due to re-running (GH-113953) * Update backported code for 3.11 specifically files: A Misc/NEWS.d/next/Core and Builtins/2024-01-03-12-19-37.gh-issue-89811.cZOj6d.rst M Lib/test/test_type_cache.py M Modules/_testcapimodule.c M Python/specialize.c diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 9dc91dc93448ad..11158f9c565c46 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -1,5 +1,6 @@ """ Tests for the internal type cache in CPython. """ import unittest +import dis from test import support from test.support import import_helper try: @@ -8,7 +9,17 @@ _clear_type_cache = None # Skip this test if the _testcapi module isn't available. -type_get_version = import_helper.import_module('_testcapi').type_get_version +_testcapi = import_helper.import_module("_testcapi") +type_get_version = _testcapi.type_get_version +type_assign_specific_version_unsafe = _testcapi.type_assign_specific_version_unsafe +type_modified = _testcapi.type_modified + + +def type_assign_version(type_): +try: +type_.x +except AttributeError: +pass @support.cpython_only @@ -42,6 +53,151 @@ def test_tp_version_tag_unique(self): self.assertEqual(len(set(all_version_tags)), 30, msg=f"{all_version_tags} contains non-unique versions") +def test_type_assign_specific_version(self): +"""meta-test for type_assign_specific_version_unsafe""" +class C: +pass + +type_assign_version(C) +orig_version = type_get_version(C) +if orig_version == 0: +self.skipTest("Could not assign a valid type version") + +type_modified(C) +type_assign_specific_version_unsafe(C, orig_version + 5) +type_assign_version(C) # this should do nothing + +new_version = type_get_version(C) +self.assertEqual(new_version, orig_version + 5) + +_clear_type_cache() + + +@support.cpython_only +class TypeCacheWithSpecializationTests(unittest.TestCase): +def tearDown(self): +_clear_type_cache() + +def _assign_valid_version_or_skip(self, type_): +type_modified(type_) +type_assign_version(type_) +if type_get_version(type_) == 0: +self.skipTest("Could not assign valid type version") + +def _assign_and_check_version_0(self, user_type): +type_modified(user_type) +type_assign_specific_version_unsafe(user_type, 0) +self.assertEqual(type_get_version(user_type), 0) + +def _all_opnames(self, func): +return set(instr.opname for instr in dis.Bytecode(func, adaptive=True)) + +def _check_specialization(self, func, arg, opname, *, should_specialize): +for _ in range(100): +func(arg) + +if should_specialize: +self.assertNotIn(opname, self._all_opnames(func)) +else: +self.assertIn(opname, self._all_opnames(func)) + +def test_load_method_specialization_user_type(self): +class A: +def foo(self): +pass + +self._assign_valid_version_or_skip(A) + +def load_foo_1(instance): +instance.foo() + +self._check_specialization( +load_foo_1, A(), "LOAD_METHOD_ADAPTIVE", should_specialize=True +) +del load_foo_1 + +self._assign_and_check_version_0(A) + +def load_foo_2(instance): +instance.foo() + +self._check_specialization( +load_foo_2, A(), "LOAD_METHOD_ADAPTIVE", should_specialize=False +) + +def test_store_attr_specialization_user_type(self): +class B: +__slots__ = ("bar",) + +self._assign_valid_version_or_skip(B) + +def store_bar_1(instance): +instance.bar = 10 + +self._check_specialization( +store_bar_1, B(), "STORE_ATTR_ADAPTIVE", should_specialize=True +) +del store_bar_1 + +self._assign_and_check_version_0(B) + +def store_bar_2(instance): +instance.bar = 10 + +self._check_specialization( +store_bar_2, B(), "STORE_ATTR_ADAPTIVE", should_specialize=False +) + +def test_load_attr_specialization_user_type(self): +class C: +__slots__ = ("biz",) +def __init__(self): +self.b
[Python-checkins] Add Peter L to ACKS (GH-115222)
https://github.com/python/cpython/commit/5a173efa693a053bf4a059c82c1c06c82a9fa8fb commit: 5a173efa693a053bf4a059c82c1c06c82a9fa8fb branch: main author: Peter Lazorchak committer: Fidget-Spinner date: 2024-02-10T01:06:14+08:00 summary: Add Peter L to ACKS (GH-115222) files: M Misc/ACKS diff --git a/Misc/ACKS b/Misc/ACKS index 466023f390a421..8a80e02ecba26a 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1051,6 +1051,7 @@ Mark Lawrence Chris Laws Michael Layzell Michael Lazar +Peter Lazorchak Brian Leair Mathieu Leduc-Hamel Amandine Lee ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-114058: Foundations of the Tier2 redundancy eliminator (GH-115085)
https://github.com/python/cpython/commit/7cce8576226249461baa91c4a89770a1823b44a4 commit: 7cce8576226249461baa91c4a89770a1823b44a4 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-13T21:24:48+08:00 summary: gh-114058: Foundations of the Tier2 redundancy eliminator (GH-115085) - Co-authored-by: Mark Shannon <9448417+markshan...@users.noreply.github.com> Co-authored-by: Jules <57632293+julia...@users.noreply.github.com> Co-authored-by: Guido van Rossum files: A Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst A Python/tier2_redundancy_eliminator_bytecodes.c A Python/tier2_redundancy_eliminator_cases.c.h A Tools/cases_generator/tier2_abstract_generator.py M .gitattributes M Include/cpython/pystats.h M Include/internal/pycore_opcode_metadata.h M Include/internal/pycore_optimizer.h M Include/internal/pycore_uop_metadata.h M Lib/test/test_capi/test_opt.py M Lib/test/test_generated_cases.py M Makefile.pre.in M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/optimizer.c M Python/optimizer_analysis.c M Python/specialize.c M Tools/c-analyzer/cpython/_parser.py M Tools/c-analyzer/cpython/ignored.tsv M Tools/cases_generator/README.md M Tools/cases_generator/analyzer.py M Tools/cases_generator/interpreter_definition.md M Tools/cases_generator/parsing.py M Tools/cases_generator/stack.py diff --git a/.gitattributes b/.gitattributes index 2a48df079e1aeb..07d877027b09f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -94,6 +94,7 @@ Programs/test_frozenmain.h generated Python/Python-ast.c generated Python/executor_cases.c.h generated Python/generated_cases.c.h generated +Python/tier2_redundancy_eliminator_bytecodes.c.hgenerated Python/opcode_targets.h generated Python/stdlib_module_names.hgenerated Tools/peg_generator/pegen/grammar_parser.py generated diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index 0f50439b73848e..db9aaedec950e4 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -120,6 +120,9 @@ typedef struct _optimization_stats { uint64_t trace_length_hist[_Py_UOP_HIST_SIZE]; uint64_t trace_run_length_hist[_Py_UOP_HIST_SIZE]; uint64_t optimized_trace_length_hist[_Py_UOP_HIST_SIZE]; +uint64_t optimizer_attempts; +uint64_t optimizer_successes; +uint64_t optimizer_failure_reason_no_memory; } OptimizationStats; typedef struct _rare_event_stats { diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 75d7f44025328e..6b60a6fbffdc5e 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1094,7 +1094,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [MATCH_KEYS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, [MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 }, -[NOP] = { true, INSTR_FMT_IX, 0 }, +[NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [POP_EXCEPT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, @@ -1156,10 +1156,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [LOAD_SUPER_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ZERO_SUPER_ATTR] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ZERO_SUPER_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -[POP_BLOCK] = { true, -1, 0 }, -[SETUP_CLEANUP] = { true, -1, HAS_ARG_FLAG }, -[SETUP_FINALLY] = { true, -1, HAS_ARG_FLAG }, -[SETUP_WITH] = { true, -1, HAS_ARG_FLAG }, +[POP_BLOCK] = { true, -1, HAS_PURE_FLAG }, +[SETUP_CLEANUP] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, +[SETUP_FINALLY] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, +[SETUP_WITH] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, [STORE_FAST_MAYBE_NULL] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, }; #endif diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index e21412fc815540..eee71c700d4904 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -8,6 +8,13 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_uop_ids.h" + +// This is the length of the trace we project initially. +#define UOP_MAX_TRACE_LENGTH 512 + +#define TRACE_STACK_SIZE 5 + int _Py_uop_analyze_and_optimize(_PyInterpreterFrame *frame, _PyUOpInstruction *t
[Python-checkins] Add myself to various CODEOWNERS (GH-115481)
https://github.com/python/cpython/commit/d9f4cbe5e1e3c31518724d87d0d379d7ce6823ca commit: d9f4cbe5e1e3c31518724d87d0d379d7ce6823ca branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-15T03:48:11+08:00 summary: Add myself to various CODEOWNERS (GH-115481) files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7933d319550576..5dbfbbb8ebaf7e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -37,6 +37,8 @@ Python/flowgraph.c@markshannon @iritkatriel Python/ast_opt.c @isidentical Python/bytecodes.c@markshannon @gvanrossum Python/optimizer*.c @markshannon @gvanrossum +Python/optimizer_analysis.c @Fidget-Spinner +Python/tier2_redundancy_eliminator_bytecodes.c @Fidget-Spinner Lib/test/test_patma.py@brandtbucher Lib/test/test_type_*.py @JelleZijlstra Lib/test/test_capi/test_misc.py @markshannon @gvanrossum ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] Trigger JIT CI with optimizer files (#115483)
https://github.com/python/cpython/commit/ed23839dc5ce21ea9ca087fac170fa1412005210 commit: ed23839dc5ce21ea9ca087fac170fa1412005210 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-15T14:01:24+08:00 summary: Trigger JIT CI with optimizer files (#115483) * Trigger JIT CI with optimizer files files: M .github/workflows/jit.yml diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 69648d87947ad6..69c7b45376a411 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -4,10 +4,14 @@ on: paths: - '**jit**' - 'Python/bytecodes.c' + - 'Python/optimizer*.c' + - 'Python/tier2_redundancy_eliminator_bytecodes.c' push: paths: - '**jit**' - 'Python/bytecodes.c' + - 'Python/optimizer*.c' + - 'Python/tier2_redundancy_eliminator_bytecodes.c' workflow_dispatch: concurrency: ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-115480: Type and constant propagation for int BINARY_OPs (GH-115478)
https://github.com/python/cpython/commit/4ebf8fbdab1c64041ff0ea54b3d15624f6e01511 commit: 4ebf8fbdab1c64041ff0ea54b3d15624f6e01511 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-15T14:02:18+08:00 summary: gh-115480: Type and constant propagation for int BINARY_OPs (GH-115478) files: M Python/optimizer_analysis.c M Python/tier2_redundancy_eliminator_bytecodes.c M Python/tier2_redundancy_eliminator_cases.c.h diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 49974520de924d..d73bc310345f41 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -341,6 +341,18 @@ sym_new_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) return temp; } +static inline bool +is_const(_Py_UOpsSymType *sym) +{ +return sym->const_val != NULL; +} + +static inline PyObject * +get_const(_Py_UOpsSymType *sym) +{ +return sym->const_val; +} + static _Py_UOpsSymType* sym_new_null(_Py_UOpsAbstractInterpContext *ctx) { diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 3272b187f20d0e..39ea0eef627632 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -81,12 +81,62 @@ dummy_func(void) { op(_BINARY_OP_ADD_INT, (left, right -- res)) { -// TODO constant propagation -(void)left; -(void)right; -res = sym_new_known_type(ctx, &PyLong_Type); -if (res == NULL) { -goto out_of_space; +if (is_const(left) && is_const(right)) { +assert(PyLong_CheckExact(get_const(left))); +assert(PyLong_CheckExact(get_const(right))); +PyObject *temp = _PyLong_Add((PyLongObject *)get_const(left), + (PyLongObject *)get_const(right)); +if (temp == NULL) { +goto error; +} +res = sym_new_const(ctx, temp); +// TODO replace opcode with constant propagated one and add tests! +} +else { +res = sym_new_known_type(ctx, &PyLong_Type); +if (res == NULL) { +goto out_of_space; +} +} +} + +op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) { +if (is_const(left) && is_const(right)) { +assert(PyLong_CheckExact(get_const(left))); +assert(PyLong_CheckExact(get_const(right))); +PyObject *temp = _PyLong_Subtract((PyLongObject *)get_const(left), + (PyLongObject *)get_const(right)); +if (temp == NULL) { +goto error; +} +res = sym_new_const(ctx, temp); +// TODO replace opcode with constant propagated one and add tests! +} +else { +res = sym_new_known_type(ctx, &PyLong_Type); +if (res == NULL) { +goto out_of_space; +} +} +} + +op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) { +if (is_const(left) && is_const(right)) { +assert(PyLong_CheckExact(get_const(left))); +assert(PyLong_CheckExact(get_const(right))); +PyObject *temp = _PyLong_Multiply((PyLongObject *)get_const(left), + (PyLongObject *)get_const(right)); +if (temp == NULL) { +goto error; +} +res = sym_new_const(ctx, temp); +// TODO replace opcode with constant propagated one and add tests! +} +else { +res = sym_new_known_type(ctx, &PyLong_Type); +if (res == NULL) { +goto out_of_space; +} } } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index c2b7bbaf1c4481..a9617f51ef4615 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -180,9 +180,28 @@ } case _BINARY_OP_MULTIPLY_INT: { +_Py_UOpsSymType *right; +_Py_UOpsSymType *left; _Py_UOpsSymType *res; -res = sym_new_unknown(ctx); -if (res == NULL) goto out_of_space; +right = stack_pointer[-1]; +left = stack_pointer[-2]; +if (is_const(left) && is_const(right)) { +assert(PyLong_CheckExact(get_const(left))); +assert(PyLong_CheckExact(get_const(right))); +PyObject *temp = _PyLong_Multiply((PyLongObject *)get_const(left), +(PyLongObject *)get_const(right)); +if (temp == NULL) { +goto error; +} +res = sym_new_const(ctx, temp); +// TODO replace opcode with constant propagate
[Python-checkins] gh-115480: Minor fixups in int constant propagation (GH-115507)
https://github.com/python/cpython/commit/f92857a93016aa26ba93959d2bdb690ef52e7f07 commit: f92857a93016aa26ba93959d2bdb690ef52e7f07 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-16T22:59:43+08:00 summary: gh-115480: Minor fixups in int constant propagation (GH-115507) files: M Python/optimizer_analysis.c M Python/tier2_redundancy_eliminator_bytecodes.c M Python/tier2_redundancy_eliminator_cases.c.h diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index d73bc310345f41..b104d2fa7baec9 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -588,16 +588,17 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, INST->oparg = ARG;\ INST->operand = OPERAND; +#define OUT_OF_SPACE_IF_NULL(EXPR) \ +do { \ +if ((EXPR) == NULL) { \ +goto out_of_space; \ +} \ +} while (0); + #define _LOAD_ATTR_NOT_NULL \ do {\ -attr = sym_new_known_notnull(ctx); \ -if (attr == NULL) { \ -goto error; \ -} \ -null = sym_new_null(ctx); \ -if (null == NULL) { \ -goto error; \ -} \ +OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); \ +OUT_OF_SPACE_IF_NULL(null = sym_new_null(ctx)); \ } while (0); diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 39ea0eef627632..6aae590a8e51e4 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -43,10 +43,8 @@ dummy_func(void) { op(_LOAD_FAST_AND_CLEAR, (-- value)) { value = GETLOCAL(oparg); -_Py_UOpsSymType *temp = sym_new_null(ctx); -if (temp == NULL) { -goto out_of_space; -} +_Py_UOpsSymType *temp; +OUT_OF_SPACE_IF_NULL(temp = sym_new_null(ctx)); GETLOCAL(oparg) = temp; } @@ -89,14 +87,12 @@ dummy_func(void) { if (temp == NULL) { goto error; } -res = sym_new_const(ctx, temp); -// TODO replace opcode with constant propagated one and add tests! +OUT_OF_SPACE_IF_NULL(res = sym_new_const(ctx, temp)); +// TODO gh-115506: +// replace opcode with constant propagated one and add tests! } else { -res = sym_new_known_type(ctx, &PyLong_Type); -if (res == NULL) { -goto out_of_space; -} +OUT_OF_SPACE_IF_NULL(res = sym_new_known_type(ctx, &PyLong_Type)); } } @@ -109,14 +105,12 @@ dummy_func(void) { if (temp == NULL) { goto error; } -res = sym_new_const(ctx, temp); -// TODO replace opcode with constant propagated one and add tests! +OUT_OF_SPACE_IF_NULL(res = sym_new_const(ctx, temp)); +// TODO gh-115506: +// replace opcode with constant propagated one and add tests! } else { -res = sym_new_known_type(ctx, &PyLong_Type); -if (res == NULL) { -goto out_of_space; -} +OUT_OF_SPACE_IF_NULL(res = sym_new_known_type(ctx, &PyLong_Type)); } } @@ -129,14 +123,12 @@ dummy_func(void) { if (temp == NULL) { goto error; } -res = sym_new_const(ctx, temp); -// TODO replace opcode with constant propagated one and add tests! +OUT_OF_SPACE_IF_NULL(res = sym_new_const(ctx, temp)); +// TODO gh-115506: +// replace opcode with constant propagated one and add tests! } else { -res = sym_new_known_type(ctx, &PyLong_Type); -if (res == NULL) { -goto out_of_space; -} +OUT_OF_SPACE_IF_NULL(res = sym_new_known_type(ctx, &PyLong_Type)); } } @@ -147,39 +139,21 @@ dummy_func(void) { } op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { -value = sym_new_const(ctx, ptr); -if (value == NULL) { -goto out_of_space; -} +OUT_OF_SPACE_IF_NULL(value = sym_new_const(ctx, ptr)); } op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { -value = sym_new_const(ctx, ptr); -if (value == NULL) { -goto out_of_space; -} +OUT_OF_SPACE_IF_NULL(value = sym_new_const(ctx, ptr)); } op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { -value = sym_new_const(ctx, ptr); -if (value == NULL) { -goto out_of_space; -} -null = sym_new_null(ctx); -if (null == NULL) { -goto out_of_space; -} +OUT_OF_SPACE_IF_NULL(value = sym_new_const(ctx, ptr));
[Python-checkins] gh-115480: Type / constant propagation for float binary uops (GH-115550)
https://github.com/python/cpython/commit/13addd2bbdcbf96c5ea26a0f425c049f1b71e945 commit: 13addd2bbdcbf96c5ea26a0f425c049f1b71e945 branch: main author: Peter Lazorchak committer: Fidget-Spinner date: 2024-02-17T02:02:48+08:00 summary: gh-115480: Type / constant propagation for float binary uops (GH-115550) Co-authored-by: Ken Jin files: M Lib/test/test_capi/test_opt.py M Python/tier2_redundancy_eliminator_bytecodes.c M Python/tier2_redundancy_eliminator_cases.c.h diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 1a8ed3441fa855..66860c67966859 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -561,6 +561,16 @@ def testfunc(n): class TestUopsOptimization(unittest.TestCase): +def _run_with_optimizer(self, testfunc, arg): +res = None +opt = _testinternalcapi.get_uop_optimizer() +with temporary_optimizer(opt): +res = testfunc(arg) + +ex = get_first_executor(testfunc) +return res, ex + + def test_int_type_propagation(self): def testfunc(loops): num = 0 @@ -570,12 +580,7 @@ def testfunc(loops): num += 1 return a -opt = _testinternalcapi.get_uop_optimizer() -res = None -with temporary_optimizer(opt): -res = testfunc(32) - -ex = get_first_executor(testfunc) +res, ex = self._run_with_optimizer(testfunc, 32) self.assertIsNotNone(ex) self.assertEqual(res, 63) binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] @@ -642,12 +647,7 @@ def testfunc(loops): num += 1 return a -opt = _testinternalcapi.get_uop_optimizer() -res = None -with temporary_optimizer(opt): -res = testfunc(64) - -ex = get_first_executor(testfunc) +res, ex = self._run_with_optimizer(testfunc, 64) self.assertIsNotNone(ex) binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] self.assertGreaterEqual(len(binop_count), 3) @@ -659,11 +659,7 @@ def dummy(x): for i in range(n): dummy(i) -opt = _testinternalcapi.get_uop_optimizer() -with temporary_optimizer(opt): -testfunc(32) - -ex = get_first_executor(testfunc) +res, ex = self._run_with_optimizer(testfunc, 32) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} self.assertIn("_PUSH_FRAME", uops) @@ -677,11 +673,7 @@ def testfunc(n): x = i + i return x -opt = _testinternalcapi.get_uop_optimizer() -with temporary_optimizer(opt): -res = testfunc(32) - -ex = get_first_executor(testfunc) +res, ex = self._run_with_optimizer(testfunc, 32) self.assertEqual(res, 62) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} @@ -699,11 +691,7 @@ def testfunc(n): res = x + z + a + b return res -opt = _testinternalcapi.get_uop_optimizer() -with temporary_optimizer(opt): -res = testfunc(32) - -ex = get_first_executor(testfunc) +res, ex = self._run_with_optimizer(testfunc, 32) self.assertEqual(res, 4) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} @@ -716,11 +704,8 @@ def testfunc(n): for _ in range(n): return [i for i in range(n)] -opt = _testinternalcapi.get_uop_optimizer() -with temporary_optimizer(opt): -testfunc(32) - -ex = get_first_executor(testfunc) +res, ex = self._run_with_optimizer(testfunc, 32) +self.assertEqual(res, list(range(32))) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} self.assertNotIn("_BINARY_OP_ADD_INT", uops) @@ -785,6 +770,56 @@ def testfunc(n): """)) self.assertEqual(result[0].rc, 0, result) +def test_float_add_constant_propagation(self): +def testfunc(n): +a = 1.0 +for _ in range(n): +a = a + 0.1 +return a + +res, ex = self._run_with_optimizer(testfunc, 32) +self.assertAlmostEqual(res, 4.2) +self.assertIsNotNone(ex) +uops = {opname for opname, _, _ in ex} +guard_both_float_count = [opname for opname, _, _ in ex if opname == "_GUARD_BOTH_FLOAT"] +self.assertLessEqual(len(guard_both_float_count), 1) +# TODO gh-115506: this assertion may change after propagating constants. +# We'll also need to verify that propagation actually occurs. +self.assertIn("_BINARY_OP_ADD_FLOAT", uops) + +def test_float_subtract_constant_propagation(self): +def testfunc(n): +
[Python-checkins] gh-115700: Add target `_RegenCases` in Windows build for cases regeneration. (GH-115708)
https://github.com/python/cpython/commit/a2bb8ad14409c7ecb8dea437b0e281eb1f65b5d8 commit: a2bb8ad14409c7ecb8dea437b0e281eb1f65b5d8 branch: main author: Kirill Podoprigora committer: Fidget-Spinner date: 2024-02-20T19:10:47+08:00 summary: gh-115700: Add target `_RegenCases` in Windows build for cases regeneration. (GH-115708) files: A Misc/NEWS.d/next/Core and Builtins/2024-02-20-12-46-20.gh-issue-115700.KLJ5r4.rst M PCbuild/regen.targets diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-02-20-12-46-20.gh-issue-115700.KLJ5r4.rst b/Misc/NEWS.d/next/Core and Builtins/2024-02-20-12-46-20.gh-issue-115700.KLJ5r4.rst new file mode 100644 index 00..5b7b8e410b5063 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-02-20-12-46-20.gh-issue-115700.KLJ5r4.rst @@ -0,0 +1 @@ +The regen-cases build stage now works on Windows. diff --git a/PCbuild/regen.targets b/PCbuild/regen.targets index a90620d6ca8b7d..8f31803dbb752a 100644 --- a/PCbuild/regen.targets +++ b/PCbuild/regen.targets @@ -31,11 +31,13 @@ <_JITSources Include="$(PySourcePath)Python\executor_cases.c.h;$(GeneratedPyConfigDir)pyconfig.h;$(PySourcePath)Tools\jit\**"/> <_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils.h"/> +<_CasesSources Include="$(PySourcePath)Python\bytecodes.c;$(PySourcePath)Python\tier2_redundancy_eliminator_bytecodes.c;"/> +<_CasesOutputs Include="$(PySourcePath)Python\generated_cases.c.h;$(PySourcePath)Include\opcode_ids.h;$(PySourcePath)Include\internal\pycore_uop_ids.h;$(PySourcePath)Python\opcode_targets.h;$(PySourcePath)Include\internal\pycore_opcode_metadata.h;$(PySourcePath)Include\internal\pycore_uop_metadata.h;$(PySourcePath)Python\tier2_redundancy_eliminator_cases.c.h;$(PySourcePath)Lib\_opcode_metadata.py"/> - @@ -79,7 +81,31 @@ - + + + + + + + + + + + + + + - + ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-115687: Split up guards from COMPARE_OP (GH-115688)
https://github.com/python/cpython/commit/dcba21f905ef170b2cd0a6433b6fe6bcb4316a67 commit: dcba21f905ef170b2cd0a6433b6fe6bcb4316a67 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-20T11:30:49Z summary: gh-115687: Split up guards from COMPARE_OP (GH-115688) files: M Include/internal/pycore_opcode_metadata.h M Include/internal/pycore_uop_ids.h M Include/internal/pycore_uop_metadata.h M Lib/test/test_capi/test_opt.py M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/tier2_redundancy_eliminator_bytecodes.c M Python/tier2_redundancy_eliminator_cases.c.h diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index f45e5f1901b0af..ab34366ab1066c 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -999,9 +999,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CLEANUP_THROW] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [COMPARE_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -[COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, -[COMPARE_OP_INT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, -[COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, +[COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, +[COMPARE_OP_INT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, +[COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, @@ -1221,9 +1221,9 @@ _PyOpcode_macro_expansion[256] = { [CHECK_EG_MATCH] = { .nuops = 1, .uops = { { _CHECK_EG_MATCH, 0, 0 } } }, [CHECK_EXC_MATCH] = { .nuops = 1, .uops = { { _CHECK_EXC_MATCH, 0, 0 } } }, [COMPARE_OP] = { .nuops = 1, .uops = { { _COMPARE_OP, 0, 0 } } }, -[COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { _COMPARE_OP_FLOAT, 0, 0 } } }, -[COMPARE_OP_INT] = { .nuops = 1, .uops = { { _COMPARE_OP_INT, 0, 0 } } }, -[COMPARE_OP_STR] = { .nuops = 1, .uops = { { _COMPARE_OP_STR, 0, 0 } } }, +[COMPARE_OP_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _COMPARE_OP_FLOAT, 0, 0 } } }, +[COMPARE_OP_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _COMPARE_OP_INT, 0, 0 } } }, +[COMPARE_OP_STR] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _COMPARE_OP_STR, 0, 0 } } }, [CONTAINS_OP] = { .nuops = 1, .uops = { { _CONTAINS_OP, 0, 0 } } }, [CONVERT_VALUE] = { .nuops = 1, .uops = { { _CONVERT_VALUE, 0, 0 } } }, [COPY] = { .nuops = 1, .uops = { { _COPY, 0, 0 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index e098852d941f18..3c133d97b2f03e 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -72,9 +72,9 @@ extern "C" { #define _CHECK_VALIDITY_AND_SET_IP 324 #define _COLD_EXIT 325 #define _COMPARE_OP 326 -#define _COMPARE_OP_FLOAT COMPARE_OP_FLOAT -#define _COMPARE_OP_INT COMPARE_OP_INT -#define _COMPARE_OP_STR COMPARE_OP_STR +#define _COMPARE_OP_FLOAT 327 +#define _COMPARE_OP_INT 328 +#define _COMPARE_OP_STR 329 #define _CONTAINS_OP CONTAINS_OP #define _CONVERT_VALUE CONVERT_VALUE #define _COPY COPY @@ -89,41 +89,41 @@ extern "C" { #define _DICT_UPDATE DICT_UPDATE #define _END_SEND END_SEND #define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _FATAL_ERROR 327 +#define _FATAL_ERROR 330 #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 328 +#define _FOR_ITER 331 #define _FOR_ITER_GEN FOR_ITER_GEN -#define _FOR_ITER_TIER_TWO 329 +#define _FOR_ITER_TIER_TWO 332 #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE #define _GET_ITER GET_ITER #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _GUARD_BOTH_FLOAT 330 -#define _GUARD_BOTH_INT 331 -#define _GUARD_BOTH_UNICODE 332 -#define _GUARD_BUILTINS_VERSION 333 -#define _GUARD_DORV_VALUES 334 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 335 -#define _GUARD_GLOBALS_VERSION 336 -#define _GUARD_IS_FALSE_POP 337 -#define _GUARD_IS_NONE_POP 338 -#define _GUARD_IS_NOT_NONE_POP 339 -#define _GUARD_IS_TRUE_POP 340 -#define _GUARD_KEYS_VERSION 341 -#define _GUARD_NOT_EXHAUSTED_LIST 342 -#define _GUARD_NOT_EXHAUSTED_RANGE 343 -#define _GUARD_NOT_EXHAUSTED_TUPLE 344 -#define _GUARD_TYPE_
[Python-checkins] gh-114058: More robust method handling in redundancy eliminator (GH-115779)
https://github.com/python/cpython/commit/a33ffe4785f90f68227ddf2ec3e06d5ceaf76cec commit: a33ffe4785f90f68227ddf2ec3e06d5ceaf76cec branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-23T15:42:03+08:00 summary: gh-114058: More robust method handling in redundancy eliminator (GH-115779) files: M Python/optimizer_analysis.c M Python/tier2_redundancy_eliminator_bytecodes.c M Python/tier2_redundancy_eliminator_cases.c.h diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 68ef8254b494a4..9503dcc74656cd 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -315,6 +315,7 @@ sym_new_known_notnull(_Py_UOpsAbstractInterpContext *ctx) if (res == NULL) { return NULL; } +sym_set_flag(res, KNOWN); sym_set_flag(res, NOT_NULL); return res; } diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index ff2b9a42272863..ef7b43d53539ce 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -295,6 +295,27 @@ dummy_func(void) { (void)owner; } +op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { +OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); +OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +} + +op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) { +OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); +OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +} + +op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self if (1))) { +OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); +OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +} + +op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, unused, unused[oparg] -- func, self, unused[oparg])) { +OUT_OF_SPACE_IF_NULL(func = sym_new_known_notnull(ctx)); +OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +} + + op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { sym_set_type(callable, &PyFunction_Type); (void)self_or_null; diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 58c11b7a1c87e0..ca9b5953d21012 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -1300,12 +1300,13 @@ } case _LOAD_ATTR_METHOD_WITH_VALUES: { +_Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; -attr = sym_new_unknown(ctx); -if (attr == NULL) goto out_of_space; -self = sym_new_unknown(ctx); -if (self == NULL) goto out_of_space; +owner = stack_pointer[-1]; +PyObject *descr = (PyObject *)this_instr->operand; +OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); +OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; @@ -1313,12 +1314,13 @@ } case _LOAD_ATTR_METHOD_NO_DICT: { +_Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; -attr = sym_new_unknown(ctx); -if (attr == NULL) goto out_of_space; -self = sym_new_unknown(ctx); -if (self == NULL) goto out_of_space; +owner = stack_pointer[-1]; +PyObject *descr = (PyObject *)this_instr->operand; +OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); +OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; @@ -1346,12 +1348,13 @@ } case _LOAD_ATTR_METHOD_LAZY_DICT: { +_Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; -attr = sym_new_unknown(ctx); -if (attr == NULL) goto out_of_space; -self = sym_new_unknown(ctx); -if (self == NULL) goto out_of_space; +owner = stack_pointer[-1]; +PyObject *descr = (PyObject *)this_instr->operand; +OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); +OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; @@ -1373,12 +1376,12 @@ } case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { +_Py_UOpsSymType *callable; _Py_UOpsSymType *func; _Py_UOpsSymType *self; -func = sy
[Python-checkins] gh-114058: Improve method information in redundancy eliminator (GH-115848)
https://github.com/python/cpython/commit/2ec50b4a66de6be418bfad058117249d4775df0f commit: 2ec50b4a66de6be418bfad058117249d4775df0f branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-23T23:41:10+08:00 summary: gh-114058: Improve method information in redundancy eliminator (GH-115848) files: M Python/tier2_redundancy_eliminator_bytecodes.c M Python/tier2_redundancy_eliminator_cases.c.h diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index ef7b43d53539ce..b9afd3089e1077 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -296,21 +296,25 @@ dummy_func(void) { } op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { +(void)descr; OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); -OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +self = owner; } op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) { +(void)descr; OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); -OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +self = owner; } op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self if (1))) { +(void)descr; OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); -OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +self = owner; } op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, unused, unused[oparg] -- func, self, unused[oparg])) { +(void)callable; OUT_OF_SPACE_IF_NULL(func = sym_new_known_notnull(ctx)); OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index ca9b5953d21012..ca341e4dde5d93 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -1305,8 +1305,9 @@ _Py_UOpsSymType *self = NULL; owner = stack_pointer[-1]; PyObject *descr = (PyObject *)this_instr->operand; +(void)descr; OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); -OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +self = owner; stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; @@ -1319,8 +1320,9 @@ _Py_UOpsSymType *self = NULL; owner = stack_pointer[-1]; PyObject *descr = (PyObject *)this_instr->operand; +(void)descr; OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); -OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +self = owner; stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; @@ -1353,8 +1355,9 @@ _Py_UOpsSymType *self = NULL; owner = stack_pointer[-1]; PyObject *descr = (PyObject *)this_instr->operand; +(void)descr; OUT_OF_SPACE_IF_NULL(attr = sym_new_known_notnull(ctx)); -OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); +self = owner; stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; @@ -1380,6 +1383,7 @@ _Py_UOpsSymType *func; _Py_UOpsSymType *self; callable = stack_pointer[-2 - oparg]; +(void)callable; OUT_OF_SPACE_IF_NULL(func = sym_new_known_notnull(ctx)); OUT_OF_SPACE_IF_NULL(self = sym_new_known_notnull(ctx)); stack_pointer[-2 - oparg] = func; ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-115859: Disable the tier 2 redundancy eliminator by default (GH-115860)
https://github.com/python/cpython/commit/3d8fc06d4f8dc1e7be2455a7e89b37285fa89112 commit: 3d8fc06d4f8dc1e7be2455a7e89b37285fa89112 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-02-23T18:43:52Z summary: gh-115859: Disable the tier 2 redundancy eliminator by default (GH-115860) files: M Lib/test/test_capi/test_opt.py M Python/optimizer_analysis.c diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 38c6fa4b47d0c9..25fc36dec93ddc 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -4,6 +4,7 @@ import textwrap import unittest import gc +import os import _testinternalcapi @@ -568,6 +569,8 @@ def testfunc(n): count = ops.count("_GUARD_IS_TRUE_POP") + ops.count("_GUARD_IS_FALSE_POP") self.assertLessEqual(count, 2) + +@unittest.skipIf(os.getenv("PYTHONUOPSOPTIMIZE", default=0) == 0, "Needs uop optimizer to run.") class TestUopsOptimization(unittest.TestCase): def _run_with_optimizer(self, testfunc, arg): diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 9503dcc74656cd..47bfc8cf1061d9 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -810,9 +810,12 @@ _Py_uop_analyze_and_optimize( peephole_opt(frame, buffer, buffer_size); -err = uop_redundancy_eliminator( -(PyCodeObject *)frame->f_executable, buffer, -buffer_size, curr_stacklen, dependencies); +char *uop_optimize = Py_GETENV("PYTHONUOPSOPTIMIZE"); +if (uop_optimize != NULL && *uop_optimize > '0') { +err = uop_redundancy_eliminator( +(PyCodeObject *)frame->f_executable, buffer, +buffer_size, curr_stacklen, dependencies); +} if (err == 0) { goto not_ready; ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-115168: Add pystats counter for invalidated executors (GH-115169)
https://github.com/python/cpython/commit/b05afdd5ec325bdb4cc89bb3be177ed577bea41f commit: b05afdd5ec325bdb4cc89bb3be177ed577bea41f branch: main author: Michael Droettboom committer: Fidget-Spinner date: 2024-02-26T17:51:47Z summary: gh-115168: Add pystats counter for invalidated executors (GH-115169) files: M Include/cpython/optimizer.h M Include/cpython/pystats.h M Modules/_testinternalcapi.c M Python/instrumentation.c M Python/optimizer.c M Python/optimizer_analysis.c M Python/pylifecycle.c M Python/pystate.c M Python/specialize.c M Python/sysmodule.c M Tools/scripts/summarize_stats.py diff --git a/Include/cpython/optimizer.h b/Include/cpython/optimizer.h index fe54d1ddfe6129..8fc9fb62aebdb4 100644 --- a/Include/cpython/optimizer.h +++ b/Include/cpython/optimizer.h @@ -100,8 +100,8 @@ void _Py_ExecutorClear(_PyExecutorObject *); void _Py_BloomFilter_Init(_PyBloomFilter *); void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj); PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); -PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj); -extern void _Py_Executors_InvalidateAll(PyInterpreterState *interp); +PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation); +extern void _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation); /* For testing */ PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewCounter(void); diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index db9aaedec950e4..887fbbedf88502 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -115,6 +115,7 @@ typedef struct _optimization_stats { uint64_t inner_loop; uint64_t recursive_call; uint64_t low_confidence; +uint64_t executors_invalidated; UOpStats opcode[512]; uint64_t unsupported_opcode[256]; uint64_t trace_length_hist[_Py_UOP_HIST_SIZE]; diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 0d23b1899f22e4..5b714ca3f3dc33 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1035,7 +1035,7 @@ static PyObject * invalidate_executors(PyObject *self, PyObject *obj) { PyInterpreterState *interp = PyInterpreterState_Get(); -_Py_Executors_InvalidateDependency(interp, obj); +_Py_Executors_InvalidateDependency(interp, obj, 1); Py_RETURN_NONE; } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 878d19f0552bf5..6f1bc2e0a107df 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1599,7 +1599,7 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) if (code->co_executors != NULL) { _PyCode_Clear_Executors(code); } -_Py_Executors_InvalidateDependency(interp, code); +_Py_Executors_InvalidateDependency(interp, code, 1); int code_len = (int)Py_SIZE(code); /* Exit early to avoid creating instrumentation * data for potential statically allocated code @@ -1820,7 +1820,7 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) return -1; } set_global_version(tstate, new_version); -_Py_Executors_InvalidateAll(interp); +_Py_Executors_InvalidateAll(interp, 1); return instrument_all_executing_code_objects(interp); } @@ -1850,7 +1850,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent /* Force instrumentation update */ code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT; } -_Py_Executors_InvalidateDependency(interp, code); +_Py_Executors_InvalidateDependency(interp, code, 1); if (_Py_Instrument(code, interp)) { return -1; } diff --git a/Python/optimizer.c b/Python/optimizer.c index 6b2ba3addefc95..c04ee17ee2171d 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1348,7 +1348,7 @@ _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj) * May cause other executors to be invalidated as well */ void -_Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj) +_Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation) { _PyBloomFilter obj_filter; _Py_BloomFilter_Init(&obj_filter); @@ -1360,6 +1360,9 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj) _PyExecutorObject *next = exec->vm_data.links.next; if (bloom_filter_may_contain(&exec->vm_data.bloom, &obj_filter)) { _Py_ExecutorClear(exec); +if (is_invalidation) { +OPT_STAT_INC(executors_invalidated); +} } exec = next; } @@ -1367,7 +1370,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj) /* Invalidate all executors */ void -_Py_Executors_InvalidateAll(PyInterpreterState *interp) +_Py_Executors_InvalidateAll(PyInter
[Python-checkins] gh-115685: Type/values propagate for TO_BOOL in tier 2 (GH-115686)
https://github.com/python/cpython/commit/d01886c5c9e3a62921b304ba7e5145daaa56d3cf commit: d01886c5c9e3a62921b304ba7e5145daaa56d3cf branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-03-01T06:13:38+08:00 summary: gh-115685: Type/values propagate for TO_BOOL in tier 2 (GH-115686) files: M Include/internal/pycore_uop_ids.h M Include/internal/pycore_uop_metadata.h M Python/bytecodes.c M Python/executor_cases.c.h M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 3c133d97b2f03e..8f71eab44d914d 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -216,42 +216,43 @@ extern "C" { #define _POP_JUMP_IF_FALSE 402 #define _POP_JUMP_IF_TRUE 403 #define _POP_TOP POP_TOP +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 404 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 404 +#define _PUSH_FRAME 405 #define _PUSH_NULL PUSH_NULL #define _RESUME_CHECK RESUME_CHECK -#define _SAVE_RETURN_OFFSET 405 -#define _SEND 406 +#define _SAVE_RETURN_OFFSET 406 +#define _SEND 407 #define _SEND_GEN SEND_GEN #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 407 -#define _STORE_ATTR 408 -#define _STORE_ATTR_INSTANCE_VALUE 409 -#define _STORE_ATTR_SLOT 410 +#define _START_EXECUTOR 408 +#define _STORE_ATTR 409 +#define _STORE_ATTR_INSTANCE_VALUE 410 +#define _STORE_ATTR_SLOT 411 #define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 411 -#define _STORE_FAST_0 412 -#define _STORE_FAST_1 413 -#define _STORE_FAST_2 414 -#define _STORE_FAST_3 415 -#define _STORE_FAST_4 416 -#define _STORE_FAST_5 417 -#define _STORE_FAST_6 418 -#define _STORE_FAST_7 419 +#define _STORE_FAST 412 +#define _STORE_FAST_0 413 +#define _STORE_FAST_1 414 +#define _STORE_FAST_2 415 +#define _STORE_FAST_3 416 +#define _STORE_FAST_4 417 +#define _STORE_FAST_5 418 +#define _STORE_FAST_6 419 +#define _STORE_FAST_7 420 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME #define _STORE_SLICE STORE_SLICE -#define _STORE_SUBSCR 420 +#define _STORE_SUBSCR 421 #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _SWAP SWAP -#define _TO_BOOL 421 +#define _TO_BOOL 422 #define _TO_BOOL_ALWAYS_TRUE TO_BOOL_ALWAYS_TRUE #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT @@ -262,12 +263,12 @@ extern "C" { #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 422 +#define _UNPACK_SEQUENCE 423 #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE #define _WITH_EXCEPT_START WITH_EXCEPT_START -#define MAX_UOP_ID 422 +#define MAX_UOP_ID 423 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 35340fe9ee1b63..7f921a6cd3f4c8 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -232,6 +232,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, [_LOAD_CONST_INLINE] = HAS_PURE_FLAG, [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, +[_POP_TOP_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG, [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG, [_CHECK_GLOBALS] = HAS_DEOPT_FLAG, @@ -425,6 +426,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_POP_EXCEPT] = "_POP_EXCEPT", [_POP_FRAME] = "_POP_FRAME", [_POP_TOP] = "_POP_TOP", +[_POP_TOP_LOAD_CONST_INLINE_BORROW] = "_POP_TOP_LOAD_CONST_INLINE_BORROW", [_PUSH_EXC_INFO] = "_PUSH_EXC_INFO", [_PUSH_FRAME] = "_PUSH_FRAME", [_PUSH_NULL] = "_PUSH_NULL", diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1d515098f6c7e9..095982d64f34d0 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4043,6 +4043,11 @@ dummy_func( value = ptr; } +tier2 pure op (_POP_TOP_LOAD_CONST_INLINE_BORROW, (ptr/4, pop -- value)) { +Py_DECREF(pop); +value = ptr; +} + tier2 pure op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { value = Py_NewRef(ptr); null = NULL; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 9ec1be9076a5a0..e84c33281ee640 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3759,6 +3759,17 @@ break;
[Python-checkins] gh-115480: Type propagate _BINARY_OP_ADD_UNICODE (GH-115710)
https://github.com/python/cpython/commit/ff96b81d78c4a52fb1eb8384300af3dd0dd2db0d commit: ff96b81d78c4a52fb1eb8384300af3dd0dd2db0d branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-03-02T03:40:04+08:00 summary: gh-115480: Type propagate _BINARY_OP_ADD_UNICODE (GH-115710) files: M Lib/test/test_capi/test_opt.py M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index f4fcdea05e96bf..a0a19225b79433 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -795,11 +795,14 @@ def test_float_add_constant_propagation(self): def testfunc(n): a = 1.0 for _ in range(n): -a = a + 0.1 +a = a + 0.25 +a = a + 0.25 +a = a + 0.25 +a = a + 0.25 return a res, ex = self._run_with_optimizer(testfunc, 32) -self.assertAlmostEqual(res, 4.2) +self.assertAlmostEqual(res, 33.0) self.assertIsNotNone(ex) uops = get_opnames(ex) guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"] @@ -812,11 +815,14 @@ def test_float_subtract_constant_propagation(self): def testfunc(n): a = 1.0 for _ in range(n): -a = a - 0.1 +a = a - 0.25 +a = a - 0.25 +a = a - 0.25 +a = a - 0.25 return a res, ex = self._run_with_optimizer(testfunc, 32) -self.assertAlmostEqual(res, -2.2) +self.assertAlmostEqual(res, -31.0) self.assertIsNotNone(ex) uops = get_opnames(ex) guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"] @@ -829,11 +835,14 @@ def test_float_multiply_constant_propagation(self): def testfunc(n): a = 1.0 for _ in range(n): -a = a * 2.0 +a = a * 1.0 +a = a * 1.0 +a = a * 1.0 +a = a * 1.0 return a res, ex = self._run_with_optimizer(testfunc, 32) -self.assertAlmostEqual(res, 2 ** 32) +self.assertAlmostEqual(res, 1.0) self.assertIsNotNone(ex) uops = get_opnames(ex) guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"] @@ -842,6 +851,24 @@ def testfunc(n): # We'll also need to verify that propagation actually occurs. self.assertIn("_BINARY_OP_MULTIPLY_FLOAT", uops) +def test_add_unicode_propagation(self): +def testfunc(n): +a = "" +for _ in range(n): +a + a +a + a +a + a +a + a +return a + +res, ex = self._run_with_optimizer(testfunc, 32) +self.assertEqual(res, "") +self.assertIsNotNone(ex) +uops = get_opnames(ex) +guard_both_unicode_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_UNICODE"] +self.assertLessEqual(len(guard_both_unicode_count), 1) +self.assertIn("_BINARY_OP_ADD_UNICODE", uops) + def test_compare_op_type_propagation_float(self): def testfunc(n): a = 1.0 diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 2b47381ec76db4..786d884fc5a1a8 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -254,6 +254,22 @@ dummy_func(void) { } } +op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { +if (sym_is_const(left) && sym_is_const(right) && +sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) { +PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right)); +if (temp == NULL) { +goto error; +} +res = sym_new_const(ctx, temp); +Py_DECREF(temp); +OUT_OF_SPACE_IF_NULL(res); +} +else { +OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyUnicode_Type)); +} +} + op(_TO_BOOL, (value -- res)) { (void)value; res = sym_new_type(ctx, &PyBool_Type); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 9d7ebb80f62857..6d3488f2118589 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -446,9 +446,24 @@ } case _BINARY_OP_ADD_UNICODE: { +_Py_UopsSymbol *right; +_Py_UopsSymbol *left; _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); -if (res == NULL) goto out_of_space; +
[Python-checkins] gh-116381: Specialize CONTAINS_OP (GH-116385)
https://github.com/python/cpython/commit/7114cf20c015b99123b32c1ba4f5475b7a6c3a13 commit: 7114cf20c015b99123b32c1ba4f5475b7a6c3a13 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-03-07T03:30:11+08:00 summary: gh-116381: Specialize CONTAINS_OP (GH-116385) * Specialize CONTAINS_OP * 📜🤖 Added by blurb_it. * Add PyAPI_FUNC for JIT - Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2024-03-05-22-00-58.gh-issue-116381.0Nq9iO.rst M Include/internal/pycore_code.h M Include/internal/pycore_list.h M Include/internal/pycore_opcode_metadata.h M Include/internal/pycore_setobject.h M Include/internal/pycore_tuple.h M Include/internal/pycore_uop_ids.h M Include/internal/pycore_uop_metadata.h M Include/opcode_ids.h M Lib/_opcode_metadata.py M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Objects/listobject.c M Objects/setobject.c M Objects/tupleobject.c M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/opcode_targets.h M Python/optimizer_cases.c.h M Python/specialize.c diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index a4e64825743ada..8eabd49a18afa9 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -121,6 +121,12 @@ typedef struct { #define INLINE_CACHE_ENTRIES_TO_BOOL CACHE_ENTRIES(_PyToBoolCache) +typedef struct { +uint16_t counter; +} _PyContainsOpCache; + +#define INLINE_CACHE_ENTRIES_CONTAINS_OP CACHE_ENTRIES(_PyContainsOpCache) + // Borrowed references to common callables: struct callable_cache { PyObject *isinstance; @@ -277,6 +283,7 @@ extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, extern void _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr); extern void _Py_Specialize_ToBool(PyObject *value, _Py_CODEUNIT *instr); +extern void _Py_Specialize_ContainsOp(PyObject *value, _Py_CODEUNIT *instr); /* Finalizer function for static codeobjects used in deepfreeze.py */ extern void _PyStaticCode_Fini(PyCodeObject *co); diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 2a82912e41d557..92cab731bc253b 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -56,6 +56,8 @@ typedef struct { PyAPI_FUNC(PyObject *)_PyList_FromArraySteal(PyObject *const *src, Py_ssize_t n); +PyAPI_FUNC(int) _PyList_Contains(PyObject *aa, PyObject *el); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index f355a496cf2e70..4c691d6a922862 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -151,6 +151,16 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 2; case CONTAINS_OP: return 2; +case CONTAINS_OP_DICT: +return 2; +case CONTAINS_OP_LIST: +return 2; +case CONTAINS_OP_SET: +return 2; +case CONTAINS_OP_STR: +return 2; +case CONTAINS_OP_TUPLE: +return 2; case CONVERT_VALUE: return 1; case COPY: @@ -576,6 +586,16 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 1; case CONTAINS_OP: return 1; +case CONTAINS_OP_DICT: +return 1; +case CONTAINS_OP_LIST: +return 1; +case CONTAINS_OP_SET: +return 1; +case CONTAINS_OP_STR: +return 1; +case CONTAINS_OP_TUPLE: +return 1; case CONVERT_VALUE: return 1; case COPY: @@ -1002,7 +1022,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [COMPARE_OP_INT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, -[CONTAINS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +[CONTAINS_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +[CONTAINS_OP_DICT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +[CONTAINS_OP_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +[CONTAINS_OP_SET] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +[CONTAINS_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +[CONTAINS_OP_TUPLE] =
[Python-checkins] gh-116420: Fix unused var compilation warnings (GH-116466)
https://github.com/python/cpython/commit/4298d69d4b2f7d0e9d93ad325238930bd6235dbf commit: 4298d69d4b2f7d0e9d93ad325238930bd6235dbf branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-03-08T00:19:59+08:00 summary: gh-116420: Fix unused var compilation warnings (GH-116466) Fix unused var compilation warnings files: M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 07a1adb8cb8a78..e3f7c9822103e6 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -352,6 +352,8 @@ dummy_func(void) { } op(_COMPARE_OP, (left, right -- res)) { +(void)left; +(void)right; if (oparg & 16) { OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); } @@ -361,22 +363,32 @@ dummy_func(void) { } op(_COMPARE_OP_INT, (left, right -- res)) { +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); } op(_COMPARE_OP_FLOAT, (left, right -- res)) { +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); } op(_COMPARE_OP_STR, (left, right -- res)) { +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); } op(_IS_OP, (left, right -- res)) { +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); } op(_CONTAINS_OP, (left, right -- res)) { +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index a19010cc403681..e4384975643ecd 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1135,6 +1135,8 @@ _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; +(void)left; +(void)right; if (oparg & 16) { OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); } @@ -1152,6 +1154,8 @@ _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); stack_pointer[-2] = res; stack_pointer += -1; @@ -1164,6 +1168,8 @@ _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); stack_pointer[-2] = res; stack_pointer += -1; @@ -1176,6 +1182,8 @@ _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); stack_pointer[-2] = res; stack_pointer += -1; @@ -1188,6 +1196,8 @@ _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); stack_pointer[-2] = res; stack_pointer += -1; @@ -1200,6 +1210,8 @@ _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; +(void)left; +(void)right; OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyBool_Type)); stack_pointer[-2] = res; stack_pointer += -1; ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-116381: Remove bad specializations, add fail stats (GH-116464)
https://github.com/python/cpython/commit/41457c7fdb04819d04a528b8dfa72c1aa5745cc9 commit: 41457c7fdb04819d04a528b8dfa72c1aa5745cc9 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-03-08T00:21:21+08:00 summary: gh-116381: Remove bad specializations, add fail stats (GH-116464) * Remove bad specializations, add fail stats files: M Include/internal/pycore_list.h M Include/internal/pycore_opcode_metadata.h M Include/internal/pycore_tuple.h M Include/internal/pycore_uop_ids.h M Include/internal/pycore_uop_metadata.h M Include/opcode_ids.h M Lib/_opcode_metadata.py M Objects/listobject.c M Objects/tupleobject.c M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/opcode_targets.h M Python/optimizer_cases.c.h M Python/specialize.c M Tools/jit/template.c diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 92cab731bc253b..2a82912e41d557 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -56,8 +56,6 @@ typedef struct { PyAPI_FUNC(PyObject *)_PyList_FromArraySteal(PyObject *const *src, Py_ssize_t n); -PyAPI_FUNC(int) _PyList_Contains(PyObject *aa, PyObject *el); - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 4c691d6a922862..efb731f1863283 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -153,14 +153,8 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 2; case CONTAINS_OP_DICT: return 2; -case CONTAINS_OP_LIST: -return 2; case CONTAINS_OP_SET: return 2; -case CONTAINS_OP_STR: -return 2; -case CONTAINS_OP_TUPLE: -return 2; case CONVERT_VALUE: return 1; case COPY: @@ -588,14 +582,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 1; case CONTAINS_OP_DICT: return 1; -case CONTAINS_OP_LIST: -return 1; case CONTAINS_OP_SET: return 1; -case CONTAINS_OP_STR: -return 1; -case CONTAINS_OP_TUPLE: -return 1; case CONVERT_VALUE: return 1; case COPY: @@ -1024,10 +1012,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP_DICT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -[CONTAINS_OP_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP_SET] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -[CONTAINS_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -[CONTAINS_OP_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, [COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1251,10 +1236,7 @@ _PyOpcode_macro_expansion[256] = { [COMPARE_OP_STR] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _COMPARE_OP_STR, 0, 0 } } }, [CONTAINS_OP] = { .nuops = 1, .uops = { { _CONTAINS_OP, 0, 0 } } }, [CONTAINS_OP_DICT] = { .nuops = 1, .uops = { { _CONTAINS_OP_DICT, 0, 0 } } }, -[CONTAINS_OP_LIST] = { .nuops = 1, .uops = { { _CONTAINS_OP_LIST, 0, 0 } } }, [CONTAINS_OP_SET] = { .nuops = 1, .uops = { { _CONTAINS_OP_SET, 0, 0 } } }, -[CONTAINS_OP_STR] = { .nuops = 1, .uops = { { _CONTAINS_OP_STR, 0, 0 } } }, -[CONTAINS_OP_TUPLE] = { .nuops = 1, .uops = { { _CONTAINS_OP_TUPLE, 0, 0 } } }, [CONVERT_VALUE] = { .nuops = 1, .uops = { { _CONVERT_VALUE, 0, 0 } } }, [COPY] = { .nuops = 1, .uops = { { _COPY, 0, 0 } } }, [COPY_FREE_VARS] = { .nuops = 1, .uops = { { _COPY_FREE_VARS, 0, 0 } } }, @@ -1429,10 +1411,7 @@ const char *_PyOpcode_OpName[268] = { [COMPARE_OP_STR] = "COMPARE_OP_STR", [CONTAINS_OP] = "CONTAINS_OP", [CONTAINS_OP_DICT] = "CONTAINS_OP_DICT", -[CONTAINS_OP_LIST] = "CONTAINS_OP_LIST", [CONTAINS_OP_SET] = "CONTAINS_OP_SET", -[CONTAINS_OP_STR] = "CONTAINS_OP_STR", -[CONTAINS_OP_TUPLE] = "CONTAINS_OP_TUPLE", [CONVERT_VALUE] = "CONVERT_VALUE", [COPY] = "COPY", [COPY_FREE_VARS] = "COPY_FREE_VARS", @@ -1685,10 +1664,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [COMPARE_OP_STR] = COMPARE
[Python-checkins] gh-115419: Change default sym to not_null (GH-116562)
https://github.com/python/cpython/commit/617aca9e745b3dfb5e6bc8cda07632d2f716426d commit: 617aca9e745b3dfb5e6bc8cda07632d2f716426d branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-03-13T20:57:48+08:00 summary: gh-115419: Change default sym to not_null (GH-116562) files: M Lib/test/test_generated_cases.py M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h M Tools/cases_generator/optimizer_generator.py diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 32c2c2fca05c4e..7b9dd36f85454f 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -908,7 +908,7 @@ def test_overridden_abstract_args(self): case OP2: { _Py_UopsSymbol *out; -out = sym_new_unknown(ctx); +out = sym_new_not_null(ctx); if (out == NULL) goto out_of_space; stack_pointer[-1] = out; break; @@ -933,7 +933,7 @@ def test_no_overridden_case(self): output = """ case OP: { _Py_UopsSymbol *out; -out = sym_new_unknown(ctx); +out = sym_new_not_null(ctx); if (out == NULL) goto out_of_space; stack_pointer[-1] = out; break; diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index e3f7c9822103e6..54abbcd74d7934 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -449,6 +449,14 @@ dummy_func(void) { } } +op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { +(void)owner; +OUT_OF_SPACE_IF_NULL(attr = sym_new_not_null(ctx)); +if (oparg & 1) { +OUT_OF_SPACE_IF_NULL(self_or_null = sym_new_unknown(ctx)); +} +} + op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) { (void)index; OUT_OF_SPACE_IF_NULL(null = sym_new_null(ctx)); @@ -513,7 +521,6 @@ dummy_func(void) { OUT_OF_SPACE_IF_NULL(self = sym_new_not_null(ctx)); } - op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { if (!sym_set_type(callable, &PyFunction_Type)) { goto hit_bottom; diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index fed5730d2e50c1..7e4214cc9acf39 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -80,7 +80,7 @@ case _END_SEND: { _Py_UopsSymbol *value; -value = sym_new_unknown(ctx); +value = sym_new_not_null(ctx); if (value == NULL) goto out_of_space; stack_pointer[-2] = value; stack_pointer += -1; @@ -89,7 +89,7 @@ case _UNARY_NEGATIVE: { _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); +res = sym_new_not_null(ctx); if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; @@ -97,7 +97,7 @@ case _UNARY_NOT: { _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); +res = sym_new_not_null(ctx); if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; @@ -205,7 +205,7 @@ case _REPLACE_WITH_TRUE: { _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); +res = sym_new_not_null(ctx); if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; @@ -213,7 +213,7 @@ case _UNARY_INVERT: { _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); +res = sym_new_not_null(ctx); if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; @@ -482,7 +482,7 @@ case _BINARY_SUBSCR: { _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); +res = sym_new_not_null(ctx); if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; @@ -491,7 +491,7 @@ case _BINARY_SLICE: { _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); +res = sym_new_not_null(ctx); if (res == NULL) goto out_of_space; stack_pointer[-3] = res; stack_pointer += -2; @@ -505,7 +505,7 @@ case _BINARY_SUBSCR_LIST_INT: { _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); +res = sym_new_not_null(ctx); if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; @@ -514,7 +514,7 @@ case _BINARY_SUBSCR_STR_INT: { _Py_UopsSymbol *res; -res = sym_new_unknown(ctx); +res = sym_new_not_null(ctx); if (res == NULL) goto out_of_space
[Python-checkins] gh-116760: Fix pystats for trace attempts (GH-116761)
https://github.com/python/cpython/commit/cef0ec1a3ca40db69b56bcd736c1b3bb05a1cf48 commit: cef0ec1a3ca40db69b56bcd736c1b3bb05a1cf48 branch: main author: Michael Droettboom committer: Fidget-Spinner date: 2024-03-13T22:13:33Z summary: gh-116760: Fix pystats for trace attempts (GH-116761) There are now at least two bytecodes that may attempt to optimize, JUMP_BACK, and more recently, COLD_EXIT. Only the JUMP_BACK was counting the attempt in the stats. This moves that counter to uop_optimize itself so it should always happen no matter where it is called from. files: M Python/bytecodes.c M Python/generated_cases.c.h M Python/optimizer.c diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ec05e40bd23fcb..af2e2c8f52ee29 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2349,7 +2349,6 @@ dummy_func( // Use '>=' not '>' so that the optimizer/backoff bits do not effect the result. // Double-check that the opcode isn't instrumented or something: if (offset_counter >= threshold && this_instr->op.code == JUMP_BACKWARD) { -OPT_STAT_INC(attempts); _Py_CODEUNIT *start = this_instr; /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ while (oparg > 255) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 72892725fb25d8..7d02e49d040c23 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3371,7 +3371,6 @@ // Use '>=' not '>' so that the optimizer/backoff bits do not effect the result. // Double-check that the opcode isn't instrumented or something: if (offset_counter >= threshold && this_instr->op.code == JUMP_BACKWARD) { -OPT_STAT_INC(attempts); _Py_CODEUNIT *start = this_instr; /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ while (oparg > 255) { diff --git a/Python/optimizer.c b/Python/optimizer.c index aaf75b2339cd2e..88c45f2e73c682 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1003,6 +1003,7 @@ uop_optimize( _PyBloomFilter dependencies; _Py_BloomFilter_Init(&dependencies); _PyUOpInstruction buffer[UOP_MAX_TRACE_LENGTH]; +OPT_STAT_INC(attempts); int err = translate_bytecode_to_trace(frame, instr, buffer, UOP_MAX_TRACE_LENGTH, &dependencies); if (err <= 0) { // Error or nothing translated ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-116879: Add new optimizer pystats to tables (GH-116880)
https://github.com/python/cpython/commit/1a33513f99bf4a9e5122b9cd82945879e73ff44c commit: 1a33513f99bf4a9e5122b9cd82945879e73ff44c branch: main author: Michael Droettboom committer: Fidget-Spinner date: 2024-03-16T23:10:43+08:00 summary: gh-116879: Add new optimizer pystats to tables (GH-116880) files: M Tools/scripts/summarize_stats.py diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index 2925e096f4d95e..6af14e1b769b80 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -459,10 +459,7 @@ def get_optimization_stats(self) -> dict[str, tuple[int, int | None]]: "The number of times a potential trace is identified. Specifically, this " "occurs in the JUMP BACKWARD instruction when the counter reaches a " "threshold.", -): ( -attempts, -None, -), +): (attempts, None), Doc( "Traces created", "The number of traces that were successfully created." ): (created, attempts), @@ -512,6 +509,26 @@ def get_optimization_stats(self) -> dict[str, tuple[int, int | None]]: ), } +def get_optimizer_stats(self) -> dict[str, tuple[int, int | None]]: +attempts = self._data["Optimization optimizer attempts"] +successes = self._data["Optimization optimizer successes"] +no_memory = self._data["Optimization optimizer failure no memory"] + +return { +Doc( +"Optimizer attempts", +"The number of times the trace optimizer (_Py_uop_analyze_and_optimize) was run.", +): (attempts, None), +Doc( +"Optimizer successes", +"The number of traces that were successfully optimized.", +): (successes, attempts), +Doc( +"Optimizer no memory", +"The number of optimizations that failed due to no memory.", +): (no_memory, attempts), +} + def get_histogram(self, prefix: str) -> list[tuple[int, int]]: rows = [] for k, v in self._data.items(): @@ -1118,6 +1135,14 @@ def calc_optimization_table(stats: Stats) -> Rows: for label, (value, den) in optimization_stats.items() ] +def calc_optimizer_table(stats: Stats) -> Rows: +optimizer_stats = stats.get_optimizer_stats() + +return [ +(label, Count(value), Ratio(value, den)) +for label, (value, den) in optimizer_stats.items() +] + def calc_histogram_table(key: str, den: str) -> RowCalculator: def calc(stats: Stats) -> Rows: histogram = stats.get_histogram(key) @@ -1159,6 +1184,7 @@ def iter_optimization_tables(base_stats: Stats, head_stats: Stats | None = None) return yield Table(("", "Count:", "Ratio:"), calc_optimization_table, JoinMode.CHANGE) +yield Table(("", "Count:", "Ratio:"), calc_optimizer_table, JoinMode.CHANGE) for name, den in [ ("Trace length", "Optimization traces created"), ("Optimized trace length", "Optimization traces created"), ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-116996: Add pystats about _Py_uop_analyse_and_optimize (GH-116997)
https://github.com/python/cpython/commit/50369e6c34d05222e5a0ec9443a9f7b230e83112 commit: 50369e6c34d05222e5a0ec9443a9f7b230e83112 branch: main author: Michael Droettboom committer: Fidget-Spinner date: 2024-03-22T01:27:46+08:00 summary: gh-116996: Add pystats about _Py_uop_analyse_and_optimize (GH-116997) files: M Include/cpython/pystats.h M Include/internal/pycore_code.h M Python/optimizer_analysis.c M Python/specialize.c M Tools/scripts/summarize_stats.py diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index 887fbbedf88502..5bf7bacd514699 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -19,6 +19,8 @@ // Define _PY_INTERPRETER macro to increment interpreter_increfs and // interpreter_decrefs. Otherwise, increment increfs and decrefs. +#include "pycore_uop_ids.h" + #ifndef Py_CPYTHON_PYSTATS_H # error "this header file must not be included directly" #endif @@ -116,7 +118,7 @@ typedef struct _optimization_stats { uint64_t recursive_call; uint64_t low_confidence; uint64_t executors_invalidated; -UOpStats opcode[512]; +UOpStats opcode[MAX_UOP_ID]; uint64_t unsupported_opcode[256]; uint64_t trace_length_hist[_Py_UOP_HIST_SIZE]; uint64_t trace_run_length_hist[_Py_UOP_HIST_SIZE]; @@ -124,6 +126,9 @@ typedef struct _optimization_stats { uint64_t optimizer_attempts; uint64_t optimizer_successes; uint64_t optimizer_failure_reason_no_memory; +uint64_t remove_globals_builtins_changed; +uint64_t remove_globals_incorrect_keys; +uint64_t error_in_opcode[MAX_UOP_ID]; } OptimizationStats; typedef struct _rare_event_stats { diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 8eabd49a18afa9..e004783ee48198 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -308,6 +308,7 @@ extern int _PyStaticCode_Init(PyCodeObject *co); #define OPT_STAT_INC(name) do { if (_Py_stats) _Py_stats->optimization_stats.name++; } while (0) #define UOP_STAT_INC(opname, name) do { if (_Py_stats) { assert(opname < 512); _Py_stats->optimization_stats.opcode[opname].name++; } } while (0) #define OPT_UNSUPPORTED_OPCODE(opname) do { if (_Py_stats) _Py_stats->optimization_stats.unsupported_opcode[opname]++; } while (0) +#define OPT_ERROR_IN_OPCODE(opname) do { if (_Py_stats) _Py_stats->optimization_stats.error_in_opcode[opname]++; } while (0) #define OPT_HIST(length, name) \ do { \ if (_Py_stats) { \ @@ -334,6 +335,7 @@ PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void); #define OPT_STAT_INC(name) ((void)0) #define UOP_STAT_INC(opname, name) ((void)0) #define OPT_UNSUPPORTED_OPCODE(opname) ((void)0) +#define OPT_ERROR_IN_OPCODE(opname) ((void)0) #define OPT_HIST(length, name) ((void)0) #define RARE_EVENT_STAT_INC(name) ((void)0) #endif // !Py_STATS diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 603ac6815665ca..6c460c5359d71e 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -139,6 +139,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *builtins = frame->f_builtins; if (builtins != interp->builtins) { +OPT_STAT_INC(remove_globals_builtins_changed); return 1; } PyObject *globals = frame->f_globals; @@ -170,6 +171,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, switch(opcode) { case _GUARD_BUILTINS_VERSION: if (incorrect_keys(inst, builtins)) { +OPT_STAT_INC(remove_globals_incorrect_keys); return 0; } if (interp->rare_events.builtin_dict >= _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) { @@ -190,6 +192,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, break; case _GUARD_GLOBALS_VERSION: if (incorrect_keys(inst, globals)) { +OPT_STAT_INC(remove_globals_incorrect_keys); return 0; } uint64_t watched_mutations = get_mutations(globals); @@ -238,6 +241,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, globals = func->func_globals; builtins = func->func_builtins; if (builtins != interp->builtins) { +OPT_STAT_INC(remove_globals_builtins_changed); return 1; } break; @@ -358,6 +362,7 @@ optimize_uops( _Py_UOpsContext context; _Py_UOpsContext *ctx = &context; +uint32_t opcode = UINT16_MAX; if (_Py_uop_abstractcontext_init(ctx) < 0) { goto out_of_space; @@ -374,8 +379,7 @@ optimize_uops( this_instr++) { int oparg
[Python-checkins] gh-117180: Complete call sequence when trace stack overflow (GH-117184)
https://github.com/python/cpython/commit/6c83352bfe78a7d567c8d76257df6eb91d5a7245 commit: 6c83352bfe78a7d567c8d76257df6eb91d5a7245 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-03-24T06:19:17+08:00 summary: gh-117180: Complete call sequence when trace stack overflow (GH-117184) - Co-authored-by: Peter Lazorchak Co-authored-by: Guido van Rossum Co-authored-by: Guido van Rossum files: M Lib/test/test_capi/test_opt.py M Python/optimizer.c diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index b0859a382de523..a1dc03dd3b651b 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -955,6 +955,32 @@ def testfunc(n): _, ex = self._run_with_optimizer(testfunc, 16) self.assertIsNone(ex) +def test_many_nested(self): +# overflow the trace_stack +def dummy_a(x): +return x +def dummy_b(x): +return dummy_a(x) +def dummy_c(x): +return dummy_b(x) +def dummy_d(x): +return dummy_c(x) +def dummy_e(x): +return dummy_d(x) +def dummy_f(x): +return dummy_e(x) +def dummy_g(x): +return dummy_f(x) +def dummy_h(x): +return dummy_g(x) +def testfunc(n): +a = 0 +for _ in range(n): +a += dummy_h(n) +return a + +self._run_with_optimizer(testfunc, 32) + if __name__ == "__main__": unittest.main() diff --git a/Python/optimizer.c b/Python/optimizer.c index 177ad343618c37..f8c1390a061650 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -476,6 +476,7 @@ BRANCH_TO_GUARD[4][2] = { if (trace_stack_depth >= TRACE_STACK_SIZE) { \ DPRINTF(2, "Trace stack overflow\n"); \ OPT_STAT_INC(trace_stack_overflow); \ +ADD_TO_TRACE(uop, oparg, operand, target); \ ADD_TO_TRACE(_EXIT_TRACE, 0, 0, 0); \ goto done; \ } \ ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-117339: Use NULL instead of None for LOAD_SUPER_ATTR in dis docs (GH-117343)
https://github.com/python/cpython/commit/a17f313e3958e825db9a83594c8471a984316536 commit: a17f313e3958e825db9a83594c8471a984316536 branch: main author: Christopher Chianelli committer: Fidget-Spinner date: 2024-03-29T06:26:56+08:00 summary: gh-117339: Use NULL instead of None for LOAD_SUPER_ATTR in dis docs (GH-117343) files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 190e994a12cc71..21ac2c87a1859e 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1224,7 +1224,7 @@ iterations of the loop. except that ``namei`` is shifted left by 2 bits instead of 1. The low bit of ``namei`` signals to attempt a method load, as with - :opcode:`LOAD_ATTR`, which results in pushing ``None`` and the loaded method. + :opcode:`LOAD_ATTR`, which results in pushing ``NULL`` and the loaded method. When it is unset a single value is pushed to the stack. The second-low bit of ``namei``, if set, means that this was a two-argument ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] [3.12] gh-117339: Use NULL instead of None for LOAD_SUPER_ATTR in dis docs (GH-117343) (GH-117345)
https://github.com/python/cpython/commit/655c4255fcb8ff73a720db7d5aa4dbb9b2e809e6 commit: 655c4255fcb8ff73a720db7d5aa4dbb9b2e809e6 branch: 3.12 author: Christopher Chianelli committer: Fidget-Spinner date: 2024-03-29T06:27:16+08:00 summary: [3.12] gh-117339: Use NULL instead of None for LOAD_SUPER_ATTR in dis docs (GH-117343) (GH-117345) files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index abcc3cde23526c..2dd11e03894f99 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1116,7 +1116,7 @@ iterations of the loop. except that ``namei`` is shifted left by 2 bits instead of 1. The low bit of ``namei`` signals to attempt a method load, as with - :opcode:`LOAD_ATTR`, which results in pushing ``None`` and the loaded method. + :opcode:`LOAD_ATTR`, which results in pushing ``NULL`` and the loaded method. When it is unset a single value is pushed to the stack. The second-low bit of ``namei``, if set, means that this was a two-argument ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] Cases generator: Remove type_prop and passthrough (#117614)
https://github.com/python/cpython/commit/375425abd17310480988c48fba57b01e8c979e07 commit: 375425abd17310480988c48fba57b01e8c979e07 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-04-08T06:26:52+08:00 summary: Cases generator: Remove type_prop and passthrough (#117614) files: M Include/internal/pycore_uop_metadata.h M Tools/cases_generator/analyzer.py M Tools/cases_generator/generators_common.py diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 111824a938f6cc..e5a99421c241e0 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -51,22 +51,22 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_UNARY_NOT] = HAS_PURE_FLAG, [_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -[_TO_BOOL_BOOL] = HAS_EXIT_FLAG | HAS_PASSTHROUGH_FLAG, +[_TO_BOOL_BOOL] = HAS_EXIT_FLAG, [_TO_BOOL_INT] = HAS_EXIT_FLAG, [_TO_BOOL_LIST] = HAS_EXIT_FLAG, [_TO_BOOL_NONE] = HAS_EXIT_FLAG, [_TO_BOOL_STR] = HAS_EXIT_FLAG, [_REPLACE_WITH_TRUE] = 0, [_UNARY_INVERT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -[_GUARD_BOTH_INT] = HAS_EXIT_FLAG | HAS_PASSTHROUGH_FLAG, +[_GUARD_BOTH_INT] = HAS_EXIT_FLAG, [_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, -[_GUARD_BOTH_FLOAT] = HAS_EXIT_FLAG | HAS_PASSTHROUGH_FLAG, +[_GUARD_BOTH_FLOAT] = HAS_EXIT_FLAG, [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG, [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG, [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG, -[_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG | HAS_PASSTHROUGH_FLAG, +[_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG, [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -129,23 +129,23 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_SUPER_ATTR_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_SUPER_ATTR_METHOD] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -[_GUARD_TYPE_VERSION] = HAS_EXIT_FLAG | HAS_PASSTHROUGH_FLAG, -[_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, +[_GUARD_TYPE_VERSION] = HAS_EXIT_FLAG, +[_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG, [_LOAD_ATTR_INSTANCE_VALUE_0] = HAS_DEOPT_FLAG, [_LOAD_ATTR_INSTANCE_VALUE_1] = HAS_DEOPT_FLAG, [_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, -[_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, +[_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG, [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -[_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, +[_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG, [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG, [_LOAD_ATTR_SLOT_0] = HAS_DEOPT_FLAG, [_LOAD_ATTR_SLOT_1] = HAS_DEOPT_FLAG, [_LOAD_ATTR_SLOT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, -[_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, +[_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG, [_LOAD_ATTR_CLASS_0] = 0, [_LOAD_ATTR_CLASS_1] = 0, [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG | HAS_OPARG_AND_1_FLAG, -[_GUARD_DORV_NO_DICT] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, +[_GUARD_DORV_NO_DICT] = HAS_DEOPT_FLAG, [_STORE_ATTR_INSTANCE_VALUE] = 0, [_STORE_ATTR_SLOT] = HAS_ESCAPES_FLAG, [_COMPARE_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -167,31 +167,31 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GET_ITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GET_YIELD_FROM_ITER] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_FOR_ITER_TIER_TWO] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, -[_ITER_CHECK_LIST] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, -[_GUARD_NOT_EXHAUSTED_LIST] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, +[_ITER_CHECK_LIST] = HAS_DEOPT_FLAG, +[_GUARD_NOT_EXHAUSTED_LIST] = HAS_DEOPT_FLAG, [_ITER_NEXT_LIST] = 0, -[_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, -[_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, +[_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG, +[_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG, [_ITER_NEXT_TUPLE] = 0, -[_ITER_CHECK_RANGE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, -[_GUARD_NOT_EXHAUSTED_RANGE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, +[_ITER_CHECK_RANGE] = HAS_DEOPT_FLAG, +[_GUARD_NOT_EXHAUSTED_RANGE] = HAS_DEOPT_FLAG
[Python-checkins] gh-117139: Add header for tagged pointers (GH-118330)
https://github.com/python/cpython/commit/dc6b12d1b2ea26bb0323d932fa7b1a337eaca562 commit: dc6b12d1b2ea26bb0323d932fa7b1a337eaca562 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-05-01T04:46:13+08:00 summary: gh-117139: Add header for tagged pointers (GH-118330) - Co-authored-by: Sam Gross <655866+colesb...@users.noreply.github.com> files: A Include/internal/pycore_stackref.h M Makefile.pre.in M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h new file mode 100644 index 00..fd929cd4873a8b --- /dev/null +++ b/Include/internal/pycore_stackref.h @@ -0,0 +1,195 @@ +#ifndef Py_INTERNAL_STACKREF_H +#define Py_INTERNAL_STACKREF_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include + +typedef union { +uintptr_t bits; +} _PyStackRef; + +static const _PyStackRef Py_STACKREF_NULL = { .bits = 0 }; + +#define Py_TAG_DEFERRED (1) + +// Gets a PyObject * from a _PyStackRef +#if defined(Py_GIL_DISABLED) +static inline PyObject * +PyStackRef_Get(_PyStackRef tagged) +{ +PyObject *cleared = ((PyObject *)((tagged).bits & (~Py_TAG_DEFERRED))); +return cleared; +} +#else +# define PyStackRef_Get(tagged) ((PyObject *)((tagged).bits)) +#endif + +// Converts a PyObject * to a PyStackRef, stealing the reference. +#if defined(Py_GIL_DISABLED) +static inline _PyStackRef +_PyStackRef_StealRef(PyObject *obj) +{ +// Make sure we don't take an already tagged value. +assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0); +return ((_PyStackRef){.bits = ((uintptr_t)(obj))}); +} +# define PyStackRef_StealRef(obj) _PyStackRef_StealRef(_PyObject_CAST(obj)) +#else +# define PyStackRef_StealRef(obj) ((_PyStackRef){.bits = ((uintptr_t)(obj))}) +#endif + +// Converts a PyObject * to a PyStackRef, with a new reference +#if defined(Py_GIL_DISABLED) +static inline _PyStackRef +_PyStackRef_NewRefDeferred(PyObject *obj) +{ +// Make sure we don't take an already tagged value. +assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0); +assert(obj != NULL); +if (_PyObject_HasDeferredRefcount(obj)) { +return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED }; +} +else { +return (_PyStackRef){ .bits = (uintptr_t)Py_NewRef(obj) }; +} +} +# define PyStackRef_NewRefDeferred(obj) _PyStackRef_NewRefDeferred(_PyObject_CAST(obj)) +#else +# define PyStackRef_NewRefDeferred(obj) PyStackRef_NewRef(((_PyStackRef){.bits = ((uintptr_t)(obj))})) +#endif + +#if defined(Py_GIL_DISABLED) +static inline _PyStackRef +_PyStackRef_XNewRefDeferred(PyObject *obj) +{ +// Make sure we don't take an already tagged value. +assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0); +if (obj == NULL) { +return Py_STACKREF_NULL; +} +return _PyStackRef_NewRefDeferred(obj); +} +# define PyStackRef_XNewRefDeferred(obj) _PyStackRef_XNewRefDeferred(_PyObject_CAST(obj)) +#else +# define PyStackRef_XNewRefDeferred(obj) PyStackRef_XNewRef(((_PyStackRef){.bits = ((uintptr_t)(obj))})) +#endif + +// Converts a PyStackRef back to a PyObject *. +#if defined(Py_GIL_DISABLED) +static inline PyObject * +PyStackRef_StealObject(_PyStackRef tagged) +{ +if ((tagged.bits & Py_TAG_DEFERRED) == Py_TAG_DEFERRED) { +assert(_PyObject_HasDeferredRefcount(PyStackRef_Get(tagged))); +return Py_NewRef(PyStackRef_Get(tagged)); +} +return PyStackRef_Get(tagged); +} +#else +# define PyStackRef_StealObject(tagged) PyStackRef_Get(tagged) +#endif + +static inline void +_Py_untag_stack_borrowed(PyObject **dst, const _PyStackRef *src, size_t length) +{ +for (size_t i = 0; i < length; i++) { +dst[i] = PyStackRef_Get(src[i]); +} +} + +static inline void +_Py_untag_stack_steal(PyObject **dst, const _PyStackRef *src, size_t length) +{ +for (size_t i = 0; i < length; i++) { +dst[i] = PyStackRef_StealObject(src[i]); +} +} + + +#define PyStackRef_XSETREF(dst, src) \ +do { \ +_PyStackRef *_tmp_dst_ptr = &(dst) \ +_PyStackRef _tmp_old_dst = (*_tmp_dst_ptr); \ +*_tmp_dst_ptr = (src); \ +PyStackRef_XDECREF(_tmp_old_dst); \ +} while (0) + +#define PyStackRef_SETREF(dst, src) \ +do { \ +_PyStackRef *_tmp_dst_ptr = &(dst); \ +_PyStackRef _tmp_old_dst = (*_tmp_dst_ptr); \ +*_tmp_dst_ptr = (src); \ +PyStackRef_DECREF(_tmp_old_dst); \ +} while (0) + +#define PyStackRef_CLEAR(op) \ +do { \ +_PyStackRef *_tmp_op_ptr = &(op); \ +_PyStackRef _tmp_old_op = (*_tmp_op_ptr); \ +if (_tmp_old_op.bits != Py_STACKREF_NULL.bits) { \ +*_tmp_op_ptr = Py_STACKREF_NULL; \ +PyStackRef_DECREF(_tmp_old_op); \ +} \ +} while (0) + +#if defined(Py_GIL_
[Python-checkins] gh-117657: Don't specialize RESUME_CHECK when specialization is disabled (GH-118349)
https://github.com/python/cpython/commit/7fabcc727dee52a3e0dfe4f903ad414e93cf2dc9 commit: 7fabcc727dee52a3e0dfe4f903ad414e93cf2dc9 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-04-30T21:51:59Z summary: gh-117657: Don't specialize RESUME_CHECK when specialization is disabled (GH-118349) files: M Python/bytecodes.c M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5bb7e1211385a5..18837aef74d78e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -163,7 +163,9 @@ dummy_func( if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) { CHECK_EVAL_BREAKER(); } +#if ENABLE_SPECIALIZATION FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK); +#endif /* ENABLE_SPECIALIZATION */ } } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a5bb29385844d8..1444f5cdebba4b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4955,7 +4955,9 @@ if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) { CHECK_EVAL_BREAKER(); } +#if ENABLE_SPECIALIZATION FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK); +#endif /* ENABLE_SPECIALIZATION */ } DISPATCH(); } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-117139: Fix missing semicolon (GH-118573)
https://github.com/python/cpython/commit/978fba58aef347de4a1376e525df2dacc7b2fff3 commit: 978fba58aef347de4a1376e525df2dacc7b2fff3 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-05-04T15:45:49Z summary: gh-117139: Fix missing semicolon (GH-118573) files: M Include/internal/pycore_stackref.h diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index fd929cd4873a8b..93898174789f7b 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -114,7 +114,7 @@ _Py_untag_stack_steal(PyObject **dst, const _PyStackRef *src, size_t length) #define PyStackRef_XSETREF(dst, src) \ do { \ -_PyStackRef *_tmp_dst_ptr = &(dst) \ +_PyStackRef *_tmp_dst_ptr = &(dst); \ _PyStackRef _tmp_old_dst = (*_tmp_dst_ptr); \ *_tmp_dst_ptr = (src); \ PyStackRef_XDECREF(_tmp_old_dst); \ ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-89811: Check for valid tp_version_tag in specializer (GH-113558)
https://github.com/python/cpython/commit/f653caa5a88d3b5027a8f286ff3a3ccd9e6fe4ed commit: f653caa5a88d3b5027a8f286ff3a3ccd9e6fe4ed branch: main author: Peter Lazorchak committer: Fidget-Spinner date: 2024-01-11T13:33:05+08:00 summary: gh-89811: Check for valid tp_version_tag in specializer (GH-113558) files: A Misc/NEWS.d/next/Core and Builtins/2024-01-03-12-19-37.gh-issue-89811.cZOj6d.rst M Lib/test/test_type_cache.py M Modules/_testcapimodule.c M Python/specialize.c diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 72587ecc11b6f3..95b55009c7187d 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -1,5 +1,6 @@ """ Tests for the internal type cache in CPython. """ import unittest +import dis from test import support from test.support import import_helper try: @@ -8,8 +9,11 @@ _clear_type_cache = None # Skip this test if the _testcapi module isn't available. -type_get_version = import_helper.import_module('_testcapi').type_get_version -type_assign_version = import_helper.import_module('_testcapi').type_assign_version +_testcapi = import_helper.import_module("_testcapi") +type_get_version = _testcapi.type_get_version +type_assign_specific_version_unsafe = _testcapi.type_assign_specific_version_unsafe +type_assign_version = _testcapi.type_assign_version +type_modified = _testcapi.type_modified @support.cpython_only @@ -56,6 +60,183 @@ class C: self.assertNotEqual(type_get_version(C), 0) self.assertNotEqual(type_get_version(C), c_ver) +def test_type_assign_specific_version(self): +"""meta-test for type_assign_specific_version_unsafe""" +class C: +pass + +type_assign_version(C) +orig_version = type_get_version(C) +self.assertNotEqual(orig_version, 0) + +type_modified(C) +type_assign_specific_version_unsafe(C, orig_version + 5) +type_assign_version(C) # this should do nothing + +new_version = type_get_version(C) +self.assertEqual(new_version, orig_version + 5) + +_clear_type_cache() + + +@support.cpython_only +class TypeCacheWithSpecializationTests(unittest.TestCase): +def tearDown(self): +_clear_type_cache() + +def _assign_and_check_valid_version(self, user_type): +type_modified(user_type) +type_assign_version(user_type) +self.assertNotEqual(type_get_version(user_type), 0) + +def _assign_and_check_version_0(self, user_type): +type_modified(user_type) +type_assign_specific_version_unsafe(user_type, 0) +self.assertEqual(type_get_version(user_type), 0) + +def _all_opnames(self, func): +return set(instr.opname for instr in dis.Bytecode(func, adaptive=True)) + +def _check_specialization(self, func, arg, opname, *, should_specialize): +self.assertIn(opname, self._all_opnames(func)) + +for _ in range(100): +func(arg) + +if should_specialize: +self.assertNotIn(opname, self._all_opnames(func)) +else: +self.assertIn(opname, self._all_opnames(func)) + +def test_class_load_attr_specialization_user_type(self): +class A: +def foo(self): +pass + +self._assign_and_check_valid_version(A) + +def load_foo_1(type_): +type_.foo + +self._check_specialization(load_foo_1, A, "LOAD_ATTR", should_specialize=True) +del load_foo_1 + +self._assign_and_check_version_0(A) + +def load_foo_2(type_): +return type_.foo + +self._check_specialization(load_foo_2, A, "LOAD_ATTR", should_specialize=False) + +def test_class_load_attr_specialization_static_type(self): +self._assign_and_check_valid_version(str) +self._assign_and_check_valid_version(bytes) + +def get_capitalize_1(type_): +return type_.capitalize + +self._check_specialization(get_capitalize_1, str, "LOAD_ATTR", should_specialize=True) +self.assertEqual(get_capitalize_1(str)('hello'), 'Hello') +self.assertEqual(get_capitalize_1(bytes)(b'hello'), b'Hello') +del get_capitalize_1 + +# Permanently overflow the static type version counter, and force str and bytes +# to have tp_version_tag == 0 +for _ in range(2**16): +type_modified(str) +type_assign_version(str) +type_modified(bytes) +type_assign_version(bytes) + +self.assertEqual(type_get_version(str), 0) +self.assertEqual(type_get_version(bytes), 0) + +def get_capitalize_2(type_): +return type_.capitalize + +self._check_specialization(get_capitalize_2, str, "LOAD_ATTR",
[Python-checkins] gh-113937 Fix failures in type cache tests due to re-running (GH-113953)
https://github.com/python/cpython/commit/e58334e4c9ccbebce6858da1985c1f75a6063d05 commit: e58334e4c9ccbebce6858da1985c1f75a6063d05 branch: main author: Peter Lazorchak committer: Fidget-Spinner date: 2024-01-12T13:18:19+08:00 summary: gh-113937 Fix failures in type cache tests due to re-running (GH-113953) files: M Lib/test/test_type_cache.py diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 95b55009c7187d..295df78a17374a 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -67,7 +67,8 @@ class C: type_assign_version(C) orig_version = type_get_version(C) -self.assertNotEqual(orig_version, 0) +if orig_version == 0: +self.skipTest("Could not assign a valid type version") type_modified(C) type_assign_specific_version_unsafe(C, orig_version + 5) @@ -84,10 +85,11 @@ class TypeCacheWithSpecializationTests(unittest.TestCase): def tearDown(self): _clear_type_cache() -def _assign_and_check_valid_version(self, user_type): -type_modified(user_type) -type_assign_version(user_type) -self.assertNotEqual(type_get_version(user_type), 0) +def _assign_valid_version_or_skip(self, type_): +type_modified(type_) +type_assign_version(type_) +if type_get_version(type_) == 0: +self.skipTest("Could not assign valid type version") def _assign_and_check_version_0(self, user_type): type_modified(user_type) @@ -98,8 +100,6 @@ def _all_opnames(self, func): return set(instr.opname for instr in dis.Bytecode(func, adaptive=True)) def _check_specialization(self, func, arg, opname, *, should_specialize): -self.assertIn(opname, self._all_opnames(func)) - for _ in range(100): func(arg) @@ -113,7 +113,7 @@ class A: def foo(self): pass -self._assign_and_check_valid_version(A) +self._assign_valid_version_or_skip(A) def load_foo_1(type_): type_.foo @@ -129,8 +129,8 @@ def load_foo_2(type_): self._check_specialization(load_foo_2, A, "LOAD_ATTR", should_specialize=False) def test_class_load_attr_specialization_static_type(self): -self._assign_and_check_valid_version(str) -self._assign_and_check_valid_version(bytes) +self._assign_valid_version_or_skip(str) +self._assign_valid_version_or_skip(bytes) def get_capitalize_1(type_): return type_.capitalize @@ -164,7 +164,7 @@ class G: def x(self): return 9 -self._assign_and_check_valid_version(G) +self._assign_valid_version_or_skip(G) def load_x_1(instance): instance.x @@ -183,7 +183,7 @@ def test_store_attr_specialization_user_type(self): class B: __slots__ = ("bar",) -self._assign_and_check_valid_version(B) +self._assign_valid_version_or_skip(B) def store_bar_1(type_): type_.bar = 10 @@ -203,7 +203,7 @@ class F: def __init__(self): pass -self._assign_and_check_valid_version(F) +self._assign_valid_version_or_skip(F) def call_class_1(type_): type_() @@ -222,7 +222,7 @@ def test_to_bool_specialization_user_type(self): class H: pass -self._assign_and_check_valid_version(H) +self._assign_valid_version_or_skip(H) def to_bool_1(instance): not instance ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-113710: Add types to the interpreter DSL (#113711)
https://github.com/python/cpython/commit/ac92527c08d917dffdb9c0a218d06f21114614a2 commit: ac92527c08d917dffdb9c0a218d06f21114614a2 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-01-13T01:30:27+08:00 summary: gh-113710: Add types to the interpreter DSL (#113711) Co-authored-by: Jules <57632293+julia...@users.noreply.github.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2024-01-09-23-01-00.gh-issue-113710.pe3flY.rst M Include/internal/pycore_opcode_metadata.h M Include/internal/pycore_uop_ids.h M Include/internal/pycore_uop_metadata.h M Lib/test/test_generated_cases.py M Python/bytecodes.c M Python/executor_cases.c.h M Tools/cases_generator/analyzer.py M Tools/cases_generator/generators_common.py M Tools/cases_generator/interpreter_definition.md M Tools/cases_generator/lexer.py M Tools/cases_generator/opcode_metadata_generator.py M Tools/cases_generator/parsing.py M Tools/cases_generator/stack.py diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index a9d698da25a1db..fbb448f663369a 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -909,6 +909,8 @@ enum InstructionFormat { #define HAS_DEOPT_FLAG (128) #define HAS_ERROR_FLAG (256) #define HAS_ESCAPES_FLAG (512) +#define HAS_PURE_FLAG (1024) +#define HAS_PASSTHROUGH_FLAG (2048) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) @@ -919,6 +921,8 @@ enum InstructionFormat { #define OPCODE_HAS_DEOPT(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_DEOPT_FLAG)) #define OPCODE_HAS_ERROR(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ERROR_FLAG)) #define OPCODE_HAS_ESCAPES(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ESCAPES_FLAG)) +#define OPCODE_HAS_PURE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PURE_FLAG)) +#define OPCODE_HAS_PASSTHROUGH(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PASSTHROUGH_FLAG)) #define OPARG_FULL 0 #define OPARG_CACHE_1 1 @@ -996,7 +1000,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, -[COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, +[COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, [COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [DELETE_ATTR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DELETE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1007,8 +1011,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [DICT_MERGE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [END_ASYNC_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -[END_FOR] = { true, INSTR_FMT_IX, 0 }, -[END_SEND] = { true, INSTR_FMT_IX, 0 }, +[END_FOR] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, +[END_SEND] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1067,9 +1071,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -[LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, +[LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG }, [LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -[LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, +[LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG }, [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG }, [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, @@ -10
[Python-checkins] gh-120619: Optimize through `_Py_FRAME_GENERAL` (GH-124518)
https://github.com/python/cpython/commit/b84a763dca412e8dbbc9cf7c6273c11d6c2220a7 commit: b84a763dca412e8dbbc9cf7c6273c11d6c2220a7 branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-10-03T01:10:51+08:00 summary: gh-120619: Optimize through `_Py_FRAME_GENERAL` (GH-124518) * Optimize through _Py_FRAME_GENERAL * refactor files: M Python/optimizer_analysis.c M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index f30e873605d858..06826ff942a761 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -385,6 +385,30 @@ get_code(_PyUOpInstruction *op) return co; } +static PyCodeObject * +get_code_with_logging(_PyUOpInstruction *op) +{ +PyCodeObject *co = NULL; +uint64_t push_operand = op->operand; +if (push_operand & 1) { +co = (PyCodeObject *)(push_operand & ~1); +DPRINTF(3, "code=%p ", co); +assert(PyCode_Check(co)); +} +else { +PyFunctionObject *func = (PyFunctionObject *)push_operand; +DPRINTF(3, "func=%p ", func); +if (func == NULL) { +DPRINTF(3, "\n"); +DPRINTF(1, "Missing function\n"); +return NULL; +} +co = (PyCodeObject *)func->func_code; +DPRINTF(3, "code=%p ", co); +} +return co; +} + /* 1 for success, 0 for not ready, cannot error at the moment. */ static int optimize_uops( diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 9a1b9da52f4bb5..bf8f0753f800c0 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -575,25 +575,13 @@ dummy_func(void) { PyCodeObject *co = NULL; assert((this_instr + 2)->opcode == _PUSH_FRAME); -uint64_t push_operand = (this_instr + 2)->operand; -if (push_operand & 1) { -co = (PyCodeObject *)(push_operand & ~1); -DPRINTF(3, "code=%p ", co); -assert(PyCode_Check(co)); -} -else { -PyFunctionObject *func = (PyFunctionObject *)push_operand; -DPRINTF(3, "func=%p ", func); -if (func == NULL) { -DPRINTF(3, "\n"); -DPRINTF(1, "Missing function\n"); -ctx->done = true; -break; -} -co = (PyCodeObject *)func->func_code; -DPRINTF(3, "code=%p ", co); +co = get_code_with_logging((this_instr + 2)); +if (co == NULL) { +ctx->done = true; +break; } + assert(self_or_null != NULL); assert(args != NULL); if (sym_is_not_null(self_or_null)) { @@ -619,12 +607,17 @@ dummy_func(void) { } op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { -/* The _Py_UOpsAbstractFrame design assumes that we can copy arguments across directly */ -(void)callable; -(void)self_or_null; -(void)args; -new_frame = NULL; -ctx->done = true; +(void)(self_or_null); +(void)(callable); +PyCodeObject *co = NULL; +assert((this_instr + 2)->opcode == _PUSH_FRAME); +co = get_code_with_logging((this_instr + 2)); +if (co == NULL) { +ctx->done = true; +break; +} + +new_frame = frame_new(ctx, co, 0, NULL, 0); } op(_PY_FRAME_KW, (callable, self_or_null, args[oparg], kwnames -- new_frame: _Py_UOpsAbstractFrame *)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 4d172e3c762704..fc0c0eff01d4c1 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1663,15 +1663,18 @@ _Py_UopsSymbol *self_or_null; _Py_UopsSymbol *callable; _Py_UOpsAbstractFrame *new_frame; -args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; -/* The _Py_UOpsAbstractFrame design assumes that we can copy arguments across directly */ -(void)callable; -(void)self_or_null; -(void)args; -new_frame = NULL; -ctx->done = true; +(void)(self_or_null); +(void)(callable); +PyCodeObject *co = NULL; +assert((this_instr + 2)->opcode == _PUSH_FRAME); +co = get_code_with_logging((this_instr + 2)); +if (co == NULL) { +ctx->done = true; +break; +} +new_frame = frame_new(ctx, co, 0, NULL, 0); stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame; stack_pointer += -1 - oparg; assert(WITHIN_STACK_BO
[Python-checkins] gh-120619: Strength reduce function guards, support 2-operand uop forms (GH-124846)
https://github.com/python/cpython/commit/6293d00e7201f3f28b1f4512e57dc4f03855cabd commit: 6293d00e7201f3f28b1f4512e57dc4f03855cabd branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-11-09T11:35:33+08:00 summary: gh-120619: Strength reduce function guards, support 2-operand uop forms (GH-124846) Co-authored-by: Brandt Bucher files: M Include/internal/pycore_optimizer.h M Include/internal/pycore_uop_ids.h M Include/internal/pycore_uop_metadata.h M Lib/test/test_capi/test_opt.py M Python/bytecodes.c M Python/ceval_macros.h M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/optimizer.c M Python/optimizer_analysis.c M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h M Tools/cases_generator/analyzer.py M Tools/cases_generator/optimizer_generator.py M Tools/cases_generator/tier2_generator.py M Tools/jit/_stencils.py M Tools/jit/template.c diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index f92c0a0cddf906..6d70b42f708854 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -58,7 +58,8 @@ typedef struct { uint16_t error_target; }; }; -uint64_t operand; // A cache entry +uint64_t operand0; // A cache entry +uint64_t operand1; } _PyUOpInstruction; typedef struct { diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 55416d2aae1e1a..fab4ce6a25b347 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -63,90 +63,91 @@ extern "C" { #define _CHECK_FUNCTION 333 #define _CHECK_FUNCTION_EXACT_ARGS 334 #define _CHECK_FUNCTION_VERSION 335 -#define _CHECK_FUNCTION_VERSION_KW 336 -#define _CHECK_IS_NOT_PY_CALLABLE 337 -#define _CHECK_IS_NOT_PY_CALLABLE_KW 338 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 339 -#define _CHECK_METHOD_VERSION 340 -#define _CHECK_METHOD_VERSION_KW 341 -#define _CHECK_PEP_523 342 -#define _CHECK_PERIODIC 343 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM 344 -#define _CHECK_STACK_SPACE 345 -#define _CHECK_STACK_SPACE_OPERAND 346 -#define _CHECK_VALIDITY 347 -#define _CHECK_VALIDITY_AND_SET_IP 348 -#define _COMPARE_OP 349 -#define _COMPARE_OP_FLOAT 350 -#define _COMPARE_OP_INT 351 -#define _COMPARE_OP_STR 352 -#define _CONTAINS_OP 353 +#define _CHECK_FUNCTION_VERSION_INLINE 336 +#define _CHECK_FUNCTION_VERSION_KW 337 +#define _CHECK_IS_NOT_PY_CALLABLE 338 +#define _CHECK_IS_NOT_PY_CALLABLE_KW 339 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 340 +#define _CHECK_METHOD_VERSION 341 +#define _CHECK_METHOD_VERSION_KW 342 +#define _CHECK_PEP_523 343 +#define _CHECK_PERIODIC 344 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM 345 +#define _CHECK_STACK_SPACE 346 +#define _CHECK_STACK_SPACE_OPERAND 347 +#define _CHECK_VALIDITY 348 +#define _CHECK_VALIDITY_AND_SET_IP 349 +#define _COMPARE_OP 350 +#define _COMPARE_OP_FLOAT 351 +#define _COMPARE_OP_INT 352 +#define _COMPARE_OP_STR 353 +#define _CONTAINS_OP 354 #define _CONTAINS_OP_DICT CONTAINS_OP_DICT #define _CONTAINS_OP_SET CONTAINS_OP_SET #define _CONVERT_VALUE CONVERT_VALUE #define _COPY COPY #define _COPY_FREE_VARS COPY_FREE_VARS -#define _CREATE_INIT_FRAME 354 +#define _CREATE_INIT_FRAME 355 #define _DELETE_ATTR DELETE_ATTR #define _DELETE_DEREF DELETE_DEREF #define _DELETE_FAST DELETE_FAST #define _DELETE_GLOBAL DELETE_GLOBAL #define _DELETE_NAME DELETE_NAME #define _DELETE_SUBSCR DELETE_SUBSCR -#define _DEOPT 355 +#define _DEOPT 356 #define _DICT_MERGE DICT_MERGE #define _DICT_UPDATE DICT_UPDATE -#define _DO_CALL 356 -#define _DO_CALL_FUNCTION_EX 357 -#define _DO_CALL_KW 358 -#define _DYNAMIC_EXIT 359 +#define _DO_CALL 357 +#define _DO_CALL_FUNCTION_EX 358 +#define _DO_CALL_KW 359 +#define _DYNAMIC_EXIT 360 #define _END_SEND END_SEND -#define _ERROR_POP_N 360 +#define _ERROR_POP_N 361 #define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _EXPAND_METHOD 361 -#define _EXPAND_METHOD_KW 362 -#define _FATAL_ERROR 363 +#define _EXPAND_METHOD 362 +#define _EXPAND_METHOD_KW 363 +#define _FATAL_ERROR 364 #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 364 -#define _FOR_ITER_GEN_FRAME 365 -#define _FOR_ITER_TIER_TWO 366 +#define _FOR_ITER 365 +#define _FOR_ITER_GEN_FRAME 366 +#define _FOR_ITER_TIER_TWO 367 #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE #define _GET_ITER GET_ITER #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _GUARD_BOTH_FLOAT 367 -#define _GUARD_BOTH_INT 368 -#define _GUARD_BOTH_UNICODE 369 -#define _GUARD_BUILTINS_VERSION_PUSH_KEYS 370 -#define _GUARD_DORV_NO_DICT 371 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 372 -#define _GUARD_GLOBALS_VERSION 373 -#define _GUARD_GLOBALS_VERSION_PUSH_KEYS 374 -#define _GUARD_IS_FALSE_POP 375 -#define _GUARD_IS_NONE_POP 376 -#define _GUARD_IS_NOT_NONE_POP 377 -#define _GUARD_IS_TRUE_POP 378 -#define _GUARD_KEYS_V
[Python-checkins] gh-117376: Fix off-by-ones in conversion functions (GH-124301)
https://github.com/python/cpython/commit/198756b0f653e9f487076df2c6f943e374def6cb commit: 198756b0f653e9f487076df2c6f943e374def6cb branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-09-26T02:41:07+08:00 summary: gh-117376: Fix off-by-ones in conversion functions (GH-124301) Fix off-by-ones in conversion function files: M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index bf8f6af83fc56e..0fd396f1319e78 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3928,7 +3928,7 @@ dummy_func( PyCFunctionFastWithKeywords cfunc = (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; -STACKREFS_TO_PYOBJECTS(args, nargs, args_o); +STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { DECREF_INPUTS(); ERROR_IF(true, error); @@ -4009,7 +4009,7 @@ dummy_func( (PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; -STACKREFS_TO_PYOBJECTS(args, nargs, args_o); +STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { DECREF_INPUTS(); ERROR_IF(true, error); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 7285acec0bacaf..7a9c6ab89c38cc 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4596,7 +4596,7 @@ int nargs = total_args - 1; PyCFunctionFastWithKeywords cfunc = (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; -STACKREFS_TO_PYOBJECTS(args, nargs, args_o); +STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { PyStackRef_CLOSE(callable); PyStackRef_CLOSE(self_or_null[0]); @@ -4713,7 +4713,7 @@ PyCFunctionFast cfunc = (PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; -STACKREFS_TO_PYOBJECTS(args, nargs, args_o); +STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { PyStackRef_CLOSE(callable); PyStackRef_CLOSE(self_or_null[0]); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 58792a2101ab28..1201fe82efb919 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2252,7 +2252,7 @@ PyCFunctionFast cfunc = (PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; -STACKREFS_TO_PYOBJECTS(args, nargs, args_o); +STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { PyStackRef_CLOSE(callable); PyStackRef_CLOSE(self_or_null[0]); @@ -2333,7 +2333,7 @@ int nargs = total_args - 1; PyCFunctionFastWithKeywords cfunc = (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; -STACKREFS_TO_PYOBJECTS(args, nargs, args_o); +STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { PyStackRef_CLOSE(callable); PyStackRef_CLOSE(self_or_null[0]); ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-103951: enable optimization for fast attribute access on module subclasses (GH-126264)
https://github.com/python/cpython/commit/d9e251223e8314ca726fc0be8b834362184b0aad commit: d9e251223e8314ca726fc0be8b834362184b0aad branch: main author: Sergey B Kirpichev committer: Fidget-Spinner date: 2024-11-15T16:03:38+08:00 summary: gh-103951: enable optimization for fast attribute access on module subclasses (GH-126264) Co-authored-by: Nicolas Tessore files: A Misc/NEWS.d/next/Core_and_Builtins/2024-11-01-09-58-06.gh-issue-103951.6qduwj.rst M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/specialize.c diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-11-01-09-58-06.gh-issue-103951.6qduwj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-11-01-09-58-06.gh-issue-103951.6qduwj.rst new file mode 100644 index 00..39b54e0b72556e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-11-01-09-58-06.gh-issue-103951.6qduwj.rst @@ -0,0 +1,2 @@ +Relax optimization requirements to allow fast attribute access to module +subclasses. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 04983fd861ec59..c85b49842daf44 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2132,7 +2132,7 @@ dummy_func( op(_CHECK_ATTR_MODULE, (dict_version/2, owner -- owner)) { PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -DEOPT_IF(!PyModule_CheckExact(owner_o)); +DEOPT_IF(Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict; assert(dict != NULL); DEOPT_IF(dict->ma_keys->dk_version != dict_version); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 494ace1bd85822..2c2a09adf281a7 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2602,7 +2602,7 @@ owner = stack_pointer[-1]; uint32_t dict_version = (uint32_t)CURRENT_OPERAND0(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -if (!PyModule_CheckExact(owner_o)) { +if (Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 77bf6ad3781f17..15308d6f1f7146 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5561,7 +5561,7 @@ owner = stack_pointer[-1]; uint32_t dict_version = read_u32(&this_instr[2].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -DEOPT_IF(!PyModule_CheckExact(owner_o), LOAD_ATTR); +DEOPT_IF(Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro, LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict; assert(dict != NULL); DEOPT_IF(dict->ma_keys->dk_version != dict_version, LOAD_ATTR); diff --git a/Python/specialize.c b/Python/specialize.c index 0699e7be5e6b9c..4c8cf8534b3dc7 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1219,7 +1219,7 @@ _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *nam SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); fail = true; } -else if (PyModule_CheckExact(owner)) { +else if (Py_TYPE(owner)->tp_getattro == PyModule_Type.tp_getattro) { fail = specialize_module_load_attr(owner, instr, name); } else if (PyType_Check(owner)) { ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-128262: Allow specialization of calls to classes with __slots__ (GH-128263)
https://github.com/python/cpython/commit/7ef49074123511003c8b7f7f3ba2a4e05285e8dc commit: 7ef49074123511003c8b7f7f3ba2a4e05285e8dc branch: main author: Ken Jin committer: Fidget-Spinner date: 2024-12-31T12:24:17+08:00 summary: gh-128262: Allow specialization of calls to classes with __slots__ (GH-128263) files: M Include/internal/pycore_uop_metadata.h M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/specialize.c diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index e71194b116e020..73fc29eb78a7a4 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -234,7 +234,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_CALL_STR_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -[_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, +[_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_EXIT_INIT_CHECK] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CALL_BUILTIN_CLASS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 63cf1978e8abe5..602cf7f47b812b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3765,13 +3765,15 @@ dummy_func( DEOPT_IF(!PyType_Check(callable_o)); PyTypeObject *tp = (PyTypeObject *)callable_o; DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version); -assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); +assert(tp->tp_new == PyBaseObject_Type.tp_new); +assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); +assert(tp->tp_alloc == PyType_GenericAlloc); PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); PyCodeObject *code = (PyCodeObject *)init_func->func_code; DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)); STAT_INC(CALL, hit); -PyObject *self_o = _PyType_NewManagedObject(tp); +PyObject *self_o = PyType_GenericAlloc(tp, 0); if (self_o == NULL) { ERROR_NO_POP(); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 22335021faaa6d..f7374d52705960 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4572,7 +4572,9 @@ UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } -assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); +assert(tp->tp_new == PyBaseObject_Type.tp_new); +assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); +assert(tp->tp_alloc == PyType_GenericAlloc); PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); PyCodeObject *code = (PyCodeObject *)init_func->func_code; @@ -4581,7 +4583,9 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); -PyObject *self_o = _PyType_NewManagedObject(tp); +_PyFrame_SetStackPointer(frame, stack_pointer); +PyObject *self_o = PyType_GenericAlloc(tp, 0); +stack_pointer = _PyFrame_GetStackPointer(frame); if (self_o == NULL) { JUMP_TO_ERROR(); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index bed16b60b76a2f..98743c27c38524 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1048,13 +1048,17 @@ DEOPT_IF(!PyType_Check(callable_o), CALL); PyTypeObject *tp = (PyTypeObject *)callable_o; DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version, CALL); -assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); +assert(tp->tp_new == PyBaseObject_Type.tp_new); +assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); +assert(tp->tp_alloc == PyType_GenericAlloc); PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); PyCodeObject *code = (PyCodeObject *)init_fu
[Python-checkins] Docs: more explanation of the implications of new tail-call interpreter (GH-129863)
https://github.com/python/cpython/commit/f2ae79d29e5e0bd24ad1300cb44e3a99104755c7 commit: f2ae79d29e5e0bd24ad1300cb44e3a99104755c7 branch: main author: Ned Batchelder committer: Fidget-Spinner date: 2025-02-08T19:28:35Z summary: Docs: more explanation of the implications of new tail-call interpreter (GH-129863) Co-authored-by: Ken Jin files: M Doc/whatsnew/3.14.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 9c4922308b7f2d..ba7e8b42ef1f24 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -235,9 +235,13 @@ For further information on how to build Python, see This is not to be confused with `tail call optimization`__ of Python functions, which is currently not implemented in CPython. + This new interpreter type is an internal implementation detail of the CPython + interpreter. It doesn't change the visible behavior of Python programs at + all. It can improve their performance, but doesn't change anything else. + __ https://en.wikipedia.org/wiki/Tail_call -(Contributed by Ken Jin in :gh:`128718`, with ideas on how to implement this +(Contributed by Ken Jin in :gh:`128563`, with ideas on how to implement this in CPython by Mark Shannon, Garrett Gu, Haoran Xu, and Josh Haberman.) ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] Fix link in 3.14 whatsnew (#129828)
https://github.com/python/cpython/commit/e4a00f70b176c3182aad3904f94c69a7fb733cd9 commit: e4a00f70b176c3182aad3904f94c69a7fb733cd9 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-07T19:30:23Z summary: Fix link in 3.14 whatsnew (#129828) files: M Doc/whatsnew/3.14.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 2bdc3cabcfbc03..6eb256586e71d8 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -68,7 +68,7 @@ Summary -- release highlights * :ref:`PEP 649: deferred evaluation of annotations ` * :ref:`PEP 741: Python Configuration C API ` * :ref:`PEP 761: Discontinuation of PGP signatures ` -* :ref:`A new tail-calling interpreter ` +* :ref:`A new type of interpreter ` New features ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] Remove tail-calling wording as it is confusing (GH-129823)
https://github.com/python/cpython/commit/7b2e01bb555359913939d7ff168363f1760d3f8e commit: 7b2e01bb555359913939d7ff168363f1760d3f8e branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-07T18:49:28Z summary: Remove tail-calling wording as it is confusing (GH-129823) files: M Doc/whatsnew/3.14.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 52d6e963a4a835..2bdc3cabcfbc03 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -211,8 +211,8 @@ configuration mechanisms). .. _whatsnew314-tail-call: -A new tail-calling interpreter --- +A new type of interpreter +- A new type of interpreter based on tail calls has been added to CPython. For certain newer compilers, this interpreter provides ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] Fix Garrett Gu name misspelling in 3.14 whatsnew (GH-129822)
https://github.com/python/cpython/commit/662e88db642899bcbc28ef142361d5f315a46901 commit: 662e88db642899bcbc28ef142361d5f315a46901 branch: main author: Garrett Gu committer: Fidget-Spinner date: 2025-02-07T17:56:46Z summary: Fix Garrett Gu name misspelling in 3.14 whatsnew (GH-129822) Update 3.14.rst to fix typo files: M Doc/whatsnew/3.14.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 1e469e8738bfcb..52d6e963a4a835 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -238,7 +238,7 @@ For further information on how to build Python, see __ https://en.wikipedia.org/wiki/Tail_call (Contributed by Ken Jin in :gh:`128718`, with ideas on how to implement this -in CPython by Mark Shannon, Garret Gu, Haoran Xu, and Josh Haberman.) +in CPython by Mark Shannon, Garrett Gu, Haoran Xu, and Josh Haberman.) Other language changes ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-129737: Fix help message for tail calling interpreter configuration (GH-129754)
https://github.com/python/cpython/commit/43e024021392c8c70e5a56cdf7428ced45d73688 commit: 43e024021392c8c70e5a56cdf7428ced45d73688 branch: main author: Pieter Eendebak committer: Fidget-Spinner date: 2025-02-07T08:47:13+08:00 summary: gh-129737: Fix help message for tail calling interpreter configuration (GH-129754) files: M configure M configure.ac diff --git a/configure b/configure index 22456959add174..65b8e711cdccae 100755 --- a/configure +++ b/configure @@ -1930,7 +1930,7 @@ Optional Packages: use libedit for backend or disable readline module --with-computed-gotos enable computed gotos in evaluation loop (enabled by default on supported compilers) - --tail-call-interp enable tail-calling interpreter in evaluation loop + --with-tail-call-interp enable tail-calling interpreter in evaluation loop and rest of CPython --with-ensurepip[=install|upgrade|no] "install" or "upgrade" using bundled pip (default is diff --git a/configure.ac b/configure.ac index cf16e77f0a1503..0c6063d87d654a 100644 --- a/configure.ac +++ b/configure.ac @@ -7022,7 +7022,7 @@ AC_MSG_CHECKING([for --with-tail-call-interp]) AC_ARG_WITH( [tail-call-interp], [AS_HELP_STRING( -[--tail-call-interp], +[--with-tail-call-interp], [enable tail-calling interpreter in evaluation loop and rest of CPython] )], [ ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-128563: Document the tail-calling interpreter (GH-129728)
https://github.com/python/cpython/commit/3d3a4beefed46df7aa3a477f2e511459ce06c4b0 commit: 3d3a4beefed46df7aa3a477f2e511459ce06c4b0 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-07T20:18:15+08:00 summary: gh-128563: Document the tail-calling interpreter (GH-129728) Co-authored-by: Hugo van Kemenade <1324225+hug...@users.noreply.github.com> files: M Doc/using/configure.rst M Doc/whatsnew/3.14.rst diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 629859e36cb654..101c43576b0314 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -618,6 +618,16 @@ also be used to improve performance. Enable computed gotos in evaluation loop (enabled by default on supported compilers). +.. option:: --with-tail-call-interp + + Enable interpreters using tail calls in CPython. If enabled, enabling PGO + (:option:`--enable-optimizations`) is highly recommended. This option specifically + requires a C compiler with proper tail call support, and the + `preserve_none <https://clang.llvm.org/docs/AttributeReference.html#preserve-none>`_ + calling convention. For example, Clang 19 and newer supports this feature. + + .. versionadded:: next + .. option:: --without-mimalloc Disable the fast :ref:`mimalloc ` allocator diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index a95fc7a4b6a9fa..c788db31fc27ed 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -68,6 +68,7 @@ Summary -- release highlights * :ref:`PEP 649: deferred evaluation of annotations ` * :ref:`PEP 741: Python Configuration C API ` * :ref:`PEP 761: Discontinuation of PGP signatures ` +* :ref:`A new tail-calling interpreter ` New features @@ -208,6 +209,30 @@ configuration mechanisms). .. seealso:: :pep:`741`. +.. _whatsnew314-tail-call: + +A new tail-calling interpreter +-- + +A new type of interpreter based on tail calls has been added to CPython. +For certain newer compilers, this interpreter provides +significantly better performance. Preliminary numbers on our machines suggest +anywhere from -3% to 30% faster Python code, and a geometric mean of 9-15% +faster on ``pyperformance`` depending on platform and architecture. + +This interpreter currently only works with Clang 19 and newer +on x86-64 and AArch64 architectures. However, we expect +that a future release of GCC will support this as well. + +This feature is opt-in for now. We highly recommend enabling profile-guided +optimization with the new interpreter as it is the only configuration we have +tested and can validate its improved performance. +For further information on how to build Python, see +:option:`--with-tail-call-interp`. + +(Contributed by Ken Jin in :gh:`128718`, with ideas on how to implement this +in CPython by Mark Shannon, Garret Gu, Haoran Xu, and Josh Haberman.) + Other language changes == ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-128563: Move assignment of opcode into ifdef (GH-129803)
https://github.com/python/cpython/commit/175844713af383c9e4dd60166d1d7407c80a1949 commit: 175844713af383c9e4dd60166d1d7407c80a1949 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-07T21:11:57+08:00 summary: gh-128563: Move assignment of opcode into ifdef (GH-129803) files: M Lib/test/test_generated_cases.py M Python/generated_cases.c.h M Tools/cases_generator/tier1_generator.py diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 35ad9ebbe5a1a9..0e0f28be6b2af0 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -305,10 +305,9 @@ def test_inst_no_args(self): output = """ TARGET(OP) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP; +int opcode = OP; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); @@ -328,10 +327,9 @@ def test_inst_one_pop(self): output = """ TARGET(OP) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP; +int opcode = OP; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); @@ -354,10 +352,9 @@ def test_inst_one_push(self): output = """ TARGET(OP) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP; +int opcode = OP; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); @@ -381,10 +378,9 @@ def test_inst_one_push_one_pop(self): output = """ TARGET(OP) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP; +int opcode = OP; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); @@ -409,10 +405,9 @@ def test_binary_op(self): output = """ TARGET(OP) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP; +int opcode = OP; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); @@ -440,10 +435,9 @@ def test_overlap(self): output = """ TARGET(OP) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP; +int opcode = OP; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); @@ -473,10 +467,9 @@ def test_predictions(self): output = """ TARGET(OP1) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP1; +int opcode = OP1; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP1); @@ -489,10 +482,9 @@ def test_predictions(self): TARGET(OP3) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP3; +int opcode = OP3; (void)(opcode); +#endif _Py_CODEUNIT* const this_instr = next_instr; (void)this_instr; frame->instr_ptr = next_instr; @@ -528,10 +520,9 @@ def test_sync_sp(self): output = """ TARGET(A) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = A; +int opcode = A; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(A); @@ -550,10 +541,9 @@ def test_sync_sp(self): TARGET(B) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = B; +int opcode = B; (void)(opcode); +#endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(B); @@ -592,10 +582,9 @@ def test_error_if_plain(self): output = """ TARGET(OP) { #if defined(Py_TAIL_CALL_INTERP) -int opcode; -#endif -opcode = OP; +int opcode = OP;
[Python-checkins] Clarify baseline for new interpreter (GH-129972)
https://github.com/python/cpython/commit/516c70d4dd39e02bb365729a4b8aa93f9e6a3e82 commit: 516c70d4dd39e02bb365729a4b8aa93f9e6a3e82 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-10T19:07:24Z summary: Clarify baseline for new interpreter (GH-129972) files: M Doc/whatsnew/3.14.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index f8df4c52a36147..28e3e2dbbe28e6 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -218,7 +218,8 @@ A new type of interpreter based on tail calls has been added to CPython. For certain newer compilers, this interpreter provides significantly better performance. Preliminary numbers on our machines suggest anywhere from -3% to 30% faster Python code, and a geometric mean of 9-15% -faster on ``pyperformance`` depending on platform and architecture. +faster on ``pyperformance`` depending on platform and architecture. The +baseline is Python 3.14 built with Clang 19 without this new interpreter. This interpreter currently only works with Clang 19 and newer on x86-64 and AArch64 architectures. However, we expect ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-130004: Disable PGO for ceval.c on MSVC for default build (GH-130009)
https://github.com/python/cpython/commit/5cdd6e5e758a3fc0a5daac80753bf611b3e23c2d commit: 5cdd6e5e758a3fc0a5daac80753bf611b3e23c2d branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-12T01:13:05+08:00 summary: gh-130004: Disable PGO for ceval.c on MSVC for default build (GH-130009) Disable PGO for ceval.c on MSVC on default build files: M Python/ceval.c diff --git a/Python/ceval.c b/Python/ceval.c index c6a7a0f841f027..5f8f0ae69ef31b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -764,15 +764,10 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch) #define PY_EVAL_C_STACK_UNITS 2 -/* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC - when the JIT is enabled or GIL is disabled. Disable that optimization around - this function only. If this is fixed upstream, we should gate this on the - version of MSVC. +/* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC. */ #if (defined(_MSC_VER) && \ - defined(_Py_USING_PGO) && \ - (defined(_Py_JIT) || \ - defined(Py_GIL_DISABLED))) + defined(_Py_USING_PGO)) #define DO_NOT_OPTIMIZE_INTERP_LOOP #endif ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-130004: Revert commit 9e52e55 (GH-130005)
https://github.com/python/cpython/commit/247b50dec8af47ed8a80069117e07b7139f9d54f commit: 247b50dec8af47ed8a80069117e07b7139f9d54f branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-11T23:23:58+08:00 summary: gh-130004: Revert commit 9e52e55 (GH-130005) Revert commit 9e52e55 files: M PCbuild/pyproject.props M Python/ceval.c diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index dbdb6b743bea37..17abfa85201a90 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -53,6 +53,7 @@ $(PySourcePath)Include;$(PySourcePath)Include\internal;$(PySourcePath)Include\internal\mimalloc;$(GeneratedPyConfigDir);$(PySourcePath)PC;%(AdditionalIncludeDirectories) WIN32;$(_Py3NamePreprocessorDefinition);$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PyStatsPreprocessorDefinition)$(_PydPreprocessorDefinition)%(PreprocessorDefinitions) + _Py_USING_PGO=1;%(PreprocessorDefinitions) MaxSpeed true diff --git a/Python/ceval.c b/Python/ceval.c index 1e4f1f3af20aca..c6a7a0f841f027 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -764,6 +764,23 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch) #define PY_EVAL_C_STACK_UNITS 2 +/* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC + when the JIT is enabled or GIL is disabled. Disable that optimization around + this function only. If this is fixed upstream, we should gate this on the + version of MSVC. + */ +#if (defined(_MSC_VER) && \ + defined(_Py_USING_PGO) && \ + (defined(_Py_JIT) || \ + defined(Py_GIL_DISABLED))) +#define DO_NOT_OPTIMIZE_INTERP_LOOP +#endif + +#ifdef DO_NOT_OPTIMIZE_INTERP_LOOP +# pragma optimize("t", off) +/* This setting is reversed below following _PyEval_EvalFrameDefault */ +#endif + #ifdef Py_TAIL_CALL_INTERP #include "opcode_targets.h" #include "generated_cases.c.h" @@ -986,6 +1003,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int return NULL; } +#ifdef DO_NOT_OPTIMIZE_INTERP_LOOP +# pragma optimize("", on) +#endif + #if defined(__GNUC__) # pragma GCC diagnostic pop #elif defined(_MSC_VER) /* MS_WINDOWS */ ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-128563: Move lltrace into the frame struct (GH-129113)
https://github.com/python/cpython/commit/5809b2590956d51ce805f877e4708d21f59fb222 commit: 5809b2590956d51ce805f877e4708d21f59fb222 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-01-21T22:17:15+08:00 summary: gh-128563: Move lltrace into the frame struct (GH-129113) files: M Include/internal/pycore_frame.h M Python/bytecodes.c M Python/ceval.c M Python/ceval_macros.h M Python/executor_cases.c.h diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 77a922630cde08..14dc91e54298ce 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -76,7 +76,12 @@ typedef struct _PyInterpreterFrame { _PyStackRef *stackpointer; uint16_t return_offset; /* Only relevant during a function call */ char owner; -char visited; +#ifdef Py_DEBUG +uint8_t visited:1; +uint8_t lltrace:7; +#else +uint8_t visited; +#endif /* Locals and stack */ _PyStackRef localsplus[1]; } _PyInterpreterFrame; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8bda4501df5f74..8bed29ca2c8fc7 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4990,7 +4990,7 @@ dummy_func( _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; #if defined(Py_DEBUG) && !defined(_Py_JIT) OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); -if (lltrace >= 2) { +if (frame->lltrace >= 2) { printf("SIDE EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(", exit %u, temp %d, target %d -> %s]\n", @@ -5108,7 +5108,7 @@ dummy_func( _Py_CODEUNIT *target = frame->instr_ptr; #if defined(Py_DEBUG) && !defined(_Py_JIT) OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); -if (lltrace >= 2) { +if (frame->lltrace >= 2) { printf("DYNAMIC EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(", exit %u, temp %d, target %d -> %s]\n", diff --git a/Python/ceval.c b/Python/ceval.c index 813d980acf5aab..58a54467f06bb0 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -799,9 +799,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #endif uint8_t opcode;/* Current opcode */ int oparg; /* Current opcode argument, if any */ -#ifdef LLTRACE -int lltrace = 0; -#endif _PyInterpreterFrame entry_frame; @@ -821,6 +818,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int entry_frame.owner = FRAME_OWNED_BY_INTERPRETER; entry_frame.visited = 0; entry_frame.return_offset = 0; +#ifdef LLTRACE +entry_frame.lltrace = 0; +#endif /* Push frame */ entry_frame.previous = tstate->current_frame; frame->previous = &entry_frame; @@ -880,9 +880,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int stack_pointer = _PyFrame_GetStackPointer(frame); #ifdef LLTRACE -lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); -if (lltrace < 0) { -goto exit_unwind; +{ +int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); +frame->lltrace = lltrace; +if (lltrace < 0) { +goto exit_unwind; +} } #endif @@ -1002,7 +1005,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } /* Resume normal execution */ #ifdef LLTRACE -if (lltrace >= 5) { +if (frame->lltrace >= 5) { lltrace_resume_frame(frame); } #endif @@ -1079,7 +1082,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int for (;;) { uopcode = next_uop->opcode; #ifdef Py_DEBUG -if (lltrace >= 3) { +if (frame->lltrace >= 3) { dump_stack(frame, stack_pointer); if (next_uop->opcode == _START_EXECUTOR) { printf("%4d uop: ", 0); @@ -1121,7 +1124,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int jump_to_error_target: #ifdef Py_DEBUG -if (lltrace >= 2) { +if (frame->lltrace >= 2) { printf("Error: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(" @ %d -> %s]\n", @@ -1157,7 +1160,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int next_instr = next_uop[-1].target + _PyFrame_GetBytecode(frame); goto_to_tier1: #ifdef Py_DEBUG -if (lltrace >= 2) { +if (frame->lltrace >= 2) { printf("DEOPT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(" -> %s]\n", diff --git a/Python/ceval_macros.h b
[Python-checkins] Remove unused DPRINTF in ceval.c (GH-129282)
https://github.com/python/cpython/commit/8fecb9fa0b42f7dc18bd58b1bef56f967612e088 commit: 8fecb9fa0b42f7dc18bd58b1bef56f967612e088 branch: main author: Chris Eibl <138194463+chris-e...@users.noreply.github.com> committer: Fidget-Spinner date: 2025-01-25T18:33:26+08:00 summary: Remove unused DPRINTF in ceval.c (GH-129282) remove unused DPRINTF in ceval.c files: M Python/ceval.c diff --git a/Python/ceval.c b/Python/ceval.c index 171b383d547e35..1bdae338845758 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1063,13 +1063,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #undef ENABLE_SPECIALIZATION_FT #define ENABLE_SPECIALIZATION_FT 0 -#ifdef Py_DEBUG -#define DPRINTF(level, ...) \ -if (lltrace >= (level)) { printf(__VA_ARGS__); } -#else -#define DPRINTF(level, ...) -#endif - ; // dummy statement after a label, before a declaration uint16_t uopcode; #ifdef Py_STATS ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-128563: Move labels in ceval.c to bytecodes.c (GH-129112)
https://github.com/python/cpython/commit/87fb8b198c1633d9ce0b542eda230575892f416e commit: 87fb8b198c1633d9ce0b542eda230575892f416e branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-01-27T18:30:20+08:00 summary: gh-128563: Move labels in ceval.c to bytecodes.c (GH-129112) files: M Lib/test/test_generated_cases.py M Python/bytecodes.c M Python/ceval.c M Python/generated_cases.c.h M Tools/cases_generator/analyzer.py M Tools/cases_generator/lexer.py M Tools/cases_generator/parser.py M Tools/cases_generator/parsing.py M Tools/cases_generator/tier1_generator.py diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index b5367a0f3ca367..bb78dd9af83b62 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -281,12 +281,12 @@ def run_cases_test(self, input: str, expected: str): ) with open(self.temp_output_filename) as temp_output: -lines = temp_output.readlines() -while lines and lines[0].startswith(("// ", "#", "#", "\n")): -lines.pop(0) -while lines and lines[-1].startswith(("#", "\n")): -lines.pop(-1) -actual = "".join(lines) +lines = temp_output.read() +_, rest = lines.split(tier1_generator.INSTRUCTION_START_MARKER) +instructions, labels_with_prelude_and_postlude = rest.split(tier1_generator.INSTRUCTION_END_MARKER) +_, labels_with_postlude = labels_with_prelude_and_postlude.split(tier1_generator.LABEL_START_MARKER) +labels, _ = labels_with_postlude.split(tier1_generator.LABEL_END_MARKER) +actual = instructions + labels # if actual.strip() != expected.strip(): # print("Actual:") # print(actual) @@ -1756,6 +1756,61 @@ def test_kill_in_wrong_order(self): with self.assertRaises(SyntaxError): self.run_cases_test(input, "") +def test_complex_label(self): +input = """ +label(my_label) { +// Comment +do_thing() +if (complex) { +goto other_label; +} +goto other_label2; +} +""" + +output = """ +my_label: +{ +// Comment +do_thing() +if (complex) { +goto other_label; +} +goto other_label2; +} +""" +self.run_cases_test(input, output) + +def test_multiple_labels(self): +input = """ +label(my_label_1) { +// Comment +do_thing1(); +goto my_label_2; +} + +label(my_label_2) { +// Comment +do_thing2(); +goto my_label_3; +} +""" + +output = """ +my_label_1: +{ +// Comment +do_thing1(); +goto my_label_2; +} + +my_label_2: +{ +// Comment +do_thing2(); +goto my_label_3; +} +""" class TestGeneratedAbstractCases(unittest.TestCase): def setUp(self) -> None: diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 12aae969340cbd..940ea9d4da6e41 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -53,6 +53,7 @@ #define super(name) static int SUPER_##name #define family(name, ...) static int family_##name #define pseudo(name) static int pseudo_##name +#define label(name) name: /* Annotations */ #define guard @@ -103,7 +104,6 @@ dummy_func( PyObject *codeobj; PyObject *cond; PyObject *descr; -_PyInterpreterFrame entry_frame; PyObject *exc; PyObject *exit; PyObject *fget; @@ -5167,6 +5167,125 @@ dummy_func( assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version)); } +label(pop_4_error) { +STACK_SHRINK(1); +goto pop_3_error; +} + +label(pop_3_error) { +STACK_SHRINK(1); +goto pop_2_error; +} + +label(pop_2_error) { +STACK_SHRINK(1); +goto pop_1_error; +} + +label(pop_1_error) { +STACK_SHRINK(1); +goto error; +} + +label(error) { +/* Double-check exception status. */ +#ifdef NDEBUG +if (!_PyErr_Occurred(tstate)) { +_PyErr_SetString(tstate, PyExc_SystemError, + "error return without exception set"); +} +#else +assert(_PyErr_Occurred(tstate)); +#endif + +/* Log traceback info. */ +assert(frame-&
[Python-checkins] gh-128563: Move GO_TO_INSTRUCTION and PREDICT to cases generator (GH-129115)
https://github.com/python/cpython/commit/86c1a60d5a28cfb51f8843b307f8969c40e3bbec commit: 86c1a60d5a28cfb51f8843b307f8969c40e3bbec branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-01-22T09:22:25+08:00 summary: gh-128563: Move GO_TO_INSTRUCTION and PREDICT to cases generator (GH-129115) files: M Lib/test/test_generated_cases.py M Python/ceval_macros.h M Python/generated_cases.c.h M Tools/cases_generator/generators_common.py M Tools/cases_generator/tier1_generator.py diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 4b17bd5c797375..c93d6fc3d237a2 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -412,7 +412,7 @@ def test_predictions(self): frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP1); -PREDICTED(OP1); +PREDICTED_OP1:; _PyStackRef res; res = Py_None; stack_pointer[-1] = res; @@ -646,7 +646,7 @@ def test_macro_instruction(self): frame->instr_ptr = next_instr; next_instr += 6; INSTRUCTION_STATS(OP); -PREDICTED(OP); +PREDICTED_OP:; _Py_CODEUNIT* const this_instr = next_instr - 6; (void)this_instr; _PyStackRef left; diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index feaac07fe435b6..62c80c96e422fd 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -166,35 +166,6 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define JUMPBY(x) (next_instr += (x)) #define SKIP_OVER(x)(next_instr += (x)) -/* OpCode prediction macros -Some opcodes tend to come in pairs thus making it possible to -predict the second code when the first is run. For example, -COMPARE_OP is often followed by POP_JUMP_IF_FALSE or POP_JUMP_IF_TRUE. - -Verifying the prediction costs a single high-speed test of a register -variable against a constant. If the pairing was good, then the -processor's own internal branch predication has a high likelihood of -success, resulting in a nearly zero-overhead transition to the -next opcode. A successful prediction saves a trip through the eval-loop -including its unpredictable switch-case branch. Combined with the -processor's internal branch prediction, a successful PREDICT has the -effect of making the two opcodes run as if they were a single new opcode -with the bodies combined. - -If collecting opcode statistics, your choices are to either keep the -predictions turned-on and interpret the results as if some opcodes -had been combined or turn-off predictions so that the opcode frequency -counter updates for both opcodes. - -Opcode prediction is disabled with threaded code, since the latter allows -the CPU to record separate branch prediction information for each -opcode. - -*/ - -#define PREDICT_ID(op) PRED_##op -#define PREDICTED(op) PREDICT_ID(op): - /* Stack manipulation macros */ @@ -260,8 +231,6 @@ GETITEM(PyObject *v, Py_ssize_t i) { GETLOCAL(i) = value; \ PyStackRef_XCLOSE(tmp); } while (0) -#define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) - #ifdef Py_STATS #define UPDATE_MISS_STATS(INSTNAME) \ do { \ @@ -281,7 +250,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* This is only a single jump on release builds! */ \ UPDATE_MISS_STATS((INSTNAME)); \ assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \ -GO_TO_INSTRUCTION(INSTNAME);\ +goto PREDICTED_##INSTNAME; \ } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a8dbcabde538d5..d0ab667a8bc8ab 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -13,7 +13,7 @@ frame->instr_ptr = next_instr; next_instr += 6; INSTRUCTION_STATS(BINARY_OP); -PREDICTED(BINARY_OP); +PREDICTED_BINARY_OP:; _Py_CODEUNIT* const this_instr = next_instr - 6; (void)this_instr; _PyStackRef lhs; @@ -484,7 +484,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_SUBSCR); -PREDICTED(BINARY_SUBSCR); +PREDICTED_BINARY_SUBSCR:; _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef container; @@ -931,7 +931,7 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL); -PREDICTED(CALL); +PREDICTED_CALL:; _Py_CODEUNIT* const this_instr = next_inst
[Python-checkins] gh-128195: Add `_REPLACE_WITH_TRUE` to the tier2 optimizer (GH-128203)
https://github.com/python/cpython/commit/30efede33ca1fe32debbae93cc40b0e7e0b133b3 commit: 30efede33ca1fe32debbae93cc40b0e7e0b133b3 branch: main author: Yan Yanchii committer: Fidget-Spinner date: 2024-12-24T05:17:47+08:00 summary: gh-128195: Add `_REPLACE_WITH_TRUE` to the tier2 optimizer (GH-128203) Add `_REPLACE_WITH_TRUE` to the tier2 optimizer files: M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index e60c0d38425bfe..a14d119b7a1dec 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -899,6 +899,10 @@ dummy_func(void) { (void)version; } +op(_REPLACE_WITH_TRUE, (value -- res)) { +res = sym_new_const(ctx, Py_True); +} + // END BYTECODES // } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index b46079ec8a1992..0fcf5e18ed5808 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -211,7 +211,7 @@ case _REPLACE_WITH_TRUE: { _Py_UopsSymbol *res; -res = sym_new_not_null(ctx); +res = sym_new_const(ctx, Py_True); stack_pointer[-1] = res; break; } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-129819: Allow tier2/JIT and tailcall (GH-129820)
https://github.com/python/cpython/commit/1b27f36eb0ef146aa60b261a1cffcc6fd55c0e88 commit: 1b27f36eb0ef146aa60b261a1cffcc6fd55c0e88 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-13T02:18:36+08:00 summary: gh-129819: Allow tier2/JIT and tailcall (GH-129820) files: A Misc/NEWS.d/next/Build/2025-02-11-08-06-44.gh-issue-129819.7rn4dY.rst M Python/ceval_macros.h M configure M configure.ac M pyconfig.h.in diff --git a/Misc/NEWS.d/next/Build/2025-02-11-08-06-44.gh-issue-129819.7rn4dY.rst b/Misc/NEWS.d/next/Build/2025-02-11-08-06-44.gh-issue-129819.7rn4dY.rst new file mode 100644 index 00..2463e4dba24ae9 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2025-02-11-08-06-44.gh-issue-129819.7rn4dY.rst @@ -0,0 +1 @@ +Allow building the JIT with the tailcall interpreter. diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 50e940c19732ad..2cb78fa80b4658 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -397,7 +397,7 @@ do { \ stack_pointer = _PyFrame_GetStackPointer(frame); \ if (next_instr == NULL) { \ next_instr = frame->instr_ptr; \ -goto error;\ +JUMP_TO_LABEL(error); \ } \ DISPATCH();\ } while (0) diff --git a/configure b/configure index d46bc563a67245..453b0123ded0a4 100755 --- a/configure +++ b/configure @@ -29284,18 +29284,6 @@ esac fi -# Do not enable tail-calling interpreter if tier 2 is enabled. -if ${tier2_flags:+false} : -then : - -case "$ac_cv_tail_call" in yes*) - -printf "%s\n" "#define Py_TAIL_CALL_INTERP 1" >>confdefs.h - -esac - -fi - case $ac_sys_system in AIX*) diff --git a/configure.ac b/configure.ac index faa8909530389d..234ae90616af62 100644 --- a/configure.ac +++ b/configure.ac @@ -7033,19 +7033,6 @@ fi ], [AC_MSG_RESULT([no value specified])]) -# Do not enable tail-calling interpreter if tier 2 is enabled. -AS_VAR_IF( - [tier2_flags], - [], - [ -case "$ac_cv_tail_call" in yes*) - AC_DEFINE([Py_TAIL_CALL_INTERP], [1], - [Define if the C compiler supports efficient proper tail calls.]) -esac - ], - [] -) - case $ac_sys_system in AIX*) diff --git a/pyconfig.h.in b/pyconfig.h.in index 9ea01ad3fc0a31..4295b4f5ea5fbd 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1718,7 +1718,7 @@ /* The version of SunOS/Solaris as reported by `uname -r' without the dot. */ #undef Py_SUNOS_VERSION -/* Define if the C compiler supports efficient proper tail calls. */ +/* Define if you want to use tail-calling interpreters in CPython. */ #undef Py_TAIL_CALL_INTERP /* Define if you want to enable tracing references for debugging purpose */ ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-130048: Reintroduce full LTO as default on Clang (GH-130049)
https://github.com/python/cpython/commit/34c06ccc4c6c21935b46302935f3df24b00daa2c commit: 34c06ccc4c6c21935b46302935f3df24b00daa2c branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-13T22:06:00+08:00 summary: gh-130048: Reintroduce full LTO as default on Clang (GH-130049) files: A Misc/NEWS.d/next/Build/2025-02-12-19-51-19.gh-issue-130048.kHNkzP.rst M Doc/using/configure.rst M Doc/whatsnew/3.14.rst M configure M configure.ac diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 72912cea2f0c28..e7116d55815679 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -575,6 +575,9 @@ also be used to improve performance. .. versionchanged:: 3.12 Use ThinLTO as the default optimization policy on Clang if the compiler accepts the flag. + .. versionchanged:: next + Revert to using full LTO as the default optimization policy on Clang. + .. option:: --enable-bolt Enable usage of the `BOLT post-link binary optimizer diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index ece5afd4597ab8..8e4b617181fd99 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1279,6 +1279,10 @@ Build changes * GNU Autoconf 2.72 is now required to generate :file:`configure`. (Contributed by Erlend Aasland in :gh:`115765`.) +* CPython now uses Full LTO as the default link time optimization policy + on Clang. This reverts an earlier change in CPython 3.12. + (Contributed by Ken Jin in :gh:`130049`.) + .. _whatsnew314-pep761: PEP 761: Discontinuation of PGP signatures diff --git a/Misc/NEWS.d/next/Build/2025-02-12-19-51-19.gh-issue-130048.kHNkzP.rst b/Misc/NEWS.d/next/Build/2025-02-12-19-51-19.gh-issue-130048.kHNkzP.rst new file mode 100644 index 00..2344325e689f34 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2025-02-12-19-51-19.gh-issue-130048.kHNkzP.rst @@ -0,0 +1 @@ +CPython now uses Full LTO as the default link time optimization policy on Clang. This reverts an earlier change in CPython 3.12. diff --git a/configure b/configure index 453b0123ded0a4..bebc8bc1a34f9b 100755 --- a/configure +++ b/configure @@ -8766,55 +8766,8 @@ printf "%s\n" "$as_me: llvm-ar found via xcrun: ${LLVM_AR}" >&6;} # Any changes made here should be reflected in the GCC+Darwin case below if test $Py_LTO_POLICY = default then -# Check that ThinLTO is accepted. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -flto=thin" >&5 -printf %s "checking whether C compiler accepts -flto=thin... " >&6; } -if test ${ax_cv_check_cflags___flto_thin+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -flto=thin" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ax_cv_check_cflags___flto_thin=yes -else case e in #( - e) ax_cv_check_cflags___flto_thin=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$ax_check_save_flags ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 -printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } -if test "x$ax_cv_check_cflags___flto_thin" = xyes -then : - - LTOFLAGS="-flto=thin -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" - LTOCFLAGS="-flto=thin" - -else case e in #( - e) - LTOFLAGS="-flto -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" - LTOCFLAGS="-flto" - - ;; -esac -fi - +LTOFLAGS="-flto -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" +LTOCFLAGS="-flto" else LTOFLAGS="-flto=${Py_LTO_POLICY} -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" LTOCFLAGS="-flto=${Py_LTO_POLICY}" @@ -8823,48 +8776,7 @@ fi *) if test $Py_LTO_POLICY = default then -# Check that ThinLTO is accepted -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -flto=thin" >&5 -printf %s "checking whether C compiler accepts -flto=thin... " >&6; } -if test ${ax_cv_check_cflags___flto_thin+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -flto=thin" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINEN
[Python-checkins] Trigger tail call CI on more files (GH-129906)
https://github.com/python/cpython/commit/8f9c6fa0773cff586d127d1b77b158edd4718035 commit: 8f9c6fa0773cff586d127d1b77b158edd4718035 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-10T00:52:58+08:00 summary: Trigger tail call CI on more files (GH-129906) files: M .github/workflows/tail-call.yml diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml index 37df21af02e919..4c2516c517b3a9 100644 --- a/.github/workflows/tail-call.yml +++ b/.github/workflows/tail-call.yml @@ -5,11 +5,13 @@ on: - 'Python/bytecodes.c' - 'Python/ceval.c' - 'Python/ceval_macros.h' + - 'Python/generated_cases.c.h' push: paths: - 'Python/bytecodes.c' - 'Python/ceval.c' - 'Python/ceval_macros.h' + - 'Python/generated_cases.c.h' workflow_dispatch: permissions: ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-129989: Properly disable tailcall interp in configure (GH-129991)
https://github.com/python/cpython/commit/359c7dde3bb074e029686913f531457eb121d1dd commit: 359c7dde3bb074e029686913f531457eb121d1dd branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-16T03:01:24+08:00 summary: gh-129989: Properly disable tailcall interp in configure (GH-129991) Co-authored-by: Zanie Blue files: A Misc/NEWS.d/next/Build/2025-02-11-07-55-28.gh-issue-129989.kaSKlD.rst M Lib/test/test_generated_cases.py M Python/bytecodes.c M Python/ceval.c M Python/ceval_macros.h M Python/generated_cases.c.h M Python/opcode_targets.h M Tools/cases_generator/target_generator.py M Tools/cases_generator/tier1_generator.py diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index f9a54f3b412b4a..ff6b566faa4a23 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -304,7 +304,7 @@ def test_inst_no_args(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -326,7 +326,7 @@ def test_inst_one_pop(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -351,7 +351,7 @@ def test_inst_one_push(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -377,7 +377,7 @@ def test_inst_one_push_one_pop(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -404,7 +404,7 @@ def test_binary_op(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -434,7 +434,7 @@ def test_overlap(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -466,7 +466,7 @@ def test_predictions(self): """ output = """ TARGET(OP1) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP1; (void)(opcode); #endif @@ -481,7 +481,7 @@ def test_predictions(self): } TARGET(OP3) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP3; (void)(opcode); #endif @@ -519,7 +519,7 @@ def test_sync_sp(self): """ output = """ TARGET(A) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = A; (void)(opcode); #endif @@ -540,7 +540,7 @@ def test_sync_sp(self): } TARGET(B) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = B; (void)(opcode); #endif @@ -581,7 +581,7 @@ def test_error_if_plain(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -604,7 +604,7 @@ def test_error_if_plain_with_comment(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -631,7 +631,7 @@ def test_error_if_pop(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -666,7 +666,7 @@ def test_error_if_pop_with_result(self): """ output = """ TARGET(OP) { -#if defined(Py_TAIL_CALL_INTERP) +#if Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -697,7 +697,7 @@ def test_cache_effect(self): """ output = &q
[Python-checkins] Add Neil's suggestions to whatsnew wording for tailcall (#130155)
https://github.com/python/cpython/commit/a13460ac4427892be613bf0e2988f5a2b2364602 commit: a13460ac4427892be613bf0e2988f5a2b2364602 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-15T21:09:37+08:00 summary: Add Neil's suggestions to whatsnew wording for tailcall (#130155) Add Neil's suggestions Co-authored-by: Neil Schemenauer <690853+nasch...@users.noreply.github.com> files: M Doc/whatsnew/3.14.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index ece5afd4597ab8..c42a5a022b7e43 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -224,7 +224,9 @@ configuration mechanisms). A new type of interpreter - -A new type of interpreter based on tail calls has been added to CPython. +A new type of interpreter has been added to CPython. +It uses tail calls between small C functions that implement individual +Python opcodes, rather than one large C case statement. For certain newer compilers, this interpreter provides significantly better performance. Preliminary numbers on our machines suggest anywhere from -3% to 30% faster Python code, and a geometric mean of 9-15% ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-132132: Upgrade LLVM on tail calling CI (GH-132098)
https://github.com/python/cpython/commit/92fb949eac22d1e058906123a21791ba55876090 commit: 92fb949eac22d1e058906123a21791ba55876090 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-04-06T00:58:23+08:00 summary: gh-132132: Upgrade LLVM on tail calling CI (GH-132098) files: M .github/workflows/tail-call.yml diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml index 572ff45e51ef00..4636372e26c41b 100644 --- a/.github/workflows/tail-call.yml +++ b/.github/workflows/tail-call.yml @@ -45,7 +45,7 @@ jobs: - aarch64-unknown-linux-gnu/gcc - free-threading llvm: - - 19 + - 20 include: # - target: i686-pc-windows-msvc/msvc #architecture: Win32 @@ -83,9 +83,9 @@ jobs: if: runner.os == 'Windows' && matrix.architecture != 'ARM64' shell: cmd run: | - choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.5 + choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0 set PlatformToolset=clangcl - set LLVMToolsVersion=${{ matrix.llvm }}.1.5 + set LLVMToolsVersion=${{ matrix.llvm }}.1.0 set LLVMInstallDir=C:\Program Files\LLVM call ./PCbuild/build.bat --tail-call-interp -d -p ${{ matrix.architecture }} call ./PCbuild/rt.bat -d -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3 @@ -95,9 +95,9 @@ jobs: if: runner.os == 'Windows' && matrix.architecture == 'ARM64' shell: cmd run: | - choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.5 + choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0 set PlatformToolset=clangcl - set LLVMToolsVersion=${{ matrix.llvm }}.1.5 + set LLVMToolsVersion=${{ matrix.llvm }}.1.0 set LLVMInstallDir=C:\Program Files\LLVM ./PCbuild/build.bat --tail-call-interp -p ${{ matrix.architecture }} @@ -105,6 +105,8 @@ jobs: # This is a bug in the macOS runner image where the pre-installed Python is installed in the same # directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes # the symlink to the pre-installed Python so that the Homebrew Python is used instead. +# Note: when a new LLVM is released, the homebrew installation directory changes, so the builds will fail. +# We either need to upgrade LLVM or change the directory being pointed to. - name: Native macOS (release) if: runner.os == 'macOS' run: | @@ -112,9 +114,9 @@ jobs: find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete brew install llvm@${{ matrix.llvm }} export SDKROOT="$(xcrun --show-sdk-path)" - export PATH="/opt/homebrew/opt/llvm@${{ matrix.llvm }}/bin:$PATH" - export PATH="/usr/local/opt/llvm@${{ matrix.llvm }}/bin:$PATH" - CC=clang-19 ./configure --with-tail-call-interp + export PATH="/usr/local/opt/llvm/bin:$PATH" + export PATH="/opt/homebrew/opt/llvm/bin:$PATH" + CC=clang-20 ./configure --with-tail-call-interp make all --jobs 4 ./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3 @@ -123,7 +125,7 @@ jobs: run: | sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }} export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH" - CC=clang-19 ./configure --with-tail-call-interp --with-pydebug + CC=clang-20 ./configure --with-tail-call-interp --with-pydebug make all --jobs 4 ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3 @@ -132,7 +134,7 @@ jobs: run: | sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }} export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH" - CC=clang-19 ./configure --with-tail-call-interp --disable-gil + CC=clang-20 ./configure --with-tail-call-interp --disable-gil make all --jobs 4 ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3 ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-126703: Add PyCFunction freelist (GH-128692)
https://github.com/python/cpython/commit/29772b0647519254b94bdf82df1666e98c3de3a2 commit: 29772b0647519254b94bdf82df1666e98c3de3a2 branch: main author: Pieter Eendebak committer: Fidget-Spinner date: 2025-04-05T23:51:05+08:00 summary: gh-126703: Add PyCFunction freelist (GH-128692) files: A Misc/NEWS.d/next/Core_and_Builtins/2025-01-09-22-12-03.gh-issue-126703.6rAxZ7.rst M Include/internal/pycore_freelist_state.h M Objects/methodobject.c M Objects/object.c diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 7c252f5b570c13..54415b22fd41ef 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -24,6 +24,8 @@ extern "C" { # define Py_futureiters_MAXFREELIST 255 # define Py_object_stack_chunks_MAXFREELIST 4 # define Py_unicode_writers_MAXFREELIST 1 +# define Py_pycfunctionobject_MAXFREELIST 16 +# define Py_pycmethodobject_MAXFREELIST 16 # define Py_pymethodobjects_MAXFREELIST 20 // A generic freelist of either PyObjects or other data structures. @@ -53,6 +55,8 @@ struct _Py_freelists { struct _Py_freelist futureiters; struct _Py_freelist object_stack_chunks; struct _Py_freelist unicode_writers; +struct _Py_freelist pycfunctionobject; +struct _Py_freelist pycmethodobject; struct _Py_freelist pymethodobjects; }; diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-09-22-12-03.gh-issue-126703.6rAxZ7.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-09-22-12-03.gh-issue-126703.6rAxZ7.rst new file mode 100644 index 00..6dc04135c7879e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-09-22-12-03.gh-issue-126703.6rAxZ7.rst @@ -0,0 +1 @@ +Improve performance of builtin methods by using a freelist. diff --git a/Objects/methodobject.c b/Objects/methodobject.c index ecec0f7205a11d..1f459dea44192c 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_call.h" // _Py_CheckFunctionResult() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() +#include "pycore_freelist.h" #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() @@ -85,9 +86,12 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c "flag but no class"); return NULL; } -PyCMethodObject *om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type); +PyCMethodObject *om = _Py_FREELIST_POP(PyCMethodObject, pycmethodobject); if (om == NULL) { -return NULL; +om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type); +if (om == NULL) { +return NULL; +} } om->mm_class = (PyTypeObject*)Py_NewRef(cls); op = (PyCFunctionObject *)om; @@ -98,9 +102,12 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c "but no METH_METHOD flag"); return NULL; } -op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); +op = _Py_FREELIST_POP(PyCFunctionObject, pycfunctionobject); if (op == NULL) { -return NULL; +op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); +if (op == NULL) { +return NULL; +} } } @@ -171,7 +178,14 @@ meth_dealloc(PyObject *self) Py_XDECREF(PyCFunction_GET_CLASS(m)); Py_XDECREF(m->m_self); Py_XDECREF(m->m_module); -PyObject_GC_Del(m); +if (m->m_ml->ml_flags & METH_METHOD) { +assert(Py_IS_TYPE(self, &PyCMethod_Type)); +_Py_FREELIST_FREE(pycmethodobject, m, PyObject_GC_Del); +} +else { +assert(Py_IS_TYPE(self, &PyCFunction_Type)); +_Py_FREELIST_FREE(pycfunctionobject, m, PyObject_GC_Del); +} Py_TRASHCAN_END; } diff --git a/Objects/object.c b/Objects/object.c index 457ff17b980e75..42ac3a1c2baa7b 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -942,6 +942,8 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) } clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free); clear_freelist(&freelists->ints, is_finalization, free_object); +clear_freelist(&freelists->pycfunctionobject, is_finalization, PyObject_GC_Del); +clear_freelist(&freelists->pycmethodobject, is_finalization, PyObject_GC_Del); clear_freelist(&freelists->pymethodobjects, is_finalization, free_object); } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-131591: Fix GENERATE_DEBUG_SECTION for clangcl on Windows (GH-132112)
https://github.com/python/cpython/commit/d827d4d0184f8832075c6b75120892439a1d97ee commit: d827d4d0184f8832075c6b75120892439a1d97ee branch: main author: Chris Eibl <138194463+chris-e...@users.noreply.github.com> committer: Fidget-Spinner date: 2025-04-06T00:00:54+08:00 summary: gh-131591: Fix GENERATE_DEBUG_SECTION for clangcl on Windows (GH-132112) files: M Include/internal/pycore_debug_offsets.h M Modules/_asynciomodule.c M Tools/c-analyzer/cpython/ignored.tsv diff --git a/Include/internal/pycore_debug_offsets.h b/Include/internal/pycore_debug_offsets.h index 124b104e4ba8ae..b280633c9ef679 100644 --- a/Include/internal/pycore_debug_offsets.h +++ b/Include/internal/pycore_debug_offsets.h @@ -23,7 +23,9 @@ extern "C" { declaration \ _GENERATE_DEBUG_SECTION_LINUX(name) -#if defined(MS_WINDOWS) && !defined(__clang__) +// Please note that section names are truncated to eight bytes +// on Windows! +#if defined(MS_WINDOWS) #define _GENERATE_DEBUG_SECTION_WINDOWS(name) \ _Pragma(Py_STRINGIFY(section(Py_STRINGIFY(name), read, write))) \ __declspec(allocate(Py_STRINGIFY(name))) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index d938955e8cb0e3..b32db3a277cf4a 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -116,7 +116,7 @@ typedef struct _Py_AsyncioModuleDebugOffsets { } asyncio_thread_state; } Py_AsyncioModuleDebugOffsets; -GENERATE_DEBUG_SECTION(AsyncioDebug, Py_AsyncioModuleDebugOffsets AsyncioDebug) +GENERATE_DEBUG_SECTION(AsyncioDebug, Py_AsyncioModuleDebugOffsets _AsyncioDebug) = {.asyncio_task_object = { .size = sizeof(TaskObj), .task_name = offsetof(TaskObj, task_name), diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 18e543ab33bb16..14dc5007b65861 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -56,7 +56,7 @@ Python/pyhash.c - _Py_HashSecret - Python/parking_lot.c - buckets - ## data needed for introspecting asyncio state from debuggers and profilers -Modules/_asynciomodule.c - AsyncioDebug- +Modules/_asynciomodule.c - _AsyncioDebug - ## ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-126703: Add freelist for range and range_iter objects (GH-128619)
https://github.com/python/cpython/commit/dff8bcfa3cb2daf0aa0d3f4717fd77948d3b2b2f commit: dff8bcfa3cb2daf0aa0d3f4717fd77948d3b2b2f branch: main author: Pieter Eendebak committer: Fidget-Spinner date: 2025-04-07T04:40:52+08:00 summary: gh-126703: Add freelist for range and range_iter objects (GH-128619) files: A Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-09-41-25.gh-issue-126703.djs9e_.rst M Include/internal/pycore_freelist_state.h M Objects/object.c M Objects/rangeobject.c diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 54415b22fd41ef..4828dfd948f70a 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -18,6 +18,8 @@ extern "C" { # define Py_floats_MAXFREELIST 100 # define Py_ints_MAXFREELIST 100 # define Py_slices_MAXFREELIST 1 +# define Py_ranges_MAXFREELIST 6 +# define Py_range_iters_MAXFREELIST 6 # define Py_contexts_MAXFREELIST 255 # define Py_async_gens_MAXFREELIST 80 # define Py_async_gen_asends_MAXFREELIST 80 @@ -49,6 +51,8 @@ struct _Py_freelists { struct _Py_freelist dicts; struct _Py_freelist dictkeys; struct _Py_freelist slices; +struct _Py_freelist ranges; +struct _Py_freelist range_iters; struct _Py_freelist contexts; struct _Py_freelist async_gens; struct _Py_freelist async_gen_asends; diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-09-41-25.gh-issue-126703.djs9e_.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-09-41-25.gh-issue-126703.djs9e_.rst new file mode 100644 index 00..2fb44568b12168 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-09-41-25.gh-issue-126703.djs9e_.rst @@ -0,0 +1 @@ +Improve performance of :class:`range` by using a freelist. diff --git a/Objects/object.c b/Objects/object.c index 42ac3a1c2baa7b..99bb1d9c0bfad5 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -931,6 +931,8 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) clear_freelist(&freelists->dicts, is_finalization, free_object); clear_freelist(&freelists->dictkeys, is_finalization, PyMem_Free); clear_freelist(&freelists->slices, is_finalization, free_object); +clear_freelist(&freelists->ranges, is_finalization, free_object); +clear_freelist(&freelists->range_iters, is_finalization, free_object); clear_freelist(&freelists->contexts, is_finalization, free_object); clear_freelist(&freelists->async_gens, is_finalization, free_object); clear_freelist(&freelists->async_gen_asends, is_finalization, free_object); diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 24f9ce807fd24e..f8cdfe68a6435e 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_freelist.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_modsupport.h"// _PyArg_NoKwnames() #include "pycore_range.h" @@ -51,16 +52,18 @@ static rangeobject * make_range_object(PyTypeObject *type, PyObject *start, PyObject *stop, PyObject *step) { -rangeobject *obj = NULL; PyObject *length; length = compute_range_length(start, stop, step); if (length == NULL) { return NULL; } -obj = PyObject_New(rangeobject, type); +rangeobject *obj = _Py_FREELIST_POP(rangeobject, ranges); if (obj == NULL) { -Py_DECREF(length); -return NULL; +obj = PyObject_New(rangeobject, type); +if (obj == NULL) { +Py_DECREF(length); +return NULL; +} } obj->start = start; obj->stop = stop; @@ -171,7 +174,7 @@ range_dealloc(PyObject *op) Py_DECREF(r->stop); Py_DECREF(r->step); Py_DECREF(r->length); -PyObject_Free(r); +_Py_FREELIST_FREE(ranges, r, PyObject_Free); } static unsigned long @@ -895,6 +898,12 @@ rangeiter_setstate(PyObject *op, PyObject *state) Py_RETURN_NONE; } +static void +rangeiter_dealloc(PyObject *self) +{ +_Py_FREELIST_FREE(range_iters, (_PyRangeIterObject *)self, PyObject_Free); +} + PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); @@ -911,7 +920,7 @@ PyTypeObject PyRangeIter_Type = { sizeof(_PyRangeIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ -0, /* tp_dealloc */ +rangeiter_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset *
[Python-checkins] gh-126703: Fix possible use after free in pycfunction freelist (GH-132319)
https://github.com/python/cpython/commit/bd3aa0b9f736164277a5bcd0a54f5f9beddbf11c commit: bd3aa0b9f736164277a5bcd0a54f5f9beddbf11c branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-04-09T22:49:33+08:00 summary: gh-126703: Fix possible use after free in pycfunction freelist (GH-132319) files: A Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-13-47-33.gh-issue-126703.kXiQHj.rst M Objects/methodobject.c diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-13-47-33.gh-issue-126703.kXiQHj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-13-47-33.gh-issue-126703.kXiQHj.rst new file mode 100644 index 00..d0461e17d0fa95 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-13-47-33.gh-issue-126703.kXiQHj.rst @@ -0,0 +1 @@ +Fix possible use after free in cases where a method's definition has the same lifetime as its ``self``. diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 1f459dea44192c..189b026ab33559 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -173,12 +173,16 @@ meth_dealloc(PyObject *self) if (m->m_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject*) m); } +// We need to access ml_flags here rather than later. +// `m->m_ml` might have the same lifetime +// as `m_self` when it's dynamically allocated. +int ml_flags = m->m_ml->ml_flags; // Dereference class before m_self: PyCFunction_GET_CLASS accesses // PyMethodDef m_ml, which could be kept alive by m_self Py_XDECREF(PyCFunction_GET_CLASS(m)); Py_XDECREF(m->m_self); Py_XDECREF(m->m_module); -if (m->m_ml->ml_flags & METH_METHOD) { +if (ml_flags & METH_METHOD) { assert(Py_IS_TYPE(self, &PyCMethod_Type)); _Py_FREELIST_FREE(pycmethodobject, m, PyObject_GC_Del); } ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] GH-131678: fix Windows tail-call CI does not run the test cases (GH-131690)
https://github.com/python/cpython/commit/ce77da5871334bffea722984cb705fd20a763a1f commit: ce77da5871334bffea722984cb705fd20a763a1f branch: main author: Chris Eibl <138194463+chris-e...@users.noreply.github.com> committer: Fidget-Spinner date: 2025-03-28T23:00:36+08:00 summary: GH-131678: fix Windows tail-call CI does not run the test cases (GH-131690) files: M .github/workflows/tail-call.yml diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml index 3bee758e2ad2cf..3c9098b88ee3b1 100644 --- a/.github/workflows/tail-call.yml +++ b/.github/workflows/tail-call.yml @@ -87,8 +87,8 @@ jobs: set PlatformToolset=clangcl set LLVMToolsVersion=${{ matrix.llvm }}.1.5 set LLVMInstallDir=C:\Program Files\LLVM - ./PCbuild/build.bat --tail-call-interp -d -p ${{ matrix.architecture }} - ./PCbuild/rt.bat -d -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3 + call ./PCbuild/build.bat --tail-call-interp -d -p ${{ matrix.architecture }} + call ./PCbuild/rt.bat -d -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3 # No tests (yet): - name: Emulated Windows (release) ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-131281: fix compile error due to `BINARY_SUBSCR` (GH-131283)
https://github.com/python/cpython/commit/1821f8f10c7a4a43a4fb55fe4e3da4cadfec699d commit: 1821f8f10c7a4a43a4fb55fe4e3da4cadfec699d branch: main author: Xuanteng Huang <44627253+xuante...@users.noreply.github.com> committer: Fidget-Spinner date: 2025-03-15T23:38:46+08:00 summary: gh-131281: fix compile error due to `BINARY_SUBSCR` (GH-131283) * fix compile error due to `BINARY_SUBSCR` * replace stat_inc with `BINARY_OP` files: M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index aaa25161d0943f..7af4d642edb919 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -878,7 +878,7 @@ dummy_func( assert(res_o != NULL); res = PyStackRef_FromPyObjectNew(res_o); #endif -STAT_INC(BINARY_SUBSCR, hit); +STAT_INC(BINARY_OP, hit); DECREF_INPUTS(); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index fb5b2240436f1c..ff9f33b6db0187 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1253,7 +1253,7 @@ assert(res_o != NULL); res = PyStackRef_FromPyObjectNew(res_o); #endif -STAT_INC(BINARY_SUBSCR, hit); +STAT_INC(BINARY_OP, hit); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = list_st; list_st = res; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 8cdbaf1a4d5761..558b0b48ceaa71 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -702,7 +702,7 @@ assert(res_o != NULL); res = PyStackRef_FromPyObjectNew(res_o); #endif -STAT_INC(BINARY_SUBSCR, hit); +STAT_INC(BINARY_OP, hit); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = list_st; list_st = res; ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-131281: Add include for pystats builds (#131369)
https://github.com/python/cpython/commit/b2ed7a6d6aae9860110f6ec495dc88dde670cfe4 commit: b2ed7a6d6aae9860110f6ec495dc88dde670cfe4 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-03-18T00:36:06+08:00 summary: gh-131281: Add include for pystats builds (#131369) Add include to for pystats builds files: M Python/specialize.c diff --git a/Python/specialize.c b/Python/specialize.c index 07c49140446c12..4aa2fb9f7359f9 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -18,6 +18,7 @@ #include "pycore_opcode_utils.h" // RESUME_AT_FUNC_START #include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() #include "pycore_runtime.h" // _Py_ID() +#include "pycore_unicodeobject.h" // _PyUnicodeASCIIIter_Type #include // rand() ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-132257: Remove -flto-partition=none for Linux LTO builds (GH-132258)
https://github.com/python/cpython/commit/bc0b94b30c9d65ba550daee2c2ef20035defd980 commit: bc0b94b30c9d65ba550daee2c2ef20035defd980 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-04-11T16:06:05+08:00 summary: gh-132257: Remove -flto-partition=none for Linux LTO builds (GH-132258) Change the default LTO flags on GCC to not pass -flto-partition=none, and allow parallelization of LTO. This has a multiple factor speedup for LTO build times on GCC, with no noticeable loss in performance. On newer make and newer GCC, this passes the jobserver automatically to GCC (or more like GCC grabs it from the env vars). On older make, this will have benign warnings about serial compilation. It's safe to ignore them. files: A Misc/NEWS.d/next/Build/2025-04-08-09-11-32.gh-issue-132257.oZWBV-.rst M configure M configure.ac diff --git a/Misc/NEWS.d/next/Build/2025-04-08-09-11-32.gh-issue-132257.oZWBV-.rst b/Misc/NEWS.d/next/Build/2025-04-08-09-11-32.gh-issue-132257.oZWBV-.rst new file mode 100644 index 00..5bf20d2f1d0d22 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2025-04-08-09-11-32.gh-issue-132257.oZWBV-.rst @@ -0,0 +1 @@ +Change the default LTO flags on GCC to not pass ``-flto-partition=none``, and allow parallelization of LTO. For newer GNU makes and GCC, this has a multiple factor speedup for LTO build times, with no noticeable loss in performance. diff --git a/configure b/configure index 24a7d1d43f0467..decb8f2449d162 100755 --- a/configure +++ b/configure @@ -8894,7 +8894,7 @@ fi LTOCFLAGS="-flto" ;; *) - LTOFLAGS="-flto -fuse-linker-plugin -ffat-lto-objects -flto-partition=none" + LTOFLAGS="-flto -fuse-linker-plugin -ffat-lto-objects" ;; esac ;; diff --git a/configure.ac b/configure.ac index bc6479c048f745..004797b5233c20 100644 --- a/configure.ac +++ b/configure.ac @@ -2031,7 +2031,7 @@ if test "$Py_LTO" = 'true' ; then LTOCFLAGS="-flto" ;; *) - LTOFLAGS="-flto -fuse-linker-plugin -ffat-lto-objects -flto-partition=none" + LTOFLAGS="-flto -fuse-linker-plugin -ffat-lto-objects" ;; esac ;; ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-132386: Fix a crash when passing a dict subclass to `exec` (GH-132412)
https://github.com/python/cpython/commit/e6ef47ac229b5c4a62b9c907e4232e350db77ce3 commit: e6ef47ac229b5c4a62b9c907e4232e350db77ce3 branch: main author: Tomas R. committer: Fidget-Spinner date: 2025-04-12T05:05:03+08:00 summary: gh-132386: Fix a crash when passing a dict subclass to `exec` (GH-132412) * Fix crash when passing a dict subclass to exec * Add news entry files: A Misc/NEWS.d/next/Core_and_Builtins/2025-04-11-18-46-37.gh-issue-132386.pMBFTe.rst M Lib/test/test_compile.py M Python/ceval.c diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index ce9c060641d6c5..9cc025d85e168a 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1636,6 +1636,16 @@ async def name_4(): pass [[]] +def test_globals_dict_subclass(self): +# gh-132386 +class WeirdDict(dict): +pass + +ns = {} +exec('def foo(): return a', WeirdDict(), ns) + +self.assertRaises(NameError, ns['foo']) + class TestBooleanExpression(unittest.TestCase): class Value: def __init__(self): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-11-18-46-37.gh-issue-132386.pMBFTe.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-11-18-46-37.gh-issue-132386.pMBFTe.rst new file mode 100644 index 00..65ba7fc182b674 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-11-18-46-37.gh-issue-132386.pMBFTe.rst @@ -0,0 +1,2 @@ +Fix crash when passing a dict subclass as the ``globals`` parameter to +:func:`exec`. diff --git a/Python/ceval.c b/Python/ceval.c index 8ab0c6318c1c91..e4a63ad9287783 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3312,6 +3312,8 @@ _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject *name _PyEval_FormatExcCheckArg( PyThreadState_GET(), PyExc_NameError, NAME_ERROR_MSG, name); +*writeto = PyStackRef_NULL; +return; } } *writeto = PyStackRef_FromPyObjectSteal(res); ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-131798: JIT - Use `sym_new_type` instead of `sym_new_not_null` for _BUILD_STRING, _BUILD_SET (GH-132564)
https://github.com/python/cpython/commit/614d79231d1e60d31b9452ea2afbc2a7d2f0034b commit: 614d79231d1e60d31b9452ea2afbc2a7d2f0034b branch: main author: Nadeshiko Manju committer: Fidget-Spinner date: 2025-04-27T20:30:28+08:00 summary: gh-131798: JIT - Use `sym_new_type` instead of `sym_new_not_null` for _BUILD_STRING, _BUILD_SET (GH-132564) Signed-off-by: Manjusaka files: A Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-18-43-31.gh-issue-131798.FsIypo.rst M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-18-43-31.gh-issue-131798.FsIypo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-18-43-31.gh-issue-131798.FsIypo.rst new file mode 100644 index 00..a252d2b69fc020 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-18-43-31.gh-issue-131798.FsIypo.rst @@ -0,0 +1,2 @@ +Use ``sym_new_type`` instead of ``sym_new_not_null`` for _BUILD_STRING, +_BUILD_SET diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index f862c9c8c6a840..567caad22554ea 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -977,6 +977,14 @@ dummy_func(void) { map = sym_new_type(ctx, &PyDict_Type); } +op(_BUILD_STRING, (values[oparg] -- str)) { +str = sym_new_type(ctx, &PyUnicode_Type); +} + +op(_BUILD_SET, (values[oparg] -- set)) { +set = sym_new_type(ctx, &PySet_Type); +} + op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) { val0 = sym_tuple_getitem(ctx, seq, 0); val1 = sym_tuple_getitem(ctx, seq, 1); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index c92b036eb56463..679240b6efa315 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1032,7 +1032,7 @@ case _BUILD_STRING: { JitOptSymbol *str; -str = sym_new_not_null(ctx); +str = sym_new_type(ctx, &PyUnicode_Type); stack_pointer[-oparg] = str; stack_pointer += 1 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -1073,7 +1073,7 @@ case _BUILD_SET: { JitOptSymbol *set; -set = sym_new_not_null(ctx); +set = sym_new_type(ctx, &PySet_Type); stack_pointer[-oparg] = set; stack_pointer += 1 - oparg; assert(WITHIN_STACK_BOUNDS()); ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-132758: Fix tail call and pystats builds (GH-132759)
https://github.com/python/cpython/commit/6430c634da4332550744fe8f50b12c927b8382f6 commit: 6430c634da4332550744fe8f50b12c927b8382f6 branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-04-23T18:17:35+08:00 summary: gh-132758: Fix tail call and pystats builds (GH-132759) files: A Misc/NEWS.d/next/Build/2025-04-20-20-07-44.gh-issue-132758.N2a3wp.rst M Python/ceval.c M Python/ceval_macros.h diff --git a/Misc/NEWS.d/next/Build/2025-04-20-20-07-44.gh-issue-132758.N2a3wp.rst b/Misc/NEWS.d/next/Build/2025-04-20-20-07-44.gh-issue-132758.N2a3wp.rst new file mode 100644 index 00..0645c35c18c133 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2025-04-20-20-07-44.gh-issue-132758.N2a3wp.rst @@ -0,0 +1 @@ +Fix building with tail call interpreter and pystats. diff --git a/Python/ceval.c b/Python/ceval.c index 17e28439872ba2..fb72fd49811e2d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1071,7 +1071,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int monitor_throw(tstate, frame, next_instr); stack_pointer = _PyFrame_GetStackPointer(frame); #if Py_TAIL_CALL_INTERP -return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0); +# if Py_STATS +return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0, lastopcode); +# else +return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0); +# endif #else goto error; #endif @@ -1083,7 +1087,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int const _PyUOpInstruction *next_uop = NULL; #endif #if Py_TAIL_CALL_INTERP -return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0); +# if Py_STATS +return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0, lastopcode); +# else +return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0); +# endif #else goto start_frame; # include "generated_cases.c.h" diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 3dca4e46ee75e4..e1d2673848cc69 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -70,8 +70,13 @@ #define INSTRUCTION_STATS(op) ((void)0) #endif -#define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg -#define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg +#ifdef Py_STATS +# define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg, int lastopcode +# define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg, lastopcode +#else +# define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg +# define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg +#endif #if Py_TAIL_CALL_INTERP // Note: [[clang::musttail]] works for GCC 15, but not __attribute__((musttail)) at the moment. @@ -88,10 +93,17 @@ do { \ Py_MUSTTAIL return (_TAIL_CALL_##name)(TAIL_CALL_ARGS); \ } while (0) -# define JUMP_TO_PREDICTED(name) \ -do { \ -Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg); \ -} while (0) +# ifdef Py_STATS +# define JUMP_TO_PREDICTED(name) \ +do { \ +Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg, lastopcode); \ +} while (0) +# else +# define JUMP_TO_PREDICTED(name) \ +do { \ +Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg); \ +} while (0) +# endif #define LABEL(name) TARGET(name) #elif USE_COMPUTED_GOTOS # define TARGET(op) TARGET_##op: ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-131798: Use `sym_new_type` instead of `sym_new_not_null` for `_BUILD_LIST`, `_BUILD_SLICE`, and `_BUILD_MAP` (GH-132434)
https://github.com/python/cpython/commit/b9e88ff4cbf6481578421d58acf2455647cefeb4 commit: b9e88ff4cbf6481578421d58acf2455647cefeb4 branch: main author: Nadeshiko Manju committer: Fidget-Spinner date: 2025-04-17T01:17:48+08:00 summary: gh-131798: Use `sym_new_type` instead of `sym_new_not_null` for `_BUILD_LIST`, `_BUILD_SLICE`, and `_BUILD_MAP` (GH-132434) - Signed-off-by: Manjusaka files: A Misc/NEWS.d/next/Core_and_Builtins/2025-04-12-19-41-16.gh-issue-131798.JkSocg.rst M Lib/test/test_capi/test_opt.py M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index c0e771a0d59c4f..34b7c5982245c7 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1678,7 +1678,7 @@ def f(n): x = 0 for _ in range(n): d = {} -d["Spam"] = 1 # Guarded... +d["Spam"] = 1 # unguarded! x += d["Spam"] # ...unguarded! return x @@ -1686,7 +1686,7 @@ def f(n): self.assertEqual(res, TIER2_THRESHOLD) self.assertIsNotNone(ex) uops = get_opnames(ex) -self.assertEqual(uops.count("_GUARD_NOS_DICT"), 1) +self.assertEqual(uops.count("_GUARD_NOS_DICT"), 0) self.assertEqual(uops.count("_STORE_SUBSCR_DICT"), 1) self.assertEqual(uops.count("_BINARY_OP_SUBSCR_DICT"), 1) @@ -1695,7 +1695,7 @@ def f(n): x = 0 for _ in range(n): l = [0] -l[0] = 1 # Guarded... +l[0] = 1 # unguarded! [a] = l # ...unguarded! b = l[0] # ...unguarded! if l: # ...unguarded! @@ -1706,7 +1706,7 @@ def f(n): self.assertEqual(res, 2 * TIER2_THRESHOLD) self.assertIsNotNone(ex) uops = get_opnames(ex) -self.assertEqual(uops.count("_GUARD_NOS_LIST"), 1) +self.assertEqual(uops.count("_GUARD_NOS_LIST"), 0) self.assertEqual(uops.count("_STORE_SUBSCR_LIST_INT"), 1) self.assertEqual(uops.count("_GUARD_TOS_LIST"), 0) self.assertEqual(uops.count("_UNPACK_SEQUENCE_LIST"), 1) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-12-19-41-16.gh-issue-131798.JkSocg.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-12-19-41-16.gh-issue-131798.JkSocg.rst new file mode 100644 index 00..5a9c0cde35fffb --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-12-19-41-16.gh-issue-131798.JkSocg.rst @@ -0,0 +1,2 @@ +Use ``sym_new_type`` instead of ``sym_new_not_null`` for _BUILD_LIST, +_BUILD_SET, _BUILD_MAP diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 8e1eacfec83e95..43fe2107bf998a 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -919,6 +919,18 @@ dummy_func(void) { tup = sym_new_tuple(ctx, oparg, values); } +op(_BUILD_LIST, (values[oparg] -- list)) { +list = sym_new_type(ctx, &PyList_Type); +} + +op(_BUILD_SLICE, (values[oparg] -- slice)) { +slice = sym_new_type(ctx, &PySlice_Type); +} + +op(_BUILD_MAP, (values[oparg*2] -- map)) { +map = sym_new_type(ctx, &PyDict_Type); +} + op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) { val0 = sym_tuple_getitem(ctx, seq, 0); val1 = sym_tuple_getitem(ctx, seq, 1); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 6a20cef906242b..f51b00d25fe506 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1031,7 +1031,7 @@ case _BUILD_LIST: { JitOptSymbol *list; -list = sym_new_not_null(ctx); +list = sym_new_type(ctx, &PyList_Type); stack_pointer[-oparg] = list; stack_pointer += 1 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -1061,7 +1061,7 @@ case _BUILD_MAP: { JitOptSymbol *map; -map = sym_new_not_null(ctx); +map = sym_new_type(ctx, &PyDict_Type); stack_pointer[-oparg*2] = map; stack_pointer += 1 - oparg*2; assert(WITHIN_STACK_BOUNDS()); @@ -2092,7 +2092,7 @@ case _BUILD_SLICE: { JitOptSymbol *slice; -slice = sym_new_not_null(ctx); +slice = sym_new_type(ctx, &PySlice_Type); stack_pointer[-oparg] = slice; stack_pointer += 1 - oparg; assert(WITHIN_STACK_BOUNDS()); ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-131798: JIT: Narrow the return type of _CALL_LEN to int (#132940)
https://github.com/python/cpython/commit/4c20f46fa011df57190cc19b21bafde1f65e73a7 commit: 4c20f46fa011df57190cc19b21bafde1f65e73a7 branch: main author: Diego Russo committer: Fidget-Spinner date: 2025-04-26T02:57:42+08:00 summary: gh-131798: JIT: Narrow the return type of _CALL_LEN to int (#132940) Reduce unnecessary guards whenever `len()` is called and used after. Co-authored-by: Max Bernstein files: A Misc/NEWS.d/next/Core_and_Builtins/2025-04-25-14-56-45.gh-issue-131798.NpcKub.rst M Lib/test/test_capi/test_opt.py M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 0fb2d78a87ecf1..0047306ae422db 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1911,6 +1911,18 @@ def testfunc(n): self.assertNotIn("_COMPARE_OP_INT", uops) self.assertNotIn("_GUARD_IS_TRUE_POP", uops) +def test_call_len(self): +def testfunc(n): +a = [1, 2, 3, 4] +for _ in range(n): +_ = len(a) - 1 + +_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) +uops = get_opnames(ex) +self.assertNotIn("_GUARD_NOS_INT", uops) +self.assertNotIn("_GUARD_TOS_INT", uops) +self.assertIn("_CALL_LEN", uops) + def global_identity(x): return x diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-25-14-56-45.gh-issue-131798.NpcKub.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-25-14-56-45.gh-issue-131798.NpcKub.rst new file mode 100644 index 00..8214870284ed93 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-25-14-56-45.gh-issue-131798.NpcKub.rst @@ -0,0 +1 @@ +Allow the JIT to remove int guards after ``_CALL_LEN`` by setting the return type to int. Patch by Diego Russo diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index ff2830d3003c61..040e54479b722a 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1055,6 +1055,10 @@ dummy_func(void) { sym_set_const(callable, (PyObject *)&PyUnicode_Type); } +op(_CALL_LEN, (callable[1], self_or_null[1], args[oparg] -- res)) { +res = sym_new_type(ctx, &PyLong_Type); +} + // END BYTECODES // } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 303e402b759530..9a5a362ec199a9 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2014,7 +2014,7 @@ case _CALL_LEN: { JitOptSymbol *res; -res = sym_new_not_null(ctx); +res = sym_new_type(ctx, &PyLong_Type); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; assert(WITHIN_STACK_BOUNDS()); ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] update comment about LLVM bug relevant for `--with-tail-call-interp` performance (#132297)
https://github.com/python/cpython/commit/67ded6a4faae29edff8e4f7886978e71ce116e33 commit: 67ded6a4faae29edff8e4f7886978e71ce116e33 branch: main author: h-vetinari committer: Fidget-Spinner date: 2025-04-09T22:50:38+08:00 summary: update comment about LLVM bug relevant for `--with-tail-call-interp` performance (#132297) files: M Doc/whatsnew/3.14.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 5f84d8ba8b02c2..0f15a2a8a8f6af 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -390,8 +390,9 @@ For further information on how to build Python, see `compiler bug <https://github.com/llvm/llvm-project/issues/106846>`_ found in Clang/LLVM 19, which causes the normal interpreter to be slower. We were unaware of this bug, resulting in inaccurate results. We sincerely apologize for -communicating results that were only accurate for certain versions of LLVM 19 -and 20. At the time of writing, this bug has not yet been fixed in LLVM 19-21. Thus +communicating results that were only accurate for LLVM v19.1.x and v20.1.0. In the meantime, +the bug has been fixed in LLVM v20.1.1 and for the upcoming v21.1, but it will remain +unfixed for LLVM v19.1.x and v20.1.0. Thus any benchmarks with those versions of LLVM may produce inaccurate numbers. (Thanks to Nelson Elhage for bringing this to light.) ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-131798: JIT: Propagate the result in `_BINARY_OP_SUBSCR_TUPLE_INT` (GH-133003)
https://github.com/python/cpython/commit/5e96e4fca80a8cd25da6b469b25f8f5a514de8be commit: 5e96e4fca80a8cd25da6b469b25f8f5a514de8be branch: main author: Tomas R. committer: Fidget-Spinner date: 2025-04-27T02:47:55+08:00 summary: gh-131798: JIT: Propagate the result in `_BINARY_OP_SUBSCR_TUPLE_INT` (GH-133003) files: A Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-13-57-13.gh-issue-131798.Gt8CGE.rst M Lib/test/test_capi/test_opt.py M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 0047306ae422db..7e0c60d5522402 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1923,6 +1923,23 @@ def testfunc(n): self.assertNotIn("_GUARD_TOS_INT", uops) self.assertIn("_CALL_LEN", uops) +def test_binary_op_subscr_tuple_int(self): +def testfunc(n): +x = 0 +for _ in range(n): +y = (1, 2) +if y[0] == 1: # _COMPARE_OP_INT + _GUARD_IS_TRUE_POP are removed +x += 1 +return x + +res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) +self.assertEqual(res, TIER2_THRESHOLD) +self.assertIsNotNone(ex) +uops = get_opnames(ex) +self.assertIn("_BINARY_OP_SUBSCR_TUPLE_INT", uops) +self.assertNotIn("_COMPARE_OP_INT", uops) +self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + def global_identity(x): return x diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-13-57-13.gh-issue-131798.Gt8CGE.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-13-57-13.gh-issue-131798.Gt8CGE.rst new file mode 100644 index 00..f4049240f7d15c --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-13-57-13.gh-issue-131798.Gt8CGE.rst @@ -0,0 +1,2 @@ +Propagate the return type of ``_BINARY_OP_SUBSCR_TUPLE_INT`` in JIT. Patch +by Tomas Roun diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 040e54479b722a..f862c9c8c6a840 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -370,6 +370,27 @@ dummy_func(void) { res = sym_new_type(ctx, &PyUnicode_Type); } +op(_BINARY_OP_SUBSCR_TUPLE_INT, (tuple_st, sub_st -- res)) { +assert(sym_matches_type(tuple_st, &PyTuple_Type)); +if (sym_is_const(ctx, sub_st)) { +assert(PyLong_CheckExact(sym_get_const(ctx, sub_st))); +long index = PyLong_AsLong(sym_get_const(ctx, sub_st)); +assert(index >= 0); +int tuple_length = sym_tuple_length(tuple_st); +if (tuple_length == -1) { +// Unknown length +res = sym_new_not_null(ctx); +} +else { +assert(index < tuple_length); +res = sym_tuple_getitem(ctx, tuple_st, index); +} +} +else { +res = sym_new_not_null(ctx); +} +} + op(_TO_BOOL, (value -- res)) { int already_bool = optimize_to_bool(this_instr, ctx, value, &res); if (!already_bool) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 9a5a362ec199a9..c92b036eb56463 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -617,8 +617,28 @@ } case _BINARY_OP_SUBSCR_TUPLE_INT: { +JitOptSymbol *sub_st; +JitOptSymbol *tuple_st; JitOptSymbol *res; -res = sym_new_not_null(ctx); +sub_st = stack_pointer[-1]; +tuple_st = stack_pointer[-2]; +assert(sym_matches_type(tuple_st, &PyTuple_Type)); +if (sym_is_const(ctx, sub_st)) { +assert(PyLong_CheckExact(sym_get_const(ctx, sub_st))); +long index = PyLong_AsLong(sym_get_const(ctx, sub_st)); +assert(index >= 0); +int tuple_length = sym_tuple_length(tuple_st); +if (tuple_length == -1) { +res = sym_new_not_null(ctx); +} +else { +assert(index < tuple_length); +res = sym_tuple_getitem(ctx, tuple_st, index); +} +} +else { +res = sym_new_not_null(ctx); +} stack_pointer[-2] = res; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com
[Python-checkins] gh-129989: Change Py_TAIL_CALL_INTERP ifndef to ! (#130269)
https://github.com/python/cpython/commit/46ac85e4d9fcffe1a8f921989414a89648b5501a commit: 46ac85e4d9fcffe1a8f921989414a89648b5501a branch: main author: Ken Jin committer: Fidget-Spinner date: 2025-02-18T15:48:49Z summary: gh-129989: Change Py_TAIL_CALL_INTERP ifndef to ! (#130269) Change Py_TAIL_CALL_INTERP ifndef to ! files: M Python/bytecodes.c M Python/ceval.c M Python/generated_cases.c.h M Tools/cases_generator/tier1_generator.py diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3f8f711c55956f..1c5fdf847b62c2 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1358,7 +1358,7 @@ dummy_func( tier1 inst(CLEANUP_THROW, (sub_iter, last_sent_val, exc_value_st -- none, value)) { PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); -#ifndef Py_TAIL_CALL_INTERP +#if !Py_TAIL_CALL_INTERP assert(throwflag); #endif assert(exc_value && PyExceptionInstance_Check(exc_value)); diff --git a/Python/ceval.c b/Python/ceval.c index 28b26ffb5de43d..cf9a8713ed9803 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -798,7 +798,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #ifdef Py_STATS int lastopcode = 0; #endif -#ifndef Py_TAIL_CALL_INTERP +#if !Py_TAIL_CALL_INTERP uint8_t opcode;/* Current opcode */ int oparg; /* Current opcode argument, if any */ assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e7f8fdce41b58a..01fa857b96ac3b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,7 @@ #endif #define TIER_ONE 1 -#ifndef Py_TAIL_CALL_INTERP +#if !Py_TAIL_CALL_INTERP #if !USE_COMPUTED_GOTOS dispatch_opcode: switch (opcode) @@ -4409,7 +4409,7 @@ last_sent_val = stack_pointer[-2]; sub_iter = stack_pointer[-3]; PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); -#ifndef Py_TAIL_CALL_INTERP +#if !Py_TAIL_CALL_INTERP assert(throwflag); #endif assert(exc_value && PyExceptionInstance_Check(exc_value)); @@ -11929,7 +11929,7 @@ } /* END INSTRUCTIONS */ -#ifndef Py_TAIL_CALL_INTERP +#if !Py_TAIL_CALL_INTERP #if USE_COMPUTED_GOTOS _unknown_opcode: #else diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py index dd9faa3587e32b..83ac8b92ee 100644 --- a/Tools/cases_generator/tier1_generator.py +++ b/Tools/cases_generator/tier1_generator.py @@ -160,7 +160,7 @@ def generate_tier1( #define TIER_ONE 1 """) outfile.write(f""" -#ifndef Py_TAIL_CALL_INTERP +#if !Py_TAIL_CALL_INTERP #if !USE_COMPUTED_GOTOS dispatch_opcode: switch (opcode) @@ -173,7 +173,7 @@ def generate_tier1( generate_tier1_cases(analysis, outfile, lines) outfile.write(f""" {INSTRUCTION_END_MARKER} -#ifndef Py_TAIL_CALL_INTERP +#if !Py_TAIL_CALL_INTERP #if USE_COMPUTED_GOTOS _unknown_opcode: #else ___ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com