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

/pypy/module/cpyext/typeobject.py

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