Repository navigation
GH-95245: Move weakreflist into the pre-header. #95657
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Reduces the size of a "simple" Python object from 8 to 6 words by moving the | ||
| weakreflist pointer into the pre-header directly before the object's | ||
| dict/values pointer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2483,8 +2483,9 @@ subtype_getweakref(PyObject *obj, void *context) | |
| return NULL; | ||
| } | ||
| _PyObject_ASSERT((PyObject *)type, | ||
| type->tp_weaklistoffset > 0); | ||
| type->tp_weaklistoffset != 0); | ||
| _PyObject_ASSERT((PyObject *)type, | ||
| (type->tp_weaklistoffset == -4 * ((int)sizeof(PyObject *))) || | ||
| ((type->tp_weaklistoffset + sizeof(PyObject *)) | ||
| <= (size_t)(type->tp_basicsize))); | ||
| weaklistptr = (PyObject **)((char *)obj + type->tp_weaklistoffset); | ||
|
|
@@ -3078,19 +3079,28 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type) | |
| } | ||
| } | ||
|
|
||
| if (ctx->add_dict && ctx->base->tp_itemsize) { | ||
| type->tp_dictoffset = -(long)sizeof(PyObject *); | ||
| slotoffset += sizeof(PyObject *); | ||
| if (ctx->add_dict) { | ||
| if (ctx->base->tp_itemsize) { | ||
| type->tp_dictoffset = -(long)sizeof(PyObject *); | ||
| slotoffset += sizeof(PyObject *); | ||
| } | ||
| else { | ||
| assert((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0); | ||
| type->tp_flags |= Py_TPFLAGS_MANAGED_DICT; | ||
| } | ||
| } | ||
|
|
||
| if (ctx->add_weak) { | ||
| assert(!ctx->base->tp_itemsize); | ||
| type->tp_weaklistoffset = slotoffset; | ||
| slotoffset += sizeof(PyObject *); | ||
| if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) { | ||
|
Member
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. Could If so, that implies that Otherwise the assert on line 3088 should probably move up to before line 3082.
Member
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. Further, if it's always either both-are-managed or neither then it would be helpful if the flag were more clear (e.g. If either can be managed separately then there should probably be a separate That might be necessary anyway since
Member
Author
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. We want both to be managed, or neither, but our hand might be forced in the case of multiple inheritance. Currently When we make it public, as we should do for 3.12, then it would make sense to add I'd like some sort of decision on #95589 first, though.
Member
Author
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. Thinking about this a bit more, we can ensure both are explicit or both managed. Moving from an explicitly declare offset to a managed one is unsafe, so we can't do that.
Member
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. Here it only matters in the context of
Member
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. Regardless, my original question stands: could |
||
| type->tp_weaklistoffset = -4 * sizeof(PyObject *); | ||
|
Member
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 the pre-header layout documented, either in a comment, the docs, or an adjacent .txt file? Either way, I don't see the weaklist's place in the pre-header added to such documentation in this PR. That information would be super helpful, since I can only guess what
Member
Author
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. Documenting the object layout is on the to-do list.
Member
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. What? No SVG? |
||
| } | ||
| else { | ||
| type->tp_weaklistoffset = slotoffset; | ||
| slotoffset += sizeof(PyObject *); | ||
| } | ||
|
ericsnowcurrently marked this conversation as resolved.
|
||
| } | ||
| if (ctx->add_dict && ctx->base->tp_itemsize == 0) { | ||
| assert((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0); | ||
| type->tp_flags |= Py_TPFLAGS_MANAGED_DICT; | ||
| if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) { | ||
|
Comment on lines
-3092
to
+3103
Member
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. Likewise about |
||
| type->tp_dictoffset = -slotoffset - sizeof(PyObject *)*3; | ||
| } | ||
|
|
||
|
|
@@ -5070,11 +5080,13 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* | |
| !same_slots_added(newbase, oldbase))) { | ||
| goto differs; | ||
| } | ||
| /* The above does not check for managed __dicts__ */ | ||
| /* The above does not check for managed __dict__ or __weakref__ */ | ||
| if ((oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT) == | ||
| ((newto->tp_flags & Py_TPFLAGS_MANAGED_DICT))) | ||
| { | ||
| return 1; | ||
| if (oldto->tp_weaklistoffset == newto->tp_weaklistoffset) { | ||
| return 1; | ||
| } | ||
| } | ||
| differs: | ||
| PyErr_Format(PyExc_TypeError, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.