Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(377)

Side by Side Diff: Objects/typeobject.c

Issue 22986: Improved handling of __class__ assignment
Patch Set: Created 5 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Lib/test/test_module.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* Type object implementation */ 1 /* Type object implementation */
2 2
3 #include "Python.h" 3 #include "Python.h"
4 #include "frameobject.h" 4 #include "frameobject.h"
5 #include "structmember.h" 5 #include "structmember.h"
6 6
7 #include <ctype.h> 7 #include <ctype.h>
8 8
9 9
10 /* Support type attribute cache */ 10 /* Support type attribute cache */
(...skipping 1178 matching lines...) Expand 10 before | Expand all | Expand 10 after
1189 type = Py_TYPE(self); 1189 type = Py_TYPE(self);
1190 1190
1191 /* Call the base tp_dealloc(); first retrack self if 1191 /* Call the base tp_dealloc(); first retrack self if
1192 * basedealloc knows about gc. 1192 * basedealloc knows about gc.
1193 */ 1193 */
1194 if (PyType_IS_GC(base)) 1194 if (PyType_IS_GC(base))
1195 _PyObject_GC_TRACK(self); 1195 _PyObject_GC_TRACK(self);
1196 assert(basedealloc); 1196 assert(basedealloc);
1197 basedealloc(self); 1197 basedealloc(self);
1198 1198
1199 /* Can't reference self beyond this point */ 1199 /* Can't reference self beyond this point. It's possible tp_del switched
1200 Py_DECREF(type); 1200 our type from a HEAPTYPE to a non-HEAPTYPE, so be careful about
1201 reference counting. */
1202 if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
1203 Py_DECREF(type);
1201 1204
1202 endlabel: 1205 endlabel:
1203 ++_PyTrash_delete_nesting; 1206 ++_PyTrash_delete_nesting;
1204 ++ tstate->trash_delete_nesting; 1207 ++ tstate->trash_delete_nesting;
1205 Py_TRASHCAN_SAFE_END(self); 1208 Py_TRASHCAN_SAFE_END(self);
1206 --_PyTrash_delete_nesting; 1209 --_PyTrash_delete_nesting;
1207 -- tstate->trash_delete_nesting; 1210 -- tstate->trash_delete_nesting;
1208 1211
1209 /* Explanation of the weirdness around the trashcan macros: 1212 /* Explanation of the weirdness around the trashcan macros:
1210 1213
(...skipping 2202 matching lines...) Expand 10 before | Expand all | Expand 10 after
3413 } 3416 }
3414 3417
3415 static PyObject * 3418 static PyObject *
3416 object_get_class(PyObject *self, void *closure) 3419 object_get_class(PyObject *self, void *closure)
3417 { 3420 {
3418 Py_INCREF(Py_TYPE(self)); 3421 Py_INCREF(Py_TYPE(self));
3419 return (PyObject *)(Py_TYPE(self)); 3422 return (PyObject *)(Py_TYPE(self));
3420 } 3423 }
3421 3424
3422 static int 3425 static int
3423 equiv_structs(PyTypeObject *a, PyTypeObject *b) 3426 compatible_with_tp_base(PyTypeObject *child)
3424 { 3427 {
3425 return a == b || 3428 PyTypeObject *parent = child->tp_base;
3426 (a != NULL && 3429 return (parent != NULL &&
3427 b != NULL && 3430 child->tp_basicsize == parent->tp_basicsize &&
3428 a->tp_basicsize == b->tp_basicsize && 3431 child->tp_itemsize == parent->tp_itemsize &&
3429 a->tp_itemsize == b->tp_itemsize && 3432 child->tp_dictoffset == parent->tp_dictoffset &&
3430 a->tp_dictoffset == b->tp_dictoffset && 3433 child->tp_weaklistoffset == parent->tp_weaklistoffset &&
3431 a->tp_weaklistoffset == b->tp_weaklistoffset && 3434 ((child->tp_flags & Py_TPFLAGS_HAVE_GC) ==
3432 ((a->tp_flags & Py_TPFLAGS_HAVE_GC) == 3435 (parent->tp_flags & Py_TPFLAGS_HAVE_GC)) &&
3433 (b->tp_flags & Py_TPFLAGS_HAVE_GC))); 3436 (child->tp_dealloc == subtype_dealloc ||
3437 child->tp_dealloc == parent->tp_dealloc));
3434 } 3438 }
3435 3439
3436 static int 3440 static int
3437 same_slots_added(PyTypeObject *a, PyTypeObject *b) 3441 same_slots_added(PyTypeObject *a, PyTypeObject *b)
3438 { 3442 {
3439 PyTypeObject *base = a->tp_base; 3443 PyTypeObject *base = a->tp_base;
3440 Py_ssize_t size; 3444 Py_ssize_t size;
3441 PyObject *slots_a, *slots_b; 3445 PyObject *slots_a, *slots_b;
3442 3446
3443 assert(base == b->tp_base); 3447 assert(base == b->tp_base);
3444 size = base->tp_basicsize; 3448 size = base->tp_basicsize;
3445 if (a->tp_dictoffset == size && b->tp_dictoffset == size) 3449 if (a->tp_dictoffset == size && b->tp_dictoffset == size)
3446 size += sizeof(PyObject *); 3450 size += sizeof(PyObject *);
3447 if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size) 3451 if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size)
3448 size += sizeof(PyObject *); 3452 size += sizeof(PyObject *);
3449 3453
3450 /* Check slots compliance */ 3454 /* Check slots compliance */
3455 if (!(a->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
3456 !(b->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
3457 return 0;
3458 }
3451 slots_a = ((PyHeapTypeObject *)a)->ht_slots; 3459 slots_a = ((PyHeapTypeObject *)a)->ht_slots;
3452 slots_b = ((PyHeapTypeObject *)b)->ht_slots; 3460 slots_b = ((PyHeapTypeObject *)b)->ht_slots;
3453 if (slots_a && slots_b) { 3461 if (slots_a && slots_b) {
3454 if (PyObject_RichCompareBool(slots_a, slots_b, Py_EQ) != 1) 3462 if (PyObject_RichCompareBool(slots_a, slots_b, Py_EQ) != 1)
3455 return 0; 3463 return 0;
3456 size += sizeof(PyObject *) * PyTuple_GET_SIZE(slots_a); 3464 size += sizeof(PyObject *) * PyTuple_GET_SIZE(slots_a);
3457 } 3465 }
3458 return size == a->tp_basicsize && size == b->tp_basicsize; 3466 return size == a->tp_basicsize && size == b->tp_basicsize;
3459 } 3467 }
3460 3468
3461 static int 3469 static int
3462 compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, char* attr) 3470 compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, char* attr)
3463 { 3471 {
3464 PyTypeObject *newbase, *oldbase; 3472 PyTypeObject *newbase, *oldbase;
3465 3473
3466 if (newto->tp_dealloc != oldto->tp_dealloc || 3474 if (newto->tp_free != oldto->tp_free)
3467 newto->tp_free != oldto->tp_free)
3468 { 3475 {
3469 PyErr_Format(PyExc_TypeError, 3476 PyErr_Format(PyExc_TypeError,
3470 "%s assignment: " 3477 "%s assignment: "
3471 "'%s' deallocator differs from '%s'", 3478 "'%s' deallocator differs from '%s'",
3472 attr, 3479 attr,
3473 newto->tp_name, 3480 newto->tp_name,
3474 oldto->tp_name); 3481 oldto->tp_name);
3475 return 0; 3482 return 0;
3476 } 3483 }
3484 /* It's tricky to tell if two arbitrary types are sufficiently compatible
3485 as to be interchangeable; e.g., even if they have the same
3486 tp_basicsize, they might have totally different struct fields. It's
3487 much easier to tell if a type and its supertype are compatible; e.g.,
3488 if they have the same tp_basicsize, then that means they have identical
3489 fields. So to check whether two arbitrary types are compatible, we
3490 first find the highest supertype that each is compatible with, and then
3491 if those supertypes are compatible then the original types must also be
3492 compatible.
3493 */
3477 newbase = newto; 3494 newbase = newto;
3478 oldbase = oldto; 3495 oldbase = oldto;
3479 while (equiv_structs(newbase, newbase->tp_base)) 3496 while (compatible_with_tp_base(newbase))
3480 newbase = newbase->tp_base; 3497 newbase = newbase->tp_base;
3481 while (equiv_structs(oldbase, oldbase->tp_base)) 3498 while (compatible_with_tp_base(oldbase))
3482 oldbase = oldbase->tp_base; 3499 oldbase = oldbase->tp_base;
3483 if (newbase != oldbase && 3500 if (newbase != oldbase &&
3484 (newbase->tp_base != oldbase->tp_base || 3501 (newbase->tp_base != oldbase->tp_base ||
3485 !same_slots_added(newbase, oldbase))) { 3502 !same_slots_added(newbase, oldbase))) {
3486 PyErr_Format(PyExc_TypeError, 3503 PyErr_Format(PyExc_TypeError,
3487 "%s assignment: " 3504 "%s assignment: "
3488 "'%s' object layout differs from '%s'", 3505 "'%s' object layout differs from '%s'",
3489 attr, 3506 attr,
3490 newto->tp_name, 3507 newto->tp_name,
3491 oldto->tp_name); 3508 oldto->tp_name);
(...skipping 14 matching lines...) Expand all
3506 "can't delete __class__ attribute"); 3523 "can't delete __class__ attribute");
3507 return -1; 3524 return -1;
3508 } 3525 }
3509 if (!PyType_Check(value)) { 3526 if (!PyType_Check(value)) {
3510 PyErr_Format(PyExc_TypeError, 3527 PyErr_Format(PyExc_TypeError,
3511 "__class__ must be set to a class, not '%s' object", 3528 "__class__ must be set to a class, not '%s' object",
3512 Py_TYPE(value)->tp_name); 3529 Py_TYPE(value)->tp_name);
3513 return -1; 3530 return -1;
3514 } 3531 }
3515 newto = (PyTypeObject *)value; 3532 newto = (PyTypeObject *)value;
3516 if (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
3517 !(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE))
3518 {
3519 PyErr_Format(PyExc_TypeError,
3520 "__class__ assignment: only for heap types");
3521 return -1;
3522 }
3523 if (compatible_for_assignment(oldto, newto, "__class__")) { 3533 if (compatible_for_assignment(oldto, newto, "__class__")) {
3524 Py_INCREF(newto); 3534 if (newto->tp_flags & Py_TPFLAGS_HEAPTYPE)
3535 Py_INCREF(newto);
3525 Py_TYPE(self) = newto; 3536 Py_TYPE(self) = newto;
3526 Py_DECREF(oldto); 3537 if (oldto->tp_flags & Py_TPFLAGS_HEAPTYPE)
3538 Py_DECREF(oldto);
3527 return 0; 3539 return 0;
3528 } 3540 }
3529 else { 3541 else {
3530 return -1; 3542 return -1;
3531 } 3543 }
3532 } 3544 }
3533 3545
3534 static PyGetSetDef object_getsets[] = { 3546 static PyGetSetDef object_getsets[] = {
3535 {"__class__", object_get_class, object_set_class, 3547 {"__class__", object_get_class, object_set_class,
3536 PyDoc_STR("the object's class")}, 3548 PyDoc_STR("the object's class")},
(...skipping 3595 matching lines...) Expand 10 before | Expand all | Expand 10 after
7132 0, /* tp_base */ 7144 0, /* tp_base */
7133 0, /* tp_dict */ 7145 0, /* tp_dict */
7134 super_descr_get, /* tp_descr_get */ 7146 super_descr_get, /* tp_descr_get */
7135 0, /* tp_descr_set */ 7147 0, /* tp_descr_set */
7136 0, /* tp_dictoffset */ 7148 0, /* tp_dictoffset */
7137 super_init, /* tp_init */ 7149 super_init, /* tp_init */
7138 PyType_GenericAlloc, /* tp_alloc */ 7150 PyType_GenericAlloc, /* tp_alloc */
7139 PyType_GenericNew, /* tp_new */ 7151 PyType_GenericNew, /* tp_new */
7140 PyObject_GC_Del, /* tp_free */ 7152 PyObject_GC_Del, /* tp_free */
7141 }; 7153 };
OLDNEW
« no previous file with comments | « Lib/test/test_module.py ('k') | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+