PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/cpyext/typeobject.py

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