Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32.3k
GH-115776: Embed the values array into the object, for "normal" Python objects.#116115
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 ourterms of service andprivacy 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 fromall commits
d5085db
0d88de4
d922903
c03e6cb
621ea3b
67daab5
34c7171
c237e79
f80befa
a0c11e4
bc1ebc8
0dc68a4
084519c
3744f32
75ee5a0
162764c
82ece1b
6a762ed
9dbc8dd
4a1f7b7
09121f9
c384b05
ee5cf2a
005b42b
48d849e
682217c
0ff1709
895a944
1b4302a
ecd4204
c05d01d
d441d7b
3395bc2
ccceffb
7700177
File 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 |
---|---|---|
@@ -11,7 +11,7 @@ extern "C" { | ||
#include "pycore_freelist.h" // _PyFreeListState | ||
#include "pycore_identifier.h" // _Py_Identifier | ||
#include "pycore_object.h" //PyManagedDictPointer | ||
// Unsafe flavor of PyDict_GetItemWithError(): no error checking | ||
extern PyObject* _PyDict_GetItemWithError(PyObject *dp, PyObject *key); | ||
@@ -181,6 +181,10 @@ struct _dictkeysobject { | ||
* [-1] = prefix size. [-2] = used size. size[-2-n...] = insertion order. | ||
*/ | ||
struct _dictvalues { | ||
uint8_t capacity; | ||
uint8_t size; | ||
uint8_t embedded; | ||
uint8_t valid; | ||
PyObject *values[1]; | ||
}; | ||
@@ -196,6 +200,7 @@ static inline void* _DK_ENTRIES(PyDictKeysObject *dk) { | ||
size_t index = (size_t)1 << dk->dk_log2_index_bytes; | ||
return (&indices[index]); | ||
} | ||
static inline PyDictKeyEntry* DK_ENTRIES(PyDictKeysObject *dk) { | ||
assert(dk->dk_kind == DICT_KEYS_GENERAL); | ||
return (PyDictKeyEntry*)_DK_ENTRIES(dk); | ||
@@ -211,9 +216,6 @@ static inline PyDictUnicodeEntry* DK_UNICODE_ENTRIES(PyDictKeysObject *dk) { | ||
#define DICT_WATCHER_MASK ((1 << DICT_MAX_WATCHERS) - 1) | ||
#define DICT_WATCHER_AND_MODIFICATION_MASK ((1 << (DICT_MAX_WATCHERS + DICT_WATCHED_MUTATION_BITS)) - 1) | ||
#ifdef Py_GIL_DISABLED | ||
#define DICT_NEXT_VERSION(INTERP) \ | ||
(_Py_atomic_add_uint64(&(INTERP)->dict_state.global_version, DICT_VERSION_INCREMENT) + DICT_VERSION_INCREMENT) | ||
@@ -246,25 +248,63 @@ _PyDict_NotifyEvent(PyInterpreterState *interp, | ||
return DICT_NEXT_VERSION(interp) | (mp->ma_version_tag & DICT_WATCHER_AND_MODIFICATION_MASK); | ||
} | ||
externPyDictObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj); | ||
PyAPI_FUNC(PyObject *)_PyDict_FromItems( | ||
PyObject *const *keys, Py_ssize_t keys_offset, | ||
PyObject *const *values, Py_ssize_t values_offset, | ||
Py_ssize_t length); | ||
static inline uint8_t * | ||
get_insertion_order_array(PyDictValues *values) | ||
{ | ||
return (uint8_t *)&values->values[values->capacity]; | ||
} | ||
static inline void | ||
_PyDictValues_AddToInsertionOrder(PyDictValues *values, Py_ssize_t ix) | ||
{ | ||
assert(ix < SHARED_KEYS_MAX_SIZE); | ||
int size = values->size; | ||
uint8_t *array = get_insertion_order_array(values); | ||
assert(size < values->capacity); | ||
assert(((uint8_t)ix) == ix); | ||
array[size] = (uint8_t)ix; | ||
values->size = size+1; | ||
} | ||
static inline size_t | ||
shared_keys_usable_size(PyDictKeysObject *keys) | ||
{ | ||
#ifdef Py_GIL_DISABLED | ||
// dk_usable will decrease for each instance that is created and each | ||
// value that is added. dk_nentries will increase for each value that | ||
// is added. We want to always return the right value or larger. | ||
// We therefore increase dk_nentries first and we decrease dk_usable | ||
// second, and conversely here we read dk_usable first and dk_entries | ||
// second (to avoid the case where we read entries before the increment | ||
// and read usable after the decrement) | ||
return (size_t)(_Py_atomic_load_ssize_acquire(&keys->dk_usable) + | ||
_Py_atomic_load_ssize_acquire(&keys->dk_nentries)); | ||
#else | ||
return (size_t)keys->dk_nentries + (size_t)keys->dk_usable; | ||
#endif | ||
markshannon marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
} | ||
static inline size_t | ||
_PyInlineValuesSize(PyTypeObject *tp) | ||
{ | ||
PyDictKeysObject *keys = ((PyHeapTypeObject*)tp)->ht_cached_keys; | ||
assert(keys != NULL); | ||
size_t size = shared_keys_usable_size(keys); | ||
size_t prefix_size = _Py_SIZE_ROUND_UP(size, sizeof(PyObject *)); | ||
assert(prefix_size < 256); | ||
return prefix_size + (size + 1) * sizeof(PyObject *); | ||
} | ||
int | ||
_PyDict_DetachFromObject(PyDictObject *dict, PyObject *obj); | ||
#ifdef __cplusplus | ||
} | ||
#endif | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -265,9 +265,8 @@ _PyObject_Init(PyObject *op, PyTypeObject *typeobj) | ||
{ | ||
assert(op != NULL); | ||
Py_SET_TYPE(op, typeobj); | ||
assert(_PyType_HasFeature(typeobj, Py_TPFLAGS_HEAPTYPE) || _Py_IsImmortal(typeobj)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I now hit this assertion in Cython modules. The (static) extension type that we use for generators has
Is this assertion simply wrong, or is there anything I can do to avoid it? The "immortal objects" API doesn't seem to be intended for public use. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. #19474 sets the reference count to 1 for statically allocated objects unless As a workaround, I'd suggest making these classes immortal and making them immutable if you can.
That does seem to be the case. I don't know why. Want to open an issue for that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Is there a reason why this new assertion exists? The previous There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. All non-heap types are immortal. Requiring that they are declared as such seems reasonable, and is probably necessary for memory safety. I don't think you should need to do so explicitly though, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Does#117673 fix the problem for you? | ||
Py_INCREF(typeobj); | ||
_Py_NewReference(op); | ||
} | ||
@@ -611,8 +610,7 @@ extern PyTypeObject* _PyType_CalculateMetaclass(PyTypeObject *, PyObject *); | ||
extern PyObject* _PyType_GetDocFromInternalDoc(const char *, const char *); | ||
extern PyObject* _PyType_GetTextSignatureFromInternalDoc(const char *, const char *, int); | ||
void _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp); | ||
extern int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values, | ||
PyObject *name, PyObject *value); | ||
PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values, | ||
@@ -627,46 +625,26 @@ PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values, | ||
#endif | ||
typedef union { | ||
PyDictObject *dict; | ||
DinoV marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
} PyManagedDictPointer; | ||
static inlinePyManagedDictPointer * | ||
_PyObject_ManagedDictPointer(PyObject *obj) | ||
{ | ||
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT); | ||
return (PyManagedDictPointer *)((char *)obj + MANAGED_DICT_OFFSET); | ||
} | ||
static inline PyDictValues * | ||
_PyObject_InlineValues(PyObject *obj) | ||
{ | ||
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES); | ||
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT); | ||
assert(Py_TYPE(obj)->tp_basicsize == sizeof(PyObject)); | ||
return (PyDictValues *)((char *)obj + sizeof(PyObject)); | ||
} | ||
extern PyObject ** _PyObject_ComputedDictPointer(PyObject *); | ||
extern int _PyObject_IsInstanceDictEmpty(PyObject *); | ||
// Export for 'math' shared extension | ||
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.