PageRenderTime 29ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/cpyext/typeobject.py

https://bitbucket.org/timfel/pypy
Python | 995 lines | 775 code | 101 blank | 119 comment | 152 complexity | 40ef356d7d7ad16bf5278520380aea13 MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0, BSD-3-Clause
  1. import os
  2. from rpython.rlib import jit
  3. from rpython.rlib.objectmodel import specialize, we_are_translated
  4. from rpython.rtyper.lltypesystem import rffi, lltype
  5. from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
  6. from pypy.interpreter.error import oefmt
  7. from pypy.interpreter.typedef import (
  8. GetSetProperty, TypeDef, interp_attrproperty, interp2app)
  9. from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
  10. from pypy.module.cpyext import structmemberdefs
  11. from pypy.module.cpyext.api import (
  12. cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
  13. slot_function, generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
  14. Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
  15. Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers,
  16. PyObjectFields, PyTypeObject, PyTypeObjectPtr,
  17. Py_TPFLAGS_HAVE_NEWBUFFER, Py_TPFLAGS_CHECKTYPES,
  18. Py_TPFLAGS_HAVE_INPLACEOPS, cts, parse_dir)
  19. from pypy.module.cpyext.cparser import parse_source
  20. from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
  21. W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction, PyMethodDef,
  22. W_PyCMethodObject, W_PyCFunctionObject)
  23. from pypy.module.cpyext.modsupport import convert_method_defs
  24. from pypy.module.cpyext.pyobject import (
  25. PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
  26. track_reference, Py_DecRef, as_pyobj)
  27. from pypy.module.cpyext.slotdefs import (
  28. slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function,
  29. llslot)
  30. from pypy.module.cpyext.state import State
  31. from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
  32. from pypy.module.cpyext.typeobjectdefs import (
  33. PyGetSetDef, PyMemberDef, PyMappingMethods,
  34. PyNumberMethods, PySequenceMethods, PyBufferProcs)
  35. from pypy.objspace.std.typeobject import W_TypeObject, find_best_base
  36. #WARN_ABOUT_MISSING_SLOT_FUNCTIONS = False
  37. PyType_Check, PyType_CheckExact = build_type_checkers("Type", "w_type")
  38. PyHeapTypeObject = cts.gettype('PyHeapTypeObject *')
  39. class W_GetSetPropertyEx(GetSetProperty):
  40. def __init__(self, getset, w_type):
  41. self.getset = getset
  42. self.name = rffi.charp2str(getset.c_name)
  43. self.w_type = w_type
  44. doc = set = get = None
  45. if doc:
  46. # XXX dead code?
  47. doc = rffi.charp2str(getset.c_doc)
  48. if getset.c_get:
  49. get = GettersAndSetters.getter.im_func
  50. if getset.c_set:
  51. set = GettersAndSetters.setter.im_func
  52. GetSetProperty.__init__(self, get, set, None, doc,
  53. cls=None, use_closure=True,
  54. tag="cpyext_1")
  55. def PyDescr_NewGetSet(space, getset, w_type):
  56. return W_GetSetPropertyEx(getset, w_type)
  57. def make_GetSet(space, getsetprop):
  58. py_getsetdef = lltype.malloc(PyGetSetDef, flavor='raw')
  59. doc = getsetprop.doc
  60. if doc:
  61. py_getsetdef.c_doc = rffi.str2charp(doc)
  62. else:
  63. py_getsetdef.c_doc = rffi.cast(rffi.CCHARP, 0)
  64. py_getsetdef.c_name = rffi.str2charp(getsetprop.getname(space))
  65. # XXX FIXME - actually assign these !!!
  66. py_getsetdef.c_get = cts.cast('getter', 0)
  67. py_getsetdef.c_set = cts.cast('setter', 0)
  68. py_getsetdef.c_closure = cts.cast('void*', 0)
  69. return py_getsetdef
  70. class W_MemberDescr(GetSetProperty):
  71. name = 'member_descriptor'
  72. def __init__(self, member, w_type):
  73. self.member = member
  74. self.name = rffi.charp2str(member.c_name)
  75. self.w_type = w_type
  76. flags = rffi.cast(lltype.Signed, member.c_flags)
  77. doc = set = None
  78. if member.c_doc:
  79. doc = rffi.charp2str(member.c_doc)
  80. get = GettersAndSetters.member_getter.im_func
  81. del_ = GettersAndSetters.member_delete.im_func
  82. if not (flags & structmemberdefs.READONLY):
  83. set = GettersAndSetters.member_setter.im_func
  84. GetSetProperty.__init__(self, get, set, del_, doc,
  85. cls=None, use_closure=True,
  86. tag="cpyext_2")
  87. # change the typedef name
  88. W_MemberDescr.typedef = TypeDef(
  89. "member_descriptor",
  90. __get__ = interp2app(GetSetProperty.descr_property_get),
  91. __set__ = interp2app(GetSetProperty.descr_property_set),
  92. __delete__ = interp2app(GetSetProperty.descr_property_del),
  93. __name__ = interp_attrproperty('name', cls=GetSetProperty,
  94. wrapfn="newtext_or_none"),
  95. __objclass__ = GetSetProperty(GetSetProperty.descr_get_objclass),
  96. __doc__ = interp_attrproperty('doc', cls=GetSetProperty,
  97. wrapfn="newtext_or_none"),
  98. )
  99. assert not W_MemberDescr.typedef.acceptable_as_base_class # no __new__
  100. PyDescrObject = lltype.ForwardReference()
  101. PyDescrObjectPtr = lltype.Ptr(PyDescrObject)
  102. PyDescrObjectFields = PyObjectFields + (
  103. ("d_type", PyTypeObjectPtr),
  104. ("d_name", PyObject),
  105. )
  106. cpython_struct("PyDescrObject", PyDescrObjectFields,
  107. PyDescrObject)
  108. PyMemberDescrObjectStruct = lltype.ForwardReference()
  109. PyMemberDescrObject = lltype.Ptr(PyMemberDescrObjectStruct)
  110. PyMemberDescrObjectFields = PyDescrObjectFields + (
  111. ("d_member", lltype.Ptr(PyMemberDef)),
  112. )
  113. cpython_struct("PyMemberDescrObject", PyMemberDescrObjectFields,
  114. PyMemberDescrObjectStruct, level=2)
  115. PyGetSetDescrObjectStruct = lltype.ForwardReference()
  116. PyGetSetDescrObject = lltype.Ptr(PyGetSetDescrObjectStruct)
  117. PyGetSetDescrObjectFields = PyDescrObjectFields + (
  118. ("d_getset", lltype.Ptr(PyGetSetDef)),
  119. )
  120. cpython_struct("PyGetSetDescrObject", PyGetSetDescrObjectFields,
  121. PyGetSetDescrObjectStruct, level=2)
  122. PyMethodDescrObjectStruct = lltype.ForwardReference()
  123. PyMethodDescrObject = lltype.Ptr(PyMethodDescrObjectStruct)
  124. PyMethodDescrObjectFields = PyDescrObjectFields + (
  125. ("d_method", lltype.Ptr(PyMethodDef)),
  126. )
  127. cpython_struct("PyMethodDescrObject", PyMethodDescrObjectFields,
  128. PyMethodDescrObjectStruct, level=2)
  129. @bootstrap_function
  130. def init_memberdescrobject(space):
  131. make_typedescr(W_MemberDescr.typedef,
  132. basestruct=PyMemberDescrObject.TO,
  133. attach=memberdescr_attach,
  134. realize=memberdescr_realize,
  135. )
  136. make_typedescr(W_GetSetPropertyEx.typedef,
  137. basestruct=PyGetSetDescrObject.TO,
  138. attach=getsetdescr_attach,
  139. )
  140. make_typedescr(W_PyCClassMethodObject.typedef,
  141. basestruct=PyMethodDescrObject.TO,
  142. attach=methoddescr_attach,
  143. realize=classmethoddescr_realize,
  144. )
  145. make_typedescr(W_PyCMethodObject.typedef,
  146. basestruct=PyMethodDescrObject.TO,
  147. attach=methoddescr_attach,
  148. realize=methoddescr_realize,
  149. )
  150. def memberdescr_attach(space, py_obj, w_obj, w_userdata=None):
  151. """
  152. Fills a newly allocated PyMemberDescrObject with the given W_MemberDescr
  153. object. The values must not be modified.
  154. """
  155. py_memberdescr = rffi.cast(PyMemberDescrObject, py_obj)
  156. # XXX assign to d_dname, d_type?
  157. assert isinstance(w_obj, W_MemberDescr)
  158. py_memberdescr.c_d_member = w_obj.member
  159. def memberdescr_realize(space, obj):
  160. # XXX NOT TESTED When is this ever called?
  161. member = cts.cast('PyMemberDef*', obj)
  162. w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
  163. w_obj = space.allocate_instance(W_MemberDescr, w_type)
  164. w_obj.__init__(member, w_type)
  165. track_reference(space, obj, w_obj)
  166. return w_obj
  167. def getsetdescr_attach(space, py_obj, w_obj, w_userdata=None):
  168. """
  169. Fills a newly allocated PyGetSetDescrObject with the given W_GetSetPropertyEx
  170. object. The values must not be modified.
  171. """
  172. py_getsetdescr = rffi.cast(PyGetSetDescrObject, py_obj)
  173. if isinstance(w_obj, GetSetProperty):
  174. py_getsetdef = make_GetSet(space, w_obj)
  175. assert space.isinstance_w(w_userdata, space.w_type)
  176. w_obj = W_GetSetPropertyEx(py_getsetdef, w_userdata)
  177. # XXX assign to d_dname, d_type?
  178. assert isinstance(w_obj, W_GetSetPropertyEx)
  179. py_getsetdescr.c_d_getset = w_obj.getset
  180. def methoddescr_attach(space, py_obj, w_obj, w_userdata=None):
  181. py_methoddescr = rffi.cast(PyMethodDescrObject, py_obj)
  182. # XXX assign to d_dname, d_type?
  183. assert isinstance(w_obj, W_PyCFunctionObject)
  184. py_methoddescr.c_d_method = w_obj.ml
  185. def classmethoddescr_realize(space, obj):
  186. # XXX NOT TESTED When is this ever called?
  187. method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
  188. w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
  189. w_obj = space.allocate_instance(W_PyCClassMethodObject, w_type)
  190. w_obj.__init__(space, method, w_type)
  191. track_reference(space, obj, w_obj)
  192. return w_obj
  193. def methoddescr_realize(space, obj):
  194. # XXX NOT TESTED When is this ever called?
  195. method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
  196. w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
  197. w_obj = space.allocate_instance(W_PyCMethodObject, w_type)
  198. w_obj.__init__(space, method, w_type)
  199. track_reference(space, obj, w_obj)
  200. return w_obj
  201. def convert_getset_defs(space, dict_w, getsets, w_type):
  202. getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets)
  203. if getsets:
  204. i = -1
  205. while True:
  206. i = i + 1
  207. getset = getsets[i]
  208. name = getset.c_name
  209. if not name:
  210. break
  211. name = rffi.charp2str(name)
  212. w_descr = PyDescr_NewGetSet(space, getset, w_type)
  213. dict_w[name] = w_descr
  214. def convert_member_defs(space, dict_w, members, w_type):
  215. members = rffi.cast(rffi.CArrayPtr(PyMemberDef), members)
  216. if members:
  217. i = 0
  218. while True:
  219. member = members[i]
  220. name = member.c_name
  221. if not name:
  222. break
  223. name = rffi.charp2str(name)
  224. w_descr = W_MemberDescr(member, w_type)
  225. dict_w[name] = w_descr
  226. i += 1
  227. missing_slots={}
  228. def update_all_slots(space, w_type, pto):
  229. # fill slots in pto
  230. # Not very sure about it, but according to
  231. # test_call_tp_dealloc, we should not
  232. # overwrite slots that are already set: these ones are probably
  233. # coming from a parent C type.
  234. if w_type.is_heaptype():
  235. typedef = None
  236. search_dict_w = w_type.dict_w
  237. else:
  238. typedef = w_type.layout.typedef
  239. search_dict_w = None
  240. for method_name, slot_name, slot_names, slot_apifunc in slotdefs_for_tp_slots:
  241. slot_func_helper = None
  242. if search_dict_w is None:
  243. # built-in types: expose as many slots as possible, even
  244. # if it happens to come from some parent class
  245. slot_apifunc = None # use get_slot_tp_function
  246. else:
  247. # For heaptypes, w_type.layout.typedef will be object's typedef, and
  248. # get_slot_tp_function will fail
  249. w_descr = search_dict_w.get(method_name, None)
  250. if w_descr:
  251. # use the slot_apifunc (userslots) to lookup at runtime
  252. pass
  253. elif len(slot_names) ==1:
  254. # 'inherit' from tp_base
  255. slot_func_helper = getattr(pto.c_tp_base, slot_names[0])
  256. else:
  257. struct = getattr(pto.c_tp_base, slot_names[0])
  258. if struct:
  259. slot_func_helper = getattr(struct, slot_names[1])
  260. if not slot_func_helper:
  261. if typedef is not None:
  262. if slot_apifunc is None:
  263. slot_apifunc = get_slot_tp_function(space, typedef, slot_name)
  264. if not slot_apifunc:
  265. if not we_are_translated():
  266. if slot_name not in missing_slots:
  267. missing_slots[slot_name] = w_type.getname(space)
  268. print "missing slot %r/%r, discovered on %r" % (
  269. method_name, slot_name, w_type.getname(space))
  270. continue
  271. slot_func_helper = slot_apifunc.get_llhelper(space)
  272. # XXX special case wrapper-functions and use a "specific" slot func
  273. if len(slot_names) == 1:
  274. if not getattr(pto, slot_names[0]):
  275. setattr(pto, slot_names[0], slot_func_helper)
  276. elif ((w_type is space.w_list or w_type is space.w_tuple) and
  277. slot_names[0] == 'c_tp_as_number'):
  278. # XXX hack - hwo can we generalize this? The problem is method
  279. # names like __mul__ map to more than one slot, and we have no
  280. # convenient way to indicate which slots CPython have filled
  281. #
  282. # We need at least this special case since Numpy checks that
  283. # (list, tuple) do __not__ fill tp_as_number
  284. pass
  285. else:
  286. assert len(slot_names) == 2
  287. struct = getattr(pto, slot_names[0])
  288. if not struct:
  289. #assert not space.config.translating
  290. assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
  291. if slot_names[0] == 'c_tp_as_number':
  292. STRUCT_TYPE = PyNumberMethods
  293. elif slot_names[0] == 'c_tp_as_sequence':
  294. STRUCT_TYPE = PySequenceMethods
  295. elif slot_names[0] == 'c_tp_as_buffer':
  296. STRUCT_TYPE = PyBufferProcs
  297. elif slot_names[0] == 'c_tp_as_mapping':
  298. STRUCT_TYPE = PyMappingMethods
  299. else:
  300. raise AssertionError(
  301. "Structure not allocated: %s" % (slot_names[0],))
  302. struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
  303. setattr(pto, slot_names[0], struct)
  304. if not getattr(struct, slot_names[1]):
  305. setattr(struct, slot_names[1], slot_func_helper)
  306. def add_operators(space, dict_w, pto):
  307. # XXX support PyObject_HashNotImplemented
  308. for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
  309. if method_name in dict_w:
  310. continue
  311. offset = [rffi.offsetof(lltype.typeOf(pto).TO, slot_names[0])]
  312. if len(slot_names) == 1:
  313. func = getattr(pto, slot_names[0])
  314. else:
  315. assert len(slot_names) == 2
  316. struct = getattr(pto, slot_names[0])
  317. if not struct:
  318. continue
  319. offset.append(rffi.offsetof(lltype.typeOf(struct).TO, slot_names[1]))
  320. func = getattr(struct, slot_names[1])
  321. func_voidp = rffi.cast(rffi.VOIDP, func)
  322. if not func:
  323. continue
  324. if wrapper_func is None and wrapper_func_kwds is None:
  325. continue
  326. w_obj = W_PyCWrapperObject(space, pto, method_name, wrapper_func,
  327. wrapper_func_kwds, doc, func_voidp, offset=offset)
  328. dict_w[method_name] = w_obj
  329. if pto.c_tp_doc:
  330. dict_w['__doc__'] = space.newtext(
  331. rffi.charp2str(cts.cast('char*', pto.c_tp_doc)))
  332. if pto.c_tp_new:
  333. add_tp_new_wrapper(space, dict_w, pto)
  334. @slot_function([PyObject, PyObject, PyObject], PyObject)
  335. def tp_new_wrapper(space, self, w_args, w_kwds):
  336. self_pytype = rffi.cast(PyTypeObjectPtr, self)
  337. tp_new = self_pytype.c_tp_new
  338. # Check that the user doesn't do something silly and unsafe like
  339. # object.__new__(dict). To do this, we check that the most
  340. # derived base that's not a heap type is this type.
  341. # XXX do it
  342. args_w = space.fixedview(w_args)
  343. w_subtype = args_w[0]
  344. w_args = space.newtuple(args_w[1:])
  345. if not space.is_true(w_kwds):
  346. w_kwds = None
  347. try:
  348. subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
  349. w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
  350. finally:
  351. Py_DecRef(space, w_subtype)
  352. return w_obj
  353. @specialize.memo()
  354. def get_new_method_def(space):
  355. state = space.fromcache(State)
  356. if state.new_method_def:
  357. return state.new_method_def
  358. ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
  359. immortal=True)
  360. ptr.c_ml_name = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp("__new__"))
  361. lltype.render_immortal(ptr.c_ml_name)
  362. rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
  363. ptr.c_ml_doc = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp(
  364. "T.__new__(S, ...) -> a new object with type S, a subtype of T"))
  365. lltype.render_immortal(ptr.c_ml_doc)
  366. state.new_method_def = ptr
  367. return ptr
  368. def setup_new_method_def(space):
  369. ptr = get_new_method_def(space)
  370. ptr.c_ml_meth = rffi.cast(PyCFunction, llslot(space, tp_new_wrapper))
  371. def add_tp_new_wrapper(space, dict_w, pto):
  372. if "__new__" in dict_w:
  373. return
  374. pyo = rffi.cast(PyObject, pto)
  375. dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
  376. from_ref(space, pyo), None)
  377. def inherit_special(space, pto, base_pto):
  378. # XXX missing: copy basicsize and flags in a magical way
  379. # (minimally, if tp_basicsize is zero or too low, we copy it from the base)
  380. if pto.c_tp_basicsize < base_pto.c_tp_basicsize:
  381. pto.c_tp_basicsize = base_pto.c_tp_basicsize
  382. if pto.c_tp_itemsize < base_pto.c_tp_itemsize:
  383. pto.c_tp_itemsize = base_pto.c_tp_itemsize
  384. pto.c_tp_flags |= base_pto.c_tp_flags & Py_TPFLAGS_CHECKTYPES
  385. pto.c_tp_flags |= base_pto.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS
  386. def check_descr(space, w_self, w_type):
  387. if not space.isinstance_w(w_self, w_type):
  388. raise DescrMismatch()
  389. class GettersAndSetters:
  390. def getter(self, space, w_self):
  391. assert isinstance(self, W_GetSetPropertyEx)
  392. check_descr(space, w_self, self.w_type)
  393. return generic_cpy_call(
  394. space, self.getset.c_get, w_self,
  395. self.getset.c_closure)
  396. def setter(self, space, w_self, w_value):
  397. assert isinstance(self, W_GetSetPropertyEx)
  398. check_descr(space, w_self, self.w_type)
  399. res = generic_cpy_call(
  400. space, self.getset.c_set, w_self, w_value,
  401. self.getset.c_closure)
  402. if rffi.cast(lltype.Signed, res) < 0:
  403. state = space.fromcache(State)
  404. state.check_and_raise_exception()
  405. def member_getter(self, space, w_self):
  406. assert isinstance(self, W_MemberDescr)
  407. check_descr(space, w_self, self.w_type)
  408. pyref = make_ref(space, w_self)
  409. try:
  410. return PyMember_GetOne(
  411. space, rffi.cast(rffi.CCHARP, pyref), self.member)
  412. finally:
  413. Py_DecRef(space, pyref)
  414. def member_delete(self, space, w_self):
  415. assert isinstance(self, W_MemberDescr)
  416. check_descr(space, w_self, self.w_type)
  417. pyref = make_ref(space, w_self)
  418. try:
  419. PyMember_SetOne(
  420. space, rffi.cast(rffi.CCHARP, pyref), self.member, None)
  421. finally:
  422. Py_DecRef(space, pyref)
  423. def member_setter(self, space, w_self, w_value):
  424. assert isinstance(self, W_MemberDescr)
  425. check_descr(space, w_self, self.w_type)
  426. pyref = make_ref(space, w_self)
  427. try:
  428. PyMember_SetOne(
  429. space, rffi.cast(rffi.CCHARP, pyref), self.member, w_value)
  430. finally:
  431. Py_DecRef(space, pyref)
  432. class W_PyCTypeObject(W_TypeObject):
  433. @jit.dont_look_inside
  434. def __init__(self, space, pto):
  435. bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
  436. dict_w = {}
  437. add_operators(space, dict_w, pto)
  438. convert_method_defs(space, dict_w, pto.c_tp_methods, self)
  439. convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
  440. convert_member_defs(space, dict_w, pto.c_tp_members, self)
  441. name = rffi.charp2str(cts.cast('char*', pto.c_tp_name))
  442. flag_heaptype = pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
  443. if flag_heaptype:
  444. minsize = rffi.sizeof(PyHeapTypeObject.TO)
  445. else:
  446. minsize = rffi.sizeof(PyObject.TO)
  447. new_layout = (pto.c_tp_basicsize > minsize or pto.c_tp_itemsize > 0)
  448. W_TypeObject.__init__(self, space, name,
  449. bases_w or [space.w_object], dict_w, force_new_layout=new_layout,
  450. is_heaptype=flag_heaptype)
  451. self.flag_cpytype = True
  452. # if a sequence or a mapping, then set the flag to force it
  453. if pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_item:
  454. self.flag_map_or_seq = 'S'
  455. elif (pto.c_tp_as_mapping and pto.c_tp_as_mapping.c_mp_subscript and
  456. not (pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_slice)):
  457. self.flag_map_or_seq = 'M'
  458. if pto.c_tp_doc:
  459. self.w_doc = space.newtext(
  460. rffi.charp2str(cts.cast('char*', pto.c_tp_doc)))
  461. @bootstrap_function
  462. def init_typeobject(space):
  463. make_typedescr(space.w_type.layout.typedef,
  464. basestruct=PyTypeObject,
  465. alloc=type_alloc,
  466. attach=type_attach,
  467. realize=type_realize,
  468. dealloc=type_dealloc)
  469. @slot_function([PyObject], lltype.Void)
  470. def subtype_dealloc(space, obj):
  471. pto = obj.c_ob_type
  472. base = pto
  473. this_func_ptr = llslot(space, subtype_dealloc)
  474. w_obj = from_ref(space, rffi.cast(PyObject, base))
  475. # This wrapper is created on a specific type, call it w_A.
  476. # We wish to call the dealloc function from one of the base classes of w_A,
  477. # the first of which is not this function itself.
  478. # w_obj is an instance of w_A or one of its subclasses. So climb up the
  479. # inheritance chain until base.c_tp_dealloc is exactly this_func, and then
  480. # continue on up until they differ.
  481. #print 'subtype_dealloc, start from', rffi.charp2str(base.c_tp_name)
  482. while base.c_tp_dealloc != this_func_ptr:
  483. base = base.c_tp_base
  484. assert base
  485. #print ' ne move to', rffi.charp2str(base.c_tp_name)
  486. w_obj = from_ref(space, rffi.cast(PyObject, base))
  487. while base.c_tp_dealloc == this_func_ptr:
  488. base = base.c_tp_base
  489. assert base
  490. #print ' eq move to', rffi.charp2str(base.c_tp_name)
  491. w_obj = from_ref(space, rffi.cast(PyObject, base))
  492. #print ' end with', rffi.charp2str(base.c_tp_name)
  493. dealloc = base.c_tp_dealloc
  494. # XXX call tp_del if necessary
  495. generic_cpy_call(space, dealloc, obj)
  496. # XXX cpy decrefs the pto here but we do it in the base-dealloc
  497. # hopefully this does not clash with the memory model assumed in
  498. # extension modules
  499. @slot_function([PyObject, Py_ssize_tP], lltype.Signed, error=CANNOT_FAIL)
  500. def bf_segcount(space, w_obj, ref):
  501. if ref:
  502. ref[0] = space.len_w(w_obj)
  503. return 1
  504. @slot_function([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, error=-1)
  505. def bf_getreadbuffer(space, w_buf, segment, ref):
  506. from rpython.rlib.buffer import StringBuffer
  507. if segment != 0:
  508. raise oefmt(space.w_SystemError,
  509. "accessing non-existent segment")
  510. buf = space.readbuf_w(w_buf)
  511. if isinstance(buf, StringBuffer):
  512. return str_getreadbuffer(space, w_buf, segment, ref)
  513. address = buf.get_raw_address()
  514. ref[0] = address
  515. return len(buf)
  516. @slot_function([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed, error=-1)
  517. def bf_getcharbuffer(space, w_buf, segment, ref):
  518. return bf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
  519. @slot_function([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, error=-1)
  520. def bf_getwritebuffer(space, w_buf, segment, ref):
  521. if segment != 0:
  522. raise oefmt(space.w_SystemError,
  523. "accessing non-existent segment")
  524. buf = space.writebuf_w(w_buf)
  525. ref[0] = buf.get_raw_address()
  526. return len(buf)
  527. @slot_function([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, error=-1)
  528. def str_getreadbuffer(space, w_str, segment, ref):
  529. from pypy.module.cpyext.bytesobject import PyString_AsString
  530. if segment != 0:
  531. raise oefmt(space.w_SystemError,
  532. "accessing non-existent string segment")
  533. pyref = make_ref(space, w_str)
  534. ref[0] = PyString_AsString(space, pyref)
  535. # Stolen reference: the object has better exist somewhere else
  536. Py_DecRef(space, pyref)
  537. return space.len_w(w_str)
  538. @slot_function([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, error=-1)
  539. def unicode_getreadbuffer(space, w_str, segment, ref):
  540. from pypy.module.cpyext.unicodeobject import (
  541. PyUnicode_AS_UNICODE, PyUnicode_GET_DATA_SIZE)
  542. if segment != 0:
  543. raise oefmt(space.w_SystemError,
  544. "accessing non-existent unicode segment")
  545. pyref = make_ref(space, w_str)
  546. ref[0] = PyUnicode_AS_UNICODE(space, pyref)
  547. # Stolen reference: the object has better exist somewhere else
  548. Py_DecRef(space, pyref)
  549. return PyUnicode_GET_DATA_SIZE(space, w_str)
  550. @slot_function([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed, error=-1)
  551. def str_getcharbuffer(space, w_buf, segment, ref):
  552. return str_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
  553. @slot_function([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, error=-1)
  554. def buf_getreadbuffer(space, pyref, segment, ref):
  555. from pypy.module.cpyext.bufferobject import PyBufferObject
  556. if segment != 0:
  557. raise oefmt(space.w_SystemError,
  558. "accessing non-existent buffer segment")
  559. py_buf = rffi.cast(PyBufferObject, pyref)
  560. ref[0] = py_buf.c_b_ptr
  561. return py_buf.c_b_size
  562. @slot_function([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed, error=-1)
  563. def buf_getcharbuffer(space, w_buf, segment, ref):
  564. return buf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
  565. def setup_buffer_procs(space, w_type, pto):
  566. bufspec = w_type.layout.typedef.buffer
  567. if bufspec is None and not space.is_w(w_type, space.w_unicode):
  568. # not a buffer, but let w_unicode be a read buffer
  569. return
  570. c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
  571. lltype.render_immortal(c_buf)
  572. c_buf.c_bf_getsegcount = llslot(space, bf_segcount)
  573. if space.is_w(w_type, space.w_bytes):
  574. # Special case: str doesn't support get_raw_address(), so we have a
  575. # custom get*buffer that instead gives the address of the char* in the
  576. # PyBytesObject*!
  577. c_buf.c_bf_getreadbuffer = llslot(space, str_getreadbuffer)
  578. c_buf.c_bf_getcharbuffer = llslot(space, str_getcharbuffer)
  579. elif space.is_w(w_type, space.w_unicode):
  580. # Special case: unicode doesn't support get_raw_address(), so we have a
  581. # custom get*buffer that instead gives the address of the char* in the
  582. # PyUnicodeObject*!
  583. c_buf.c_bf_getreadbuffer = llslot(space, unicode_getreadbuffer)
  584. elif space.is_w(w_type, space.w_buffer):
  585. # Special case: we store a permanent address on the cpyext wrapper,
  586. # so we'll reuse that.
  587. # Note: we could instead store a permanent address on the buffer object,
  588. # and use get_raw_address()
  589. c_buf.c_bf_getreadbuffer = llslot(space, buf_getreadbuffer)
  590. c_buf.c_bf_getcharbuffer = llslot(space, buf_getcharbuffer)
  591. else:
  592. # use get_raw_address()
  593. c_buf.c_bf_getreadbuffer = llslot(space, bf_getreadbuffer)
  594. c_buf.c_bf_getcharbuffer = llslot(space, bf_getcharbuffer)
  595. if bufspec == 'read-write':
  596. c_buf.c_bf_getwritebuffer = llslot(space, bf_getwritebuffer)
  597. pto.c_tp_as_buffer = c_buf
  598. pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
  599. pto.c_tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER
  600. @slot_function([PyObject], lltype.Void)
  601. def type_dealloc(space, obj):
  602. from pypy.module.cpyext.object import _dealloc
  603. obj_pto = rffi.cast(PyTypeObjectPtr, obj)
  604. base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
  605. Py_DecRef(space, obj_pto.c_tp_bases)
  606. Py_DecRef(space, obj_pto.c_tp_mro)
  607. Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
  608. Py_DecRef(space, obj_pto.c_tp_dict)
  609. if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
  610. heaptype = rffi.cast(PyHeapTypeObject, obj)
  611. Py_DecRef(space, heaptype.c_ht_name)
  612. Py_DecRef(space, base_pyo)
  613. _dealloc(space, obj)
  614. def type_alloc(space, w_metatype, itemsize=0):
  615. metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype))
  616. # Don't increase refcount for non-heaptypes
  617. if metatype:
  618. flags = rffi.cast(lltype.Signed, metatype.c_tp_flags)
  619. if not flags & Py_TPFLAGS_HEAPTYPE:
  620. Py_DecRef(space, w_metatype)
  621. heaptype = lltype.malloc(PyHeapTypeObject.TO,
  622. flavor='raw', zero=True,
  623. add_memory_pressure=True)
  624. pto = heaptype.c_ht_type
  625. pto.c_ob_refcnt = 1
  626. pto.c_ob_pypy_link = 0
  627. pto.c_ob_type = metatype
  628. pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
  629. pto.c_tp_as_number = heaptype.c_as_number
  630. pto.c_tp_as_sequence = heaptype.c_as_sequence
  631. pto.c_tp_as_mapping = heaptype.c_as_mapping
  632. pto.c_tp_as_buffer = heaptype.c_as_buffer
  633. pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
  634. pto.c_tp_itemsize = 0
  635. return rffi.cast(PyObject, heaptype)
  636. def type_attach(space, py_obj, w_type, w_userdata=None):
  637. """
  638. Fills a newly allocated PyTypeObject from an existing type.
  639. """
  640. from pypy.module.cpyext.object import PyObject_Free
  641. assert isinstance(w_type, W_TypeObject)
  642. pto = rffi.cast(PyTypeObjectPtr, py_obj)
  643. typedescr = get_typedescr(w_type.layout.typedef)
  644. if space.is_w(w_type, space.w_bytes):
  645. pto.c_tp_itemsize = 1
  646. elif space.is_w(w_type, space.w_tuple):
  647. pto.c_tp_itemsize = rffi.sizeof(PyObject)
  648. # buffer protocol
  649. setup_buffer_procs(space, w_type, pto)
  650. pto.c_tp_free = llslot(space, PyObject_Free)
  651. pto.c_tp_alloc = llslot(space, PyType_GenericAlloc)
  652. builder = space.fromcache(State).builder
  653. if ((pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE) != 0
  654. and builder.cpyext_type_init is None):
  655. # this ^^^ is not None only during startup of cpyext. At that
  656. # point we might get into troubles by doing make_ref() when
  657. # things are not initialized yet. So in this case, simply use
  658. # str2charp() and "leak" the string.
  659. w_typename = space.getattr(w_type, space.newtext('__name__'))
  660. heaptype = cts.cast('PyHeapTypeObject*', pto)
  661. heaptype.c_ht_name = make_ref(space, w_typename)
  662. from pypy.module.cpyext.bytesobject import PyString_AsString
  663. pto.c_tp_name = cts.cast('const char *',
  664. PyString_AsString(space, heaptype.c_ht_name))
  665. else:
  666. pto.c_tp_name = cts.cast('const char*', rffi.str2charp(w_type.name))
  667. # uninitialized fields:
  668. # c_tp_print
  669. # XXX implement
  670. # c_tp_compare and more?
  671. w_base = best_base(space, w_type.bases_w)
  672. pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))
  673. # dealloc
  674. if space.gettypeobject(w_type.layout.typedef) is w_type:
  675. # only for the exact type, like 'space.w_tuple' or 'space.w_list'
  676. pto.c_tp_dealloc = typedescr.get_dealloc().get_llhelper(space)
  677. else:
  678. # for all subtypes, use base's dealloc (requires sorting in attach_all)
  679. pto.c_tp_dealloc = pto.c_tp_base.c_tp_dealloc
  680. if not pto.c_tp_dealloc:
  681. # strange, but happens (ABCMeta)
  682. pto.c_tp_dealloc = llslot(space, subtype_dealloc)
  683. if builder.cpyext_type_init is not None:
  684. builder.cpyext_type_init.append((pto, w_type))
  685. else:
  686. finish_type_1(space, pto, w_type.bases_w)
  687. finish_type_2(space, pto, w_type)
  688. pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
  689. if pto.c_tp_base:
  690. if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
  691. pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
  692. if pto.c_tp_itemsize < pto.c_tp_base.c_tp_itemsize:
  693. pto.c_tp_itemsize = pto.c_tp_base.c_tp_itemsize
  694. update_all_slots(space, w_type, pto)
  695. if not pto.c_tp_new:
  696. base_object_pyo = make_ref(space, space.w_object)
  697. base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
  698. flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
  699. if pto.c_tp_base != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE:
  700. pto.c_tp_new = pto.c_tp_base.c_tp_new
  701. Py_DecRef(space, base_object_pyo)
  702. pto.c_tp_flags |= Py_TPFLAGS_READY
  703. return pto
  704. def py_type_ready(space, pto):
  705. if pto.c_tp_flags & Py_TPFLAGS_READY:
  706. return
  707. type_realize(space, rffi.cast(PyObject, pto))
  708. @cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
  709. def PyType_Ready(space, pto):
  710. py_type_ready(space, pto)
  711. return 0
  712. def type_realize(space, py_obj):
  713. pto = rffi.cast(PyTypeObjectPtr, py_obj)
  714. assert pto.c_tp_flags & Py_TPFLAGS_READY == 0
  715. assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
  716. pto.c_tp_flags |= Py_TPFLAGS_READYING
  717. try:
  718. w_obj = _type_realize(space, py_obj)
  719. finally:
  720. name = rffi.charp2str(cts.cast('char*', pto.c_tp_name))
  721. pto.c_tp_flags &= ~Py_TPFLAGS_READYING
  722. pto.c_tp_flags |= Py_TPFLAGS_READY
  723. return w_obj
  724. def solid_base(space, w_type):
  725. typedef = w_type.layout.typedef
  726. return space.gettypeobject(typedef)
  727. def best_base(space, bases_w):
  728. if not bases_w:
  729. return None
  730. return find_best_base(bases_w)
  731. def inherit_slots(space, pto, w_base):
  732. base_pyo = make_ref(space, w_base)
  733. try:
  734. base = rffi.cast(PyTypeObjectPtr, base_pyo)
  735. if not pto.c_tp_dealloc:
  736. pto.c_tp_dealloc = base.c_tp_dealloc
  737. if not pto.c_tp_init:
  738. pto.c_tp_init = base.c_tp_init
  739. if not pto.c_tp_alloc:
  740. pto.c_tp_alloc = base.c_tp_alloc
  741. # XXX check for correct GC flags!
  742. if not pto.c_tp_free:
  743. pto.c_tp_free = base.c_tp_free
  744. if not pto.c_tp_setattro:
  745. pto.c_tp_setattro = base.c_tp_setattro
  746. if not pto.c_tp_getattro:
  747. pto.c_tp_getattro = base.c_tp_getattro
  748. if not pto.c_tp_as_buffer:
  749. pto.c_tp_as_buffer = base.c_tp_as_buffer
  750. if base.c_tp_as_buffer:
  751. # inherit base.c_tp_as_buffer functions not inherited from w_type
  752. # note: builtin types are handled in setup_buffer_procs
  753. pto_as = pto.c_tp_as_buffer
  754. base_as = base.c_tp_as_buffer
  755. if not pto_as.c_bf_getbuffer:
  756. pto_as.c_bf_getbuffer = base_as.c_bf_getbuffer
  757. if not pto_as.c_bf_getcharbuffer:
  758. pto_as.c_bf_getcharbuffer = base_as.c_bf_getcharbuffer
  759. if not pto_as.c_bf_getwritebuffer:
  760. pto_as.c_bf_getwritebuffer = base_as.c_bf_getwritebuffer
  761. if not pto_as.c_bf_getreadbuffer:
  762. pto_as.c_bf_getreadbuffer = base_as.c_bf_getreadbuffer
  763. if not pto_as.c_bf_getsegcount:
  764. pto_as.c_bf_getsegcount = base_as.c_bf_getsegcount
  765. if not pto_as.c_bf_releasebuffer:
  766. pto_as.c_bf_releasebuffer = base_as.c_bf_releasebuffer
  767. finally:
  768. Py_DecRef(space, base_pyo)
  769. def _type_realize(space, py_obj):
  770. """
  771. Creates an interpreter type from a PyTypeObject structure.
  772. """
  773. # missing:
  774. # unsupported:
  775. # tp_mro, tp_subclasses
  776. py_type = rffi.cast(PyTypeObjectPtr, py_obj)
  777. if not py_type.c_tp_base:
  778. # borrowed reference, but w_object is unlikely to disappear
  779. base = as_pyobj(space, space.w_object)
  780. py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
  781. finish_type_1(space, py_type)
  782. if py_type.c_ob_type:
  783. w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
  784. else:
  785. # Somehow the tp_base type is created with no ob_type, notably
  786. # PyString_Type and PyBaseString_Type
  787. # While this is a hack, cpython does it as well.
  788. w_metatype = space.w_type
  789. w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
  790. track_reference(space, py_obj, w_obj)
  791. # __init__ wraps all slotdefs functions from py_type via add_operators
  792. w_obj.__init__(space, py_type)
  793. w_obj.ready()
  794. finish_type_2(space, py_type, w_obj)
  795. base = py_type.c_tp_base
  796. if base:
  797. # XXX refactor - parts of this are done in finish_type_2 -> inherit_slots
  798. if not py_type.c_tp_as_number:
  799. py_type.c_tp_as_number = base.c_tp_as_number
  800. py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_CHECKTYPES
  801. py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS
  802. if not py_type.c_tp_as_sequence:
  803. py_type.c_tp_as_sequence = base.c_tp_as_sequence
  804. py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS
  805. if not py_type.c_tp_as_mapping:
  806. py_type.c_tp_as_mapping = base.c_tp_as_mapping
  807. #if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = base.c_tp_as_buffer
  808. return w_obj
  809. def finish_type_1(space, pto, bases_w=None):
  810. """
  811. Sets up tp_bases, necessary before creating the interpreter type.
  812. """
  813. base = pto.c_tp_base
  814. base_pyo = rffi.cast(PyObject, pto.c_tp_base)
  815. if base and not base.c_tp_flags & Py_TPFLAGS_READY:
  816. name = rffi.charp2str(cts.cast('char*', base.c_tp_name))
  817. type_realize(space, base_pyo)
  818. if base and not pto.c_ob_type: # will be filled later
  819. pto.c_ob_type = base.c_ob_type
  820. if not pto.c_tp_bases:
  821. if bases_w is None:
  822. if not base:
  823. bases_w = []
  824. else:
  825. bases_w = [from_ref(space, base_pyo)]
  826. pto.c_tp_bases = make_ref(space, space.newtuple(bases_w))
  827. def finish_type_2(space, pto, w_obj):
  828. """
  829. Sets up other attributes, when the interpreter type has been created.
  830. """
  831. pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w))
  832. base = pto.c_tp_base
  833. if base:
  834. inherit_special(space, pto, base)
  835. for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
  836. if isinstance(w_base, W_TypeObject):
  837. inherit_slots(space, pto, w_base)
  838. #else:
  839. # w_base is a W_ClassObject, ignore it
  840. if not pto.c_tp_setattro:
  841. from pypy.module.cpyext.object import PyObject_GenericSetAttr
  842. pto.c_tp_setattro = llslot(space, PyObject_GenericSetAttr)
  843. if not pto.c_tp_getattro:
  844. from pypy.module.cpyext.object import PyObject_GenericGetAttr
  845. pto.c_tp_getattro = llslot(space, PyObject_GenericGetAttr)
  846. if w_obj.is_cpytype():
  847. Py_DecRef(space, pto.c_tp_dict)
  848. w_dict = w_obj.getdict(space)
  849. # pass in the w_obj to convert any values that are
  850. # unbound GetSetProperty into bound PyGetSetDescrObject
  851. pto.c_tp_dict = make_ref(space, w_dict, w_obj)
  852. @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
  853. def PyType_IsSubtype(space, a, b):
  854. """Return true if a is a subtype of b.
  855. """
  856. w_type1 = from_ref(space, rffi.cast(PyObject, a))
  857. w_type2 = from_ref(space, rffi.cast(PyObject, b))
  858. return int(abstract_issubclass_w(space, w_type1, w_type2)) #XXX correct?
  859. @cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject, result_is_ll=True)
  860. def PyType_GenericAlloc(space, type, nitems):
  861. from pypy.module.cpyext.object import _PyObject_NewVar
  862. return _PyObject_NewVar(space, type, nitems)
  863. @cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject)
  864. def PyType_GenericNew(space, type, w_args, w_kwds):
  865. return generic_cpy_call(
  866. space, type.c_tp_alloc, type, 0)
  867. @cpython_api([PyTypeObjectPtr, PyObject], PyObject, error=CANNOT_FAIL,
  868. result_borrowed=True)
  869. def _PyType_Lookup(space, type, w_name):
  870. """Internal API to look for a name through the MRO.
  871. This returns a borrowed reference, and doesn't set an exception!"""
  872. w_type = from_ref(space, rffi.cast(PyObject, type))
  873. assert isinstance(w_type, W_TypeObject)
  874. if not space.isinstance_w(w_name, space.w_text):
  875. return None
  876. name = space.text_w(w_name)
  877. w_obj = w_type.lookup(name)
  878. # this assumes that w_obj is not dynamically created, but will stay alive
  879. # until w_type is modified or dies. Assuming this, we return a borrowed ref
  880. return w_obj
  881. @cpython_api([PyTypeObjectPtr], lltype.Void)
  882. def PyType_Modified(space, w_obj):
  883. """Invalidate the internal lookup cache for the type and all of its
  884. subtypes. This function must be called after any manual
  885. modification of the attributes or base classes of the type.
  886. """
  887. # Invalidate the type cache in case of a builtin type.
  888. if not isinstance(w_obj, W_TypeObject):
  889. return
  890. if w_obj.is_cpytype():
  891. w_obj.mutated(None)