PageRenderTime 60ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/cpyext/typeobject.py

https://bitbucket.org/alex_gaynor/pypy-postgresql/
Python | 662 lines | 517 code | 84 blank | 61 comment | 89 complexity | e11a996b3bbd53535e1215cbdef7b772 MD5 | raw file
  1. import os
  2. import sys
  3. from pypy.rpython.lltypesystem import rffi, lltype
  4. from pypy.rpython.annlowlevel import llhelper
  5. from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
  6. from pypy.objspace.std.typeobject import W_TypeObject
  7. from pypy.interpreter.typedef import GetSetProperty
  8. from pypy.module.cpyext.api import (
  9. cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
  10. generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
  11. Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
  12. Py_TPFLAGS_HAVE_GETCHARBUFFER,
  13. build_type_checkers)
  14. from pypy.module.cpyext.pyobject import (
  15. PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
  16. track_reference, RefcountState, borrow_from)
  17. from pypy.interpreter.module import Module
  18. from pypy.module.cpyext import structmemberdefs
  19. from pypy.module.cpyext.modsupport import convert_method_defs
  20. from pypy.module.cpyext.state import State
  21. from pypy.module.cpyext.methodobject import (
  22. PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef)
  23. from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef, _Py_Dealloc
  24. from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
  25. from pypy.module.cpyext.typeobjectdefs import (
  26. PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
  27. PyNumberMethods, PySequenceMethods, PyBufferProcs)
  28. from pypy.module.cpyext.slotdefs import (
  29. slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
  30. from pypy.interpreter.error import OperationError
  31. from pypy.rlib.rstring import rsplit
  32. from pypy.rlib.objectmodel import specialize
  33. from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
  34. from pypy.module.__builtin__.interp_classobj import W_ClassObject
  35. from pypy.rlib import jit
  36. WARN_ABOUT_MISSING_SLOT_FUNCTIONS = False
  37. PyType_Check, PyType_CheckExact = build_type_checkers("Type", "w_type")
  38. class W_GetSetPropertyEx(GetSetProperty):
  39. def __init__(self, getset, w_type):
  40. self.getset = getset
  41. self.name = rffi.charp2str(getset.c_name)
  42. self.w_type = w_type
  43. doc = set = get = None
  44. if doc:
  45. doc = rffi.charp2str(getset.c_doc)
  46. if getset.c_get:
  47. get = GettersAndSetters.getter.im_func
  48. if getset.c_set:
  49. set = GettersAndSetters.setter.im_func
  50. GetSetProperty.__init__(self, get, set, None, doc,
  51. cls=None, use_closure=True,
  52. tag="cpyext_1")
  53. def PyDescr_NewGetSet(space, getset, w_type):
  54. return space.wrap(W_GetSetPropertyEx(getset, w_type))
  55. class W_MemberDescr(GetSetProperty):
  56. def __init__(self, member, w_type):
  57. self.member = member
  58. self.name = rffi.charp2str(member.c_name)
  59. self.w_type = w_type
  60. flags = rffi.cast(lltype.Signed, member.c_flags)
  61. doc = set = None
  62. if member.c_doc:
  63. doc = rffi.charp2str(member.c_doc)
  64. get = GettersAndSetters.member_getter.im_func
  65. del_ = GettersAndSetters.member_delete.im_func
  66. if not (flags & structmemberdefs.READONLY):
  67. set = GettersAndSetters.member_setter.im_func
  68. GetSetProperty.__init__(self, get, set, del_, doc,
  69. cls=None, use_closure=True,
  70. tag="cpyext_2")
  71. def convert_getset_defs(space, dict_w, getsets, w_type):
  72. getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets)
  73. if getsets:
  74. i = -1
  75. while True:
  76. i = i + 1
  77. getset = getsets[i]
  78. name = getset.c_name
  79. if not name:
  80. break
  81. name = rffi.charp2str(name)
  82. w_descr = PyDescr_NewGetSet(space, getset, w_type)
  83. dict_w[name] = w_descr
  84. def convert_member_defs(space, dict_w, members, w_type):
  85. members = rffi.cast(rffi.CArrayPtr(PyMemberDef), members)
  86. if members:
  87. i = 0
  88. while True:
  89. member = members[i]
  90. name = member.c_name
  91. if not name:
  92. break
  93. name = rffi.charp2str(name)
  94. w_descr = space.wrap(W_MemberDescr(member, w_type))
  95. dict_w[name] = w_descr
  96. i += 1
  97. def update_all_slots(space, w_type, pto):
  98. # XXX fill slots in pto
  99. typedef = w_type.instancetypedef
  100. for method_name, slot_name, slot_names, slot_func in slotdefs_for_tp_slots:
  101. w_descr = w_type.lookup(method_name)
  102. if w_descr is None:
  103. # XXX special case iternext
  104. continue
  105. slot_func_helper = None
  106. if slot_func is None and typedef is not None:
  107. get_slot = get_slot_tp_function(space, typedef, slot_name)
  108. if get_slot:
  109. slot_func_helper = get_slot()
  110. elif slot_func:
  111. slot_func_helper = llhelper(slot_func.api_func.functype,
  112. slot_func.api_func.get_wrapper(space))
  113. if slot_func_helper is None:
  114. if WARN_ABOUT_MISSING_SLOT_FUNCTIONS:
  115. os.write(2, method_name + " defined by the type but no slot function defined!\n")
  116. continue
  117. # XXX special case wrapper-functions and use a "specific" slot func
  118. if len(slot_names) == 1:
  119. setattr(pto, slot_names[0], slot_func_helper)
  120. else:
  121. assert len(slot_names) == 2
  122. struct = getattr(pto, slot_names[0])
  123. if not struct:
  124. if slot_names[0] == 'c_tp_as_number':
  125. STRUCT_TYPE = PyNumberMethods
  126. elif slot_names[0] == 'c_tp_as_sequence':
  127. STRUCT_TYPE = PySequenceMethods
  128. else:
  129. raise AssertionError(
  130. "Structure not allocated: %s" % (slot_names[0],))
  131. struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
  132. setattr(pto, slot_names[0], struct)
  133. setattr(struct, slot_names[1], slot_func_helper)
  134. def add_operators(space, dict_w, pto):
  135. # XXX support PyObject_HashNotImplemented
  136. for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
  137. if method_name in dict_w:
  138. continue
  139. if len(slot_names) == 1:
  140. func = getattr(pto, slot_names[0])
  141. else:
  142. assert len(slot_names) == 2
  143. struct = getattr(pto, slot_names[0])
  144. if not struct:
  145. continue
  146. func = getattr(struct, slot_names[1])
  147. func_voidp = rffi.cast(rffi.VOIDP, func)
  148. if not func:
  149. continue
  150. if wrapper_func is None and wrapper_func_kwds is None:
  151. continue
  152. dict_w[method_name] = PyDescr_NewWrapper(space, pto, method_name, wrapper_func,
  153. wrapper_func_kwds, doc, func_voidp)
  154. if pto.c_tp_new:
  155. add_tp_new_wrapper(space, dict_w, pto)
  156. @cpython_api([PyObject, PyObject, PyObject], PyObject, external=False)
  157. def tp_new_wrapper(space, self, w_args, w_kwds):
  158. tp_new = rffi.cast(PyTypeObjectPtr, self).c_tp_new
  159. # Check that the user doesn't do something silly and unsafe like
  160. # object.__new__(dict). To do this, we check that the most
  161. # derived base that's not a heap type is this type.
  162. # XXX do it
  163. args_w = space.fixedview(w_args)
  164. w_subtype = args_w[0]
  165. w_args = space.newtuple(args_w[1:])
  166. subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
  167. try:
  168. w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
  169. finally:
  170. Py_DecRef(space, w_subtype)
  171. return w_obj
  172. @specialize.memo()
  173. def get_new_method_def(space):
  174. state = space.fromcache(State)
  175. if state.new_method_def:
  176. return state.new_method_def
  177. from pypy.module.cpyext.modsupport import PyMethodDef
  178. ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
  179. immortal=True)
  180. ptr.c_ml_name = rffi.str2charp("__new__")
  181. lltype.render_immortal(ptr.c_ml_name)
  182. rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
  183. ptr.c_ml_doc = rffi.str2charp(
  184. "T.__new__(S, ...) -> a new object with type S, a subtype of T")
  185. lltype.render_immortal(ptr.c_ml_doc)
  186. state.new_method_def = ptr
  187. return ptr
  188. def setup_new_method_def(space):
  189. ptr = get_new_method_def(space)
  190. ptr.c_ml_meth = rffi.cast(PyCFunction_typedef,
  191. llhelper(tp_new_wrapper.api_func.functype,
  192. tp_new_wrapper.api_func.get_wrapper(space)))
  193. def add_tp_new_wrapper(space, dict_w, pto):
  194. if "__new__" in dict_w:
  195. return
  196. pyo = rffi.cast(PyObject, pto)
  197. dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
  198. from_ref(space, pyo), None)
  199. def inherit_special(space, pto, base_pto):
  200. # XXX missing: copy basicsize and flags in a magical way
  201. flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
  202. base_object_pyo = make_ref(space, space.w_object)
  203. base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
  204. if base_pto != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE:
  205. if not pto.c_tp_new:
  206. pto.c_tp_new = base_pto.c_tp_new
  207. Py_DecRef(space, base_object_pyo)
  208. def check_descr(space, w_self, w_type):
  209. if not space.is_true(space.isinstance(w_self, w_type)):
  210. raise DescrMismatch()
  211. class GettersAndSetters:
  212. def getter(self, space, w_self):
  213. assert isinstance(self, W_GetSetPropertyEx)
  214. check_descr(space, w_self, self.w_type)
  215. return generic_cpy_call(
  216. space, self.getset.c_get, w_self,
  217. self.getset.c_closure)
  218. def setter(self, space, w_self, w_value):
  219. assert isinstance(self, W_GetSetPropertyEx)
  220. check_descr(space, w_self, self.w_type)
  221. res = generic_cpy_call(
  222. space, self.getset.c_set, w_self, w_value,
  223. self.getset.c_closure)
  224. if rffi.cast(lltype.Signed, res) < 0:
  225. state = space.fromcache(State)
  226. state.check_and_raise_exception()
  227. def member_getter(self, space, w_self):
  228. assert isinstance(self, W_MemberDescr)
  229. check_descr(space, w_self, self.w_type)
  230. return PyMember_GetOne(space, w_self, self.member)
  231. def member_delete(self, space, w_self):
  232. assert isinstance(self, W_MemberDescr)
  233. check_descr(space, w_self, self.w_type)
  234. PyMember_SetOne(space, w_self, self.member, None)
  235. def member_setter(self, space, w_self, w_value):
  236. assert isinstance(self, W_MemberDescr)
  237. check_descr(space, w_self, self.w_type)
  238. PyMember_SetOne(space, w_self, self.member, w_value)
  239. class W_PyCTypeObject(W_TypeObject):
  240. @jit.dont_look_inside
  241. def __init__(self, space, pto):
  242. bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
  243. dict_w = {}
  244. add_operators(space, dict_w, pto)
  245. convert_method_defs(space, dict_w, pto.c_tp_methods, self)
  246. convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
  247. convert_member_defs(space, dict_w, pto.c_tp_members, self)
  248. full_name = rffi.charp2str(pto.c_tp_name)
  249. if '.' in full_name:
  250. module_name, extension_name = rsplit(full_name, ".", 1)
  251. dict_w["__module__"] = space.wrap(module_name)
  252. else:
  253. extension_name = full_name
  254. W_TypeObject.__init__(self, space, extension_name,
  255. bases_w or [space.w_object], dict_w)
  256. if not space.is_true(space.issubtype(self, space.w_type)):
  257. self.flag_cpytype = True
  258. self.flag_heaptype = False
  259. @bootstrap_function
  260. def init_typeobject(space):
  261. # Probably a hack
  262. space.model.typeorder[W_PyCTypeObject] = [(W_PyCTypeObject, None),
  263. (W_TypeObject, None),
  264. (W_Root, None)]
  265. make_typedescr(space.w_type.instancetypedef,
  266. basestruct=PyTypeObject,
  267. attach=type_attach,
  268. realize=type_realize,
  269. dealloc=type_dealloc)
  270. # some types are difficult to create because of cycles.
  271. # - object.ob_type = type
  272. # - type.ob_type = type
  273. # - tuple.ob_type = type
  274. # - type.tp_base = object
  275. # - tuple.tp_base = object
  276. # - type.tp_bases is a tuple
  277. # - object.tp_bases is a tuple
  278. # - tuple.tp_bases is a tuple
  279. # insert null placeholders to please create_ref()
  280. track_reference(space, lltype.nullptr(PyObject.TO), space.w_type)
  281. track_reference(space, lltype.nullptr(PyObject.TO), space.w_object)
  282. track_reference(space, lltype.nullptr(PyObject.TO), space.w_tuple)
  283. # create the objects
  284. py_type = create_ref(space, space.w_type)
  285. py_object = create_ref(space, space.w_object)
  286. py_tuple = create_ref(space, space.w_tuple)
  287. # form cycles
  288. pto_type = rffi.cast(PyTypeObjectPtr, py_type)
  289. py_type.c_ob_type = pto_type
  290. py_object.c_ob_type = pto_type
  291. py_tuple.c_ob_type = pto_type
  292. pto_object = rffi.cast(PyTypeObjectPtr, py_object)
  293. pto_type.c_tp_base = pto_object
  294. pto_tuple = rffi.cast(PyTypeObjectPtr, py_tuple)
  295. pto_tuple.c_tp_base = pto_object
  296. pto_type.c_tp_bases.c_ob_type = pto_tuple
  297. pto_object.c_tp_bases.c_ob_type = pto_tuple
  298. pto_tuple.c_tp_bases.c_ob_type = pto_tuple
  299. # Restore the mapping
  300. track_reference(space, py_type, space.w_type, replace=True)
  301. track_reference(space, py_object, space.w_object, replace=True)
  302. track_reference(space, py_tuple, space.w_tuple, replace=True)
  303. @cpython_api([PyObject], lltype.Void, external=False)
  304. def subtype_dealloc(space, obj):
  305. pto = obj.c_ob_type
  306. base = pto
  307. this_func_ptr = llhelper(subtype_dealloc.api_func.functype,
  308. subtype_dealloc.api_func.get_wrapper(space))
  309. while base.c_tp_dealloc == this_func_ptr:
  310. base = base.c_tp_base
  311. assert base
  312. dealloc = base.c_tp_dealloc
  313. # XXX call tp_del if necessary
  314. generic_cpy_call(space, dealloc, obj)
  315. # XXX cpy decrefs the pto here but we do it in the base-dealloc
  316. # hopefully this does not clash with the memory model assumed in
  317. # extension modules
  318. @cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False,
  319. error=CANNOT_FAIL)
  320. def str_segcount(space, w_obj, ref):
  321. if ref:
  322. ref[0] = space.len_w(w_obj)
  323. return 1
  324. @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
  325. external=False, error=-1)
  326. def str_getreadbuffer(space, w_str, segment, ref):
  327. from pypy.module.cpyext.stringobject import PyString_AsString
  328. if segment != 0:
  329. raise OperationError(space.w_SystemError, space.wrap
  330. ("accessing non-existent string segment"))
  331. pyref = make_ref(space, w_str)
  332. ref[0] = PyString_AsString(space, pyref)
  333. # Stolen reference: the object has better exist somewhere else
  334. Py_DecRef(space, pyref)
  335. return space.len_w(w_str)
  336. @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
  337. external=False, error=-1)
  338. def str_getcharbuffer(space, w_str, segment, ref):
  339. from pypy.module.cpyext.stringobject import PyString_AsString
  340. if segment != 0:
  341. raise OperationError(space.w_SystemError, space.wrap
  342. ("accessing non-existent string segment"))
  343. pyref = make_ref(space, w_str)
  344. ref[0] = PyString_AsString(space, pyref)
  345. # Stolen reference: the object has better exist somewhere else
  346. Py_DecRef(space, pyref)
  347. return space.len_w(w_str)
  348. def setup_string_buffer_procs(space, pto):
  349. c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
  350. c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
  351. str_segcount.api_func.get_wrapper(space))
  352. c_buf.c_bf_getreadbuffer = llhelper(str_getreadbuffer.api_func.functype,
  353. str_getreadbuffer.api_func.get_wrapper(space))
  354. c_buf.c_bf_getcharbuffer = llhelper(str_getcharbuffer.api_func.functype,
  355. str_getcharbuffer.api_func.get_wrapper(space))
  356. pto.c_tp_as_buffer = c_buf
  357. pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
  358. @cpython_api([PyObject], lltype.Void, external=False)
  359. def type_dealloc(space, obj):
  360. from pypy.module.cpyext.object import PyObject_dealloc
  361. obj_pto = rffi.cast(PyTypeObjectPtr, obj)
  362. base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
  363. Py_DecRef(space, obj_pto.c_tp_bases)
  364. Py_DecRef(space, obj_pto.c_tp_mro)
  365. Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
  366. Py_DecRef(space, obj_pto.c_tp_dict)
  367. if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
  368. if obj_pto.c_tp_as_buffer:
  369. lltype.free(obj_pto.c_tp_as_buffer, flavor='raw')
  370. if obj_pto.c_tp_as_number:
  371. lltype.free(obj_pto.c_tp_as_number, flavor='raw')
  372. if obj_pto.c_tp_as_sequence:
  373. lltype.free(obj_pto.c_tp_as_sequence, flavor='raw')
  374. Py_DecRef(space, base_pyo)
  375. rffi.free_charp(obj_pto.c_tp_name)
  376. PyObject_dealloc(space, obj)
  377. def type_attach(space, py_obj, w_type):
  378. """
  379. Fills a newly allocated PyTypeObject from an existing type.
  380. """
  381. from pypy.module.cpyext.object import PyObject_Del
  382. assert isinstance(w_type, W_TypeObject)
  383. pto = rffi.cast(PyTypeObjectPtr, py_obj)
  384. typedescr = get_typedescr(w_type.instancetypedef)
  385. # dealloc
  386. pto.c_tp_dealloc = typedescr.get_dealloc(space)
  387. # buffer protocol
  388. if space.is_w(w_type, space.w_str):
  389. setup_string_buffer_procs(space, pto)
  390. pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
  391. pto.c_tp_free = llhelper(PyObject_Del.api_func.functype,
  392. PyObject_Del.api_func.get_wrapper(space))
  393. pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype,
  394. PyType_GenericAlloc.api_func.get_wrapper(space))
  395. pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?"))
  396. pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
  397. pto.c_tp_itemsize = 0
  398. # uninitialized fields:
  399. # c_tp_print, c_tp_getattr, c_tp_setattr
  400. # XXX implement
  401. # c_tp_compare and the following fields (see http://docs.python.org/c-api/typeobj.html )
  402. w_base = best_base(space, w_type.bases_w)
  403. pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))
  404. finish_type_1(space, pto)
  405. finish_type_2(space, pto, w_type)
  406. pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
  407. if pto.c_tp_base:
  408. if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
  409. pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
  410. # will be filled later on with the correct value
  411. # may not be 0
  412. if space.is_w(w_type, space.w_object):
  413. pto.c_tp_new = rffi.cast(newfunc, 1)
  414. update_all_slots(space, w_type, pto)
  415. pto.c_tp_flags |= Py_TPFLAGS_READY
  416. return pto
  417. @cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
  418. def PyType_Ready(space, pto):
  419. if pto.c_tp_flags & Py_TPFLAGS_READY:
  420. return 0
  421. type_realize(space, rffi.cast(PyObject, pto))
  422. return 0
  423. def type_realize(space, py_obj):
  424. pto = rffi.cast(PyTypeObjectPtr, py_obj)
  425. assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
  426. pto.c_tp_flags |= Py_TPFLAGS_READYING
  427. try:
  428. w_obj = _type_realize(space, py_obj)
  429. finally:
  430. pto.c_tp_flags &= ~Py_TPFLAGS_READYING
  431. pto.c_tp_flags |= Py_TPFLAGS_READY
  432. return w_obj
  433. def solid_base(space, w_type):
  434. typedef = w_type.instancetypedef
  435. return space.gettypeobject(typedef)
  436. def best_base(space, bases_w):
  437. if not bases_w:
  438. return None
  439. w_winner = None
  440. w_base = None
  441. for w_base_i in bases_w:
  442. if isinstance(w_base_i, W_ClassObject):
  443. # old-style base
  444. continue
  445. assert isinstance(w_base_i, W_TypeObject)
  446. w_candidate = solid_base(space, w_base_i)
  447. if not w_winner:
  448. w_winner = w_candidate
  449. w_base = w_base_i
  450. elif space.abstract_issubclass_w(w_winner, w_candidate):
  451. pass
  452. elif space.abstract_issubclass_w(w_candidate, w_winner):
  453. w_winner = w_candidate
  454. w_base = w_base_i
  455. else:
  456. raise OperationError(
  457. space.w_TypeError,
  458. space.wrap("multiple bases have instance lay-out conflict"))
  459. if w_base is None:
  460. raise OperationError(
  461. space.w_TypeError,
  462. space.wrap("a new-style class can't have only classic bases"))
  463. return w_base
  464. def inherit_slots(space, pto, w_base):
  465. # XXX missing: nearly everything
  466. base_pyo = make_ref(space, w_base)
  467. try:
  468. base = rffi.cast(PyTypeObjectPtr, base_pyo)
  469. if not pto.c_tp_dealloc:
  470. pto.c_tp_dealloc = base.c_tp_dealloc
  471. if not pto.c_tp_init:
  472. pto.c_tp_init = base.c_tp_init
  473. if not pto.c_tp_alloc:
  474. pto.c_tp_alloc = base.c_tp_alloc
  475. # XXX check for correct GC flags!
  476. if not pto.c_tp_free:
  477. pto.c_tp_free = base.c_tp_free
  478. if not pto.c_tp_setattro:
  479. pto.c_tp_setattro = base.c_tp_setattro
  480. finally:
  481. Py_DecRef(space, base_pyo)
  482. def _type_realize(space, py_obj):
  483. """
  484. Creates an interpreter type from a PyTypeObject structure.
  485. """
  486. # missing:
  487. # setting __doc__ if not defined and tp_doc defined
  488. # inheriting tp_as_* slots
  489. # unsupported:
  490. # tp_mro, tp_subclasses
  491. py_type = rffi.cast(PyTypeObjectPtr, py_obj)
  492. if not py_type.c_tp_base:
  493. # borrowed reference, but w_object is unlikely to disappear
  494. base = make_ref(space, space.w_object)
  495. Py_DecRef(space, base)
  496. py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
  497. finish_type_1(space, py_type)
  498. w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
  499. w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
  500. track_reference(space, py_obj, w_obj)
  501. w_obj.__init__(space, py_type)
  502. w_obj.ready()
  503. finish_type_2(space, py_type, w_obj)
  504. state = space.fromcache(RefcountState)
  505. state.non_heaptypes_w.append(w_obj)
  506. return w_obj
  507. def finish_type_1(space, pto):
  508. """
  509. Sets up tp_bases, necessary before creating the interpreter type.
  510. """
  511. base = pto.c_tp_base
  512. base_pyo = rffi.cast(PyObject, pto.c_tp_base)
  513. if base and not base.c_tp_flags & Py_TPFLAGS_READY:
  514. type_realize(space, rffi.cast(PyObject, base_pyo))
  515. if base and not pto.c_ob_type: # will be filled later
  516. pto.c_ob_type = base.c_ob_type
  517. if not pto.c_tp_bases:
  518. if not base:
  519. bases = space.newtuple([])
  520. else:
  521. bases = space.newtuple([from_ref(space, base_pyo)])
  522. pto.c_tp_bases = make_ref(space, bases)
  523. def finish_type_2(space, pto, w_obj):
  524. """
  525. Sets up other attributes, when the interpreter type has been created.
  526. """
  527. pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w))
  528. base = pto.c_tp_base
  529. if base:
  530. inherit_special(space, pto, base)
  531. for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
  532. inherit_slots(space, pto, w_base)
  533. if not pto.c_tp_setattro:
  534. from pypy.module.cpyext.object import PyObject_GenericSetAttr
  535. pto.c_tp_setattro = llhelper(
  536. PyObject_GenericSetAttr.api_func.functype,
  537. PyObject_GenericSetAttr.api_func.get_wrapper(space))
  538. if w_obj.is_cpytype():
  539. Py_DecRef(space, pto.c_tp_dict)
  540. w_dict = w_obj.getdict(space)
  541. pto.c_tp_dict = make_ref(space, w_dict)
  542. @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
  543. def PyType_IsSubtype(space, a, b):
  544. """Return true if a is a subtype of b.
  545. """
  546. w_type1 = from_ref(space, rffi.cast(PyObject, a))
  547. w_type2 = from_ref(space, rffi.cast(PyObject, b))
  548. return int(abstract_issubclass_w(space, w_type1, w_type2)) #XXX correct?
  549. @cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject)
  550. def PyType_GenericAlloc(space, type, nitems):
  551. from pypy.module.cpyext.object import _PyObject_NewVar
  552. return _PyObject_NewVar(space, type, nitems)
  553. @cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject)
  554. def PyType_GenericNew(space, type, w_args, w_kwds):
  555. return generic_cpy_call(
  556. space, type.c_tp_alloc, type, 0)
  557. @cpython_api([PyTypeObjectPtr, PyObject], PyObject, error=CANNOT_FAIL)
  558. def _PyType_Lookup(space, type, w_name):
  559. """Internal API to look for a name through the MRO.
  560. This returns a borrowed reference, and doesn't set an exception!"""
  561. w_type = from_ref(space, rffi.cast(PyObject, type))
  562. assert isinstance(w_type, W_TypeObject)
  563. if not space.isinstance_w(w_name, space.w_str):
  564. return None
  565. name = space.str_w(w_name)
  566. w_obj = w_type.lookup(name)
  567. return borrow_from(w_type, w_obj)
  568. @cpython_api([PyTypeObjectPtr], lltype.Void)
  569. def PyType_Modified(space, w_obj):
  570. """Invalidate the internal lookup cache for the type and all of its
  571. subtypes. This function must be called after any manual
  572. modification of the attributes or base classes of the type.
  573. """
  574. # PyPy already takes care of direct modifications to type.__dict__
  575. # (which is a W_DictProxyObject).
  576. pass