Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
gh-127119: Faster check for small ints in long_dealloc#127620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
cfb70cb426dd094639642d9c26d32f73d473b6e1fe03184a75eca812fedc102c733d25829a59539da0ea5058e538a3d00f878207a068a16aa65ec5a38fe25f32b6e448543c78e232ca4f1ce75399a2fc7f6a76b098948667834406d91b6e3ebc7e17aaf110b8fcc1d0aff8812ebb0bca8d8e7944a07ba11d5b2e0cfb9120b606c09b4c8444f76c0e2File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Slightly optimize the :class:`int` deallocator. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,8 @@ | ||
| #include "parts.h" | ||
| #define Py_BUILD_CORE | ||
| #include "internal/pycore_long.h" // IMMORTALITY_BIT_MASK | ||
| int verify_immortality(PyObject *object) | ||
| { | ||
| assert(_Py_IsImmortal(object)); | ||
| @@ -26,7 +29,17 @@ static PyObject * | ||
| test_immortal_small_ints(PyObject *self, PyObject *Py_UNUSED(ignored)) | ||
| { | ||
| for (int i = -5; i <= 256; i++) { | ||
| assert(verify_immortality(PyLong_FromLong(i))); | ||
| PyObject *obj = PyLong_FromLong(i); | ||
| assert(verify_immortality(obj)); | ||
| int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK; | ||
| assert(has_int_immortal_bit); | ||
| } | ||
| for (int i = 257; i <= 260; i++) { | ||
| PyObject *obj = PyLong_FromLong(i); | ||
eendebakpt marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| assert(obj); | ||
| int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK; | ||
| assert(!has_int_immortal_bit); | ||
eendebakpt marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. eendebakpt marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| Py_DECREF(obj); | ||
| } | ||
| Py_RETURN_NONE; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -3616,32 +3616,25 @@ long_richcompare(PyObject *self, PyObject *other, int op) | ||
| } | ||
| static inline int | ||
| compact_int_is_small(PyObject *self) | ||
| /// Return 1 if the object is one of the immortal small ints | ||
| _long_is_small_int(PyObject *op) | ||
markshannon marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| { | ||
| PyLongObject *pylong = (PyLongObject *)self; | ||
| assert(_PyLong_IsCompact(pylong)); | ||
| stwodigits ival = medium_value(pylong); | ||
| if (IS_SMALL_INT(ival)) { | ||
| PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival); | ||
| if (pylong == small_pylong) { | ||
| return 1; | ||
| } | ||
| } | ||
| return 0; | ||
| PyLongObject *long_object = (PyLongObject *)op; | ||
| int is_small_int = (long_object->long_value.lv_tag & IMMORTALITY_BIT_MASK) != 0; | ||
| assert((!is_small_int) || PyLong_CheckExact(op)); | ||
| return is_small_int; | ||
| } | ||
| void | ||
| _PyLong_ExactDealloc(PyObject *self) | ||
| { | ||
| assert(PyLong_CheckExact(self)); | ||
| if (_long_is_small_int(self)) { | ||
| // See PEP 683, section Accidental De-Immortalizing for details | ||
| _Py_SetImmortal(self); | ||
| return; | ||
| } | ||
| if (_PyLong_IsCompact((PyLongObject *)self)) { | ||
| #ifndef Py_GIL_DISABLED | ||
| if (compact_int_is_small(self)) { | ||
| // See PEP 683, section Accidental De-Immortalizing for details | ||
| _Py_SetImmortal(self); | ||
| return; | ||
| } | ||
| #endif | ||
| _Py_FREELIST_FREE(ints, self, PyObject_Free); | ||
| return; | ||
| } | ||
| @@ -3651,24 +3644,20 @@ _PyLong_ExactDealloc(PyObject *self) | ||
| static void | ||
| long_dealloc(PyObject *self) | ||
| { | ||
| assert(self); | ||
| if (_PyLong_IsCompact((PyLongObject *)self)) { | ||
| if (compact_int_is_small(self)) { | ||
| /* This should never get called, but we also don't want to SEGV if | ||
| * we accidentally decref small Ints out of existence. Instead, | ||
| * since small Ints are immortal, re-set the reference count. | ||
| * | ||
| * See PEP 683, section Accidental De-Immortalizing for details | ||
| */ | ||
| _Py_SetImmortal(self); | ||
| return; | ||
| } | ||
| if (PyLong_CheckExact(self)) { | ||
| _Py_FREELIST_FREE(ints, self, PyObject_Free); | ||
| return; | ||
| } | ||
| if (_long_is_small_int(self)) { | ||
| /* This should never get called, but we also don't want to SEGV if | ||
| * we accidentally decref small Ints out of existence. Instead, | ||
| * since small Ints are immortal, re-set the reference count. | ||
| * | ||
| * See PEP 683, section Accidental De-Immortalizing for details | ||
| */ | ||
| _Py_SetImmortal(self); | ||
| return; | ||
| } | ||
| if (PyLong_CheckExact(self) && _PyLong_IsCompact((PyLongObject *)self)) { | ||
| _Py_FREELIST_FREE(ints, self, PyObject_Free); | ||
| return; | ||
| } | ||
| Py_TYPE(self)->tp_free(self); | ||
| } | ||
| @@ -6030,7 +6019,7 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) | ||
| return NULL; | ||
| } | ||
| assert(PyLong_Check(newobj)); | ||
| newobj->long_value.lv_tag = tmp->long_value.lv_tag; | ||
| newobj->long_value.lv_tag = tmp->long_value.lv_tag & ~IMMORTALITY_BIT_MASK; | ||
| for (i = 0; i < n; i++) { | ||
| newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i]; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe include the benchmarks results (it's a 4% improvement which is still noticable IMO). You should mention that it only concerns PGO builds as well.