PageRenderTime 28ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/cpyext/typeobject.py

https://bitbucket.org/krono/pypy
Python | 889 lines | 706 code | 98 blank | 85 comment | 116 complexity | 5f42467f8a6674e69bbd30121508305e 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)
  19. from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
  20. PyDescr_NewWrapper, 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. PyTypeObjectPtr, PyTypeObject, 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. # XXX 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. else:
  246. assert len(slot_names) == 2
  247. struct = getattr(pto, slot_names[0])
  248. if not struct:
  249. #assert not space.config.translating
  250. assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
  251. if slot_names[0] == 'c_tp_as_number':
  252. STRUCT_TYPE = PyNumberMethods
  253. elif slot_names[0] == 'c_tp_as_sequence':
  254. STRUCT_TYPE = PySequenceMethods
  255. else:
  256. raise AssertionError(
  257. "Structure not allocated: %s" % (slot_names[0],))
  258. struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
  259. setattr(pto, slot_names[0], struct)
  260. if not getattr(struct, slot_names[1]):
  261. setattr(struct, slot_names[1], slot_func_helper)
  262. def add_operators(space, dict_w, pto):
  263. # XXX support PyObject_HashNotImplemented
  264. for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
  265. if method_name in dict_w:
  266. continue
  267. if len(slot_names) == 1:
  268. func = getattr(pto, slot_names[0])
  269. else:
  270. assert len(slot_names) == 2
  271. struct = getattr(pto, slot_names[0])
  272. if not struct:
  273. continue
  274. func = getattr(struct, slot_names[1])
  275. func_voidp = rffi.cast(rffi.VOIDP, func)
  276. if not func:
  277. continue
  278. if wrapper_func is None and wrapper_func_kwds is None:
  279. continue
  280. dict_w[method_name] = PyDescr_NewWrapper(space, pto, method_name, wrapper_func,
  281. wrapper_func_kwds, doc, func_voidp)
  282. if pto.c_tp_new:
  283. add_tp_new_wrapper(space, dict_w, pto)
  284. @cpython_api([PyObject, PyObject, PyObject], PyObject, header=None)
  285. def tp_new_wrapper(space, self, w_args, w_kwds):
  286. self_pytype = rffi.cast(PyTypeObjectPtr, self)
  287. tp_new = self_pytype.c_tp_new
  288. # Check that the user doesn't do something silly and unsafe like
  289. # object.__new__(dict). To do this, we check that the most
  290. # derived base that's not a heap type is this type.
  291. # XXX do it
  292. args_w = space.fixedview(w_args)
  293. w_subtype = args_w[0]
  294. w_args = space.newtuple(args_w[1:])
  295. if not space.is_true(w_kwds):
  296. w_kwds = None
  297. try:
  298. subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
  299. w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
  300. finally:
  301. Py_DecRef(space, w_subtype)
  302. return w_obj
  303. @specialize.memo()
  304. def get_new_method_def(space):
  305. state = space.fromcache(State)
  306. if state.new_method_def:
  307. return state.new_method_def
  308. ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
  309. immortal=True)
  310. ptr.c_ml_name = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp("__new__"))
  311. lltype.render_immortal(ptr.c_ml_name)
  312. rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
  313. ptr.c_ml_doc = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp(
  314. "T.__new__(S, ...) -> a new object with type S, a subtype of T"))
  315. lltype.render_immortal(ptr.c_ml_doc)
  316. state.new_method_def = ptr
  317. return ptr
  318. def setup_new_method_def(space):
  319. ptr = get_new_method_def(space)
  320. ptr.c_ml_meth = rffi.cast(PyCFunction_typedef,
  321. llhelper(tp_new_wrapper.api_func.functype,
  322. tp_new_wrapper.api_func.get_wrapper(space)))
  323. def add_tp_new_wrapper(space, dict_w, pto):
  324. if "__new__" in dict_w:
  325. return
  326. pyo = rffi.cast(PyObject, pto)
  327. dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
  328. from_ref(space, pyo), None)
  329. def inherit_special(space, pto, base_pto):
  330. # XXX missing: copy basicsize and flags in a magical way
  331. # (minimally, if tp_basicsize is zero we copy it from the base)
  332. if not pto.c_tp_basicsize:
  333. pto.c_tp_basicsize = base_pto.c_tp_basicsize
  334. flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
  335. base_object_pyo = make_ref(space, space.w_object)
  336. base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
  337. if base_pto != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE:
  338. if not pto.c_tp_new:
  339. pto.c_tp_new = base_pto.c_tp_new
  340. Py_DecRef(space, base_object_pyo)
  341. def check_descr(space, w_self, w_type):
  342. if not space.isinstance_w(w_self, w_type):
  343. raise DescrMismatch()
  344. class GettersAndSetters:
  345. def getter(self, space, w_self):
  346. assert isinstance(self, W_GetSetPropertyEx)
  347. check_descr(space, w_self, self.w_type)
  348. return generic_cpy_call(
  349. space, self.getset.c_get, w_self,
  350. self.getset.c_closure)
  351. def setter(self, space, w_self, w_value):
  352. assert isinstance(self, W_GetSetPropertyEx)
  353. check_descr(space, w_self, self.w_type)
  354. res = generic_cpy_call(
  355. space, self.getset.c_set, w_self, w_value,
  356. self.getset.c_closure)
  357. if rffi.cast(lltype.Signed, res) < 0:
  358. state = space.fromcache(State)
  359. state.check_and_raise_exception()
  360. def member_getter(self, space, w_self):
  361. assert isinstance(self, W_MemberDescr)
  362. check_descr(space, w_self, self.w_type)
  363. pyref = make_ref(space, w_self)
  364. try:
  365. return PyMember_GetOne(
  366. space, rffi.cast(rffi.CCHARP, pyref), self.member)
  367. finally:
  368. Py_DecRef(space, pyref)
  369. def member_delete(self, space, w_self):
  370. assert isinstance(self, W_MemberDescr)
  371. check_descr(space, w_self, self.w_type)
  372. pyref = make_ref(space, w_self)
  373. try:
  374. PyMember_SetOne(
  375. space, rffi.cast(rffi.CCHARP, pyref), self.member, None)
  376. finally:
  377. Py_DecRef(space, pyref)
  378. def member_setter(self, space, w_self, w_value):
  379. assert isinstance(self, W_MemberDescr)
  380. check_descr(space, w_self, self.w_type)
  381. pyref = make_ref(space, w_self)
  382. try:
  383. PyMember_SetOne(
  384. space, rffi.cast(rffi.CCHARP, pyref), self.member, w_value)
  385. finally:
  386. Py_DecRef(space, pyref)
  387. class W_PyCTypeObject(W_TypeObject):
  388. @jit.dont_look_inside
  389. def __init__(self, space, pto):
  390. bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
  391. dict_w = {}
  392. add_operators(space, dict_w, pto)
  393. convert_method_defs(space, dict_w, pto.c_tp_methods, self)
  394. convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
  395. convert_member_defs(space, dict_w, pto.c_tp_members, self)
  396. name = rffi.charp2str(pto.c_tp_name)
  397. new_layout = (pto.c_tp_basicsize > rffi.sizeof(PyObject.TO) or
  398. pto.c_tp_itemsize > 0)
  399. W_TypeObject.__init__(self, space, name,
  400. bases_w or [space.w_object], dict_w, force_new_layout=new_layout)
  401. self.flag_cpytype = True
  402. self.flag_heaptype = False
  403. # if a sequence or a mapping, then set the flag to force it
  404. if pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_item:
  405. self.flag_map_or_seq = 'S'
  406. elif (pto.c_tp_as_mapping and pto.c_tp_as_mapping.c_mp_subscript and
  407. not (pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_slice)):
  408. self.flag_map_or_seq = 'M'
  409. if pto.c_tp_doc:
  410. self.w_doc = space.wrap(rffi.charp2str(pto.c_tp_doc))
  411. @bootstrap_function
  412. def init_typeobject(space):
  413. make_typedescr(space.w_type.layout.typedef,
  414. basestruct=PyTypeObject,
  415. alloc=type_alloc,
  416. attach=type_attach,
  417. realize=type_realize,
  418. dealloc=type_dealloc)
  419. @cpython_api([PyObject], lltype.Void, header=None)
  420. def subtype_dealloc(space, obj):
  421. pto = obj.c_ob_type
  422. base = pto
  423. this_func_ptr = llhelper(subtype_dealloc.api_func.functype,
  424. subtype_dealloc.api_func.get_wrapper(space))
  425. while base.c_tp_dealloc == this_func_ptr:
  426. base = base.c_tp_base
  427. assert base
  428. dealloc = base.c_tp_dealloc
  429. # XXX call tp_del if necessary
  430. generic_cpy_call(space, dealloc, obj)
  431. # XXX cpy decrefs the pto here but we do it in the base-dealloc
  432. # hopefully this does not clash with the memory model assumed in
  433. # extension modules
  434. @cpython_api([PyObject, Py_ssize_tP], lltype.Signed, header=None,
  435. error=CANNOT_FAIL)
  436. def bf_segcount(space, w_obj, ref):
  437. if ref:
  438. ref[0] = space.len_w(w_obj)
  439. return 1
  440. @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
  441. header=None, error=-1)
  442. def bf_getreadbuffer(space, w_buf, segment, ref):
  443. if segment != 0:
  444. raise oefmt(space.w_SystemError,
  445. "accessing non-existent segment")
  446. buf = space.readbuf_w(w_buf)
  447. address = buf.get_raw_address()
  448. ref[0] = address
  449. return len(buf)
  450. @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
  451. header=None, error=-1)
  452. def bf_getcharbuffer(space, w_buf, segment, ref):
  453. return bf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
  454. @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
  455. header=None, error=-1)
  456. def bf_getwritebuffer(space, w_buf, segment, ref):
  457. if segment != 0:
  458. raise oefmt(space.w_SystemError,
  459. "accessing non-existent segment")
  460. buf = space.writebuf_w(w_buf)
  461. ref[0] = buf.get_raw_address()
  462. return len(buf)
  463. @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
  464. header=None, error=-1)
  465. def str_getreadbuffer(space, w_str, segment, ref):
  466. from pypy.module.cpyext.bytesobject import PyString_AsString
  467. if segment != 0:
  468. raise oefmt(space.w_SystemError,
  469. "accessing non-existent string segment")
  470. pyref = make_ref(space, w_str)
  471. ref[0] = PyString_AsString(space, pyref)
  472. # Stolen reference: the object has better exist somewhere else
  473. Py_DecRef(space, pyref)
  474. return space.len_w(w_str)
  475. @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
  476. header=None, error=-1)
  477. def str_getcharbuffer(space, w_buf, segment, ref):
  478. return str_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
  479. @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
  480. header=None, error=-1)
  481. def buf_getreadbuffer(space, pyref, segment, ref):
  482. from pypy.module.cpyext.bufferobject import PyBufferObject
  483. if segment != 0:
  484. raise oefmt(space.w_SystemError,
  485. "accessing non-existent buffer segment")
  486. py_buf = rffi.cast(PyBufferObject, pyref)
  487. ref[0] = py_buf.c_b_ptr
  488. return py_buf.c_b_size
  489. @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
  490. header=None, error=-1)
  491. def buf_getcharbuffer(space, w_buf, segment, ref):
  492. return buf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
  493. def setup_buffer_procs(space, w_type, pto):
  494. bufspec = w_type.layout.typedef.buffer
  495. if bufspec is None:
  496. # not a buffer
  497. return
  498. c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
  499. lltype.render_immortal(c_buf)
  500. c_buf.c_bf_getsegcount = llhelper(bf_segcount.api_func.functype,
  501. bf_segcount.api_func.get_wrapper(space))
  502. if space.is_w(w_type, space.w_str):
  503. # Special case: str doesn't support get_raw_address(), so we have a
  504. # custom get*buffer that instead gives the address of the char* in the
  505. # PyStringObject*!
  506. c_buf.c_bf_getreadbuffer = llhelper(
  507. str_getreadbuffer.api_func.functype,
  508. str_getreadbuffer.api_func.get_wrapper(space))
  509. c_buf.c_bf_getcharbuffer = llhelper(
  510. str_getcharbuffer.api_func.functype,
  511. str_getcharbuffer.api_func.get_wrapper(space))
  512. elif space.is_w(w_type, space.w_buffer):
  513. # Special case: we store a permanent address on the cpyext wrapper,
  514. # so we'll reuse that.
  515. # Note: we could instead store a permanent address on the buffer object,
  516. # and use get_raw_address()
  517. c_buf.c_bf_getreadbuffer = llhelper(
  518. buf_getreadbuffer.api_func.functype,
  519. buf_getreadbuffer.api_func.get_wrapper(space))
  520. c_buf.c_bf_getcharbuffer = llhelper(
  521. buf_getcharbuffer.api_func.functype,
  522. buf_getcharbuffer.api_func.get_wrapper(space))
  523. else:
  524. # use get_raw_address()
  525. c_buf.c_bf_getreadbuffer = llhelper(bf_getreadbuffer.api_func.functype,
  526. bf_getreadbuffer.api_func.get_wrapper(space))
  527. c_buf.c_bf_getcharbuffer = llhelper(bf_getcharbuffer.api_func.functype,
  528. bf_getcharbuffer.api_func.get_wrapper(space))
  529. if bufspec == 'read-write':
  530. c_buf.c_bf_getwritebuffer = llhelper(
  531. bf_getwritebuffer.api_func.functype,
  532. bf_getwritebuffer.api_func.get_wrapper(space))
  533. pto.c_tp_as_buffer = c_buf
  534. pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
  535. @cpython_api([PyObject], lltype.Void, header=None)
  536. def type_dealloc(space, obj):
  537. from pypy.module.cpyext.object import PyObject_dealloc
  538. obj_pto = rffi.cast(PyTypeObjectPtr, obj)
  539. base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
  540. Py_DecRef(space, obj_pto.c_tp_bases)
  541. Py_DecRef(space, obj_pto.c_tp_mro)
  542. Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
  543. Py_DecRef(space, obj_pto.c_tp_dict)
  544. if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
  545. heaptype = rffi.cast(PyHeapTypeObject, obj)
  546. Py_DecRef(space, heaptype.c_ht_name)
  547. Py_DecRef(space, base_pyo)
  548. PyObject_dealloc(space, obj)
  549. def type_alloc(space, w_metatype, itemsize=0):
  550. metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype))
  551. # Don't increase refcount for non-heaptypes
  552. if metatype:
  553. flags = rffi.cast(lltype.Signed, metatype.c_tp_flags)
  554. if not flags & Py_TPFLAGS_HEAPTYPE:
  555. Py_DecRef(space, w_metatype)
  556. heaptype = lltype.malloc(PyHeapTypeObject.TO,
  557. flavor='raw', zero=True,
  558. add_memory_pressure=True)
  559. pto = heaptype.c_ht_type
  560. pto.c_ob_refcnt = 1
  561. pto.c_ob_pypy_link = 0
  562. pto.c_ob_type = metatype
  563. pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
  564. pto.c_tp_as_number = heaptype.c_as_number
  565. pto.c_tp_as_sequence = heaptype.c_as_sequence
  566. pto.c_tp_as_mapping = heaptype.c_as_mapping
  567. pto.c_tp_as_buffer = heaptype.c_as_buffer
  568. pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
  569. pto.c_tp_itemsize = 0
  570. return rffi.cast(PyObject, heaptype)
  571. def type_attach(space, py_obj, w_type):
  572. """
  573. Fills a newly allocated PyTypeObject from an existing type.
  574. """
  575. from pypy.module.cpyext.object import PyObject_Free
  576. assert isinstance(w_type, W_TypeObject)
  577. pto = rffi.cast(PyTypeObjectPtr, py_obj)
  578. typedescr = get_typedescr(w_type.layout.typedef)
  579. # dealloc
  580. if space.gettypeobject(w_type.layout.typedef) is w_type:
  581. # only for the exact type, like 'space.w_tuple' or 'space.w_list'
  582. pto.c_tp_dealloc = typedescr.get_dealloc(space)
  583. else:
  584. # for all subtypes, use subtype_dealloc()
  585. pto.c_tp_dealloc = llhelper(
  586. subtype_dealloc.api_func.functype,
  587. subtype_dealloc.api_func.get_wrapper(space))
  588. # buffer protocol
  589. setup_buffer_procs(space, w_type, pto)
  590. pto.c_tp_free = llhelper(PyObject_Free.api_func.functype,
  591. PyObject_Free.api_func.get_wrapper(space))
  592. pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype,
  593. PyType_GenericAlloc.api_func.get_wrapper(space))
  594. builder = space.fromcache(StaticObjectBuilder)
  595. if ((pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE) != 0
  596. and builder.cpyext_type_init is None):
  597. # this ^^^ is not None only during startup of cpyext. At that
  598. # point we might get into troubles by doing make_ref() when
  599. # things are not initialized yet. So in this case, simply use
  600. # str2charp() and "leak" the string.
  601. w_typename = space.getattr(w_type, space.wrap('__name__'))
  602. heaptype = rffi.cast(PyHeapTypeObject, pto)
  603. heaptype.c_ht_name = make_ref(space, w_typename)
  604. from pypy.module.cpyext.bytesobject import PyString_AsString
  605. pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name)
  606. else:
  607. pto.c_tp_name = rffi.str2charp(w_type.name)
  608. # uninitialized fields:
  609. # c_tp_print
  610. # XXX implement
  611. # c_tp_compare and the following fields (see http://docs.python.org/c-api/typeobj.html )
  612. w_base = best_base(space, w_type.bases_w)
  613. pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))
  614. if builder.cpyext_type_init is not None:
  615. builder.cpyext_type_init.append((pto, w_type))
  616. else:
  617. finish_type_1(space, pto)
  618. finish_type_2(space, pto, w_type)
  619. pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
  620. if pto.c_tp_base:
  621. if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
  622. pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
  623. # will be filled later on with the correct value
  624. # may not be 0
  625. if space.is_w(w_type, space.w_object):
  626. pto.c_tp_new = rffi.cast(newfunc, 1)
  627. update_all_slots(space, w_type, pto)
  628. pto.c_tp_flags |= Py_TPFLAGS_READY
  629. return pto
  630. def py_type_ready(space, pto):
  631. if pto.c_tp_flags & Py_TPFLAGS_READY:
  632. return
  633. type_realize(space, rffi.cast(PyObject, pto))
  634. @cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
  635. def PyType_Ready(space, pto):
  636. py_type_ready(space, pto)
  637. return 0
  638. def type_realize(space, py_obj):
  639. pto = rffi.cast(PyTypeObjectPtr, py_obj)
  640. assert pto.c_tp_flags & Py_TPFLAGS_READY == 0
  641. assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
  642. pto.c_tp_flags |= Py_TPFLAGS_READYING
  643. try:
  644. w_obj = _type_realize(space, py_obj)
  645. finally:
  646. pto.c_tp_flags &= ~Py_TPFLAGS_READYING
  647. pto.c_tp_flags |= Py_TPFLAGS_READY
  648. return w_obj
  649. def solid_base(space, w_type):
  650. typedef = w_type.layout.typedef
  651. return space.gettypeobject(typedef)
  652. def best_base(space, bases_w):
  653. if not bases_w:
  654. return None
  655. return find_best_base(bases_w)
  656. def inherit_slots(space, pto, w_base):
  657. # XXX missing: nearly everything
  658. base_pyo = make_ref(space, w_base)
  659. try:
  660. base = rffi.cast(PyTypeObjectPtr, base_pyo)
  661. if not pto.c_tp_dealloc:
  662. pto.c_tp_dealloc = base.c_tp_dealloc
  663. if not pto.c_tp_init:
  664. pto.c_tp_init = base.c_tp_init
  665. if not pto.c_tp_alloc:
  666. pto.c_tp_alloc = base.c_tp_alloc
  667. # XXX check for correct GC flags!
  668. if not pto.c_tp_free:
  669. pto.c_tp_free = base.c_tp_free
  670. if not pto.c_tp_setattro:
  671. pto.c_tp_setattro = base.c_tp_setattro
  672. if not pto.c_tp_getattro:
  673. pto.c_tp_getattro = base.c_tp_getattro
  674. finally:
  675. Py_DecRef(space, base_pyo)
  676. def _type_realize(space, py_obj):
  677. """
  678. Creates an interpreter type from a PyTypeObject structure.
  679. """
  680. # missing:
  681. # unsupported:
  682. # tp_mro, tp_subclasses
  683. py_type = rffi.cast(PyTypeObjectPtr, py_obj)
  684. if not py_type.c_tp_base:
  685. # borrowed reference, but w_object is unlikely to disappear
  686. base = as_pyobj(space, space.w_object)
  687. py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
  688. finish_type_1(space, py_type)
  689. if py_type.c_ob_type:
  690. w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
  691. else:
  692. # Somehow the tp_base type is created with no ob_type, notably
  693. # PyString_Type and PyBaseString_Type
  694. # While this is a hack, cpython does it as well.
  695. w_metatype = space.w_type
  696. w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
  697. track_reference(space, py_obj, w_obj)
  698. w_obj.__init__(space, py_type)
  699. w_obj.ready()
  700. finish_type_2(space, py_type, w_obj)
  701. # inheriting tp_as_* slots
  702. base = py_type.c_tp_base
  703. if base:
  704. if not py_type.c_tp_as_number: py_type.c_tp_as_number = base.c_tp_as_number
  705. if not py_type.c_tp_as_sequence: py_type.c_tp_as_sequence = base.c_tp_as_sequence
  706. if not py_type.c_tp_as_mapping: py_type.c_tp_as_mapping = base.c_tp_as_mapping
  707. if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = base.c_tp_as_buffer
  708. return w_obj
  709. def finish_type_1(space, pto):
  710. """
  711. Sets up tp_bases, necessary before creating the interpreter type.
  712. """
  713. base = pto.c_tp_base
  714. base_pyo = rffi.cast(PyObject, pto.c_tp_base)
  715. if base and not base.c_tp_flags & Py_TPFLAGS_READY:
  716. type_realize(space, rffi.cast(PyObject, base_pyo))
  717. if base and not pto.c_ob_type: # will be filled later
  718. pto.c_ob_type = base.c_ob_type
  719. if not pto.c_tp_bases:
  720. if not base:
  721. bases = space.newtuple([])
  722. else:
  723. bases = space.newtuple([from_ref(space, base_pyo)])
  724. pto.c_tp_bases = make_ref(space, bases)
  725. def finish_type_2(space, pto, w_obj):
  726. """
  727. Sets up other attributes, when the interpreter type has been created.
  728. """
  729. pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w))
  730. base = pto.c_tp_base
  731. if base:
  732. inherit_special(space, pto, base)
  733. for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
  734. inherit_slots(space, pto, w_base)
  735. if not pto.c_tp_setattro:
  736. from pypy.module.cpyext.object import PyObject_GenericSetAttr
  737. pto.c_tp_setattro = llhelper(
  738. PyObject_GenericSetAttr.api_func.functype,
  739. PyObject_GenericSetAttr.api_func.get_wrapper(space))
  740. if not pto.c_tp_getattro:
  741. from pypy.module.cpyext.object import PyObject_GenericGetAttr
  742. pto.c_tp_getattro = llhelper(
  743. PyObject_GenericGetAttr.api_func.functype,
  744. PyObject_GenericGetAttr.api_func.get_wrapper(space))
  745. if w_obj.is_cpytype():
  746. Py_DecRef(space, pto.c_tp_dict)
  747. w_dict = w_obj.getdict(space)
  748. pto.c_tp_dict = make_ref(space, w_dict)
  749. @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
  750. def PyType_IsSubtype(space, a, b):
  751. """Return true if a is a subtype of b.
  752. """
  753. w_type1 = from_ref(space, rffi.cast(PyObject, a))
  754. w_type2 = from_ref(space, rffi.cast(PyObject, b))
  755. return int(abstract_issubclass_w(space, w_type1, w_type2)) #XXX correct?
  756. @cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject, result_is_ll=True)
  757. def PyType_GenericAlloc(space, type, nitems):
  758. from pypy.module.cpyext.object import _PyObject_NewVar
  759. return _PyObject_NewVar(space, type, nitems)
  760. @cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject)
  761. def PyType_GenericNew(space, type, w_args, w_kwds):
  762. return generic_cpy_call(
  763. space, type.c_tp_alloc, type, 0)
  764. @cpython_api([PyTypeObjectPtr, PyObject], PyObject, error=CANNOT_FAIL,
  765. result_borrowed=True)
  766. def _PyType_Lookup(space, type, w_name):
  767. """Internal API to look for a name through the MRO.
  768. This returns a borrowed reference, and doesn't set an exception!"""
  769. w_type = from_ref(space, rffi.cast(PyObject, type))
  770. assert isinstance(w_type, W_TypeObject)
  771. if not space.isinstance_w(w_name, space.w_str):
  772. return None
  773. name = space.str_w(w_name)
  774. w_obj = w_type.lookup(name)
  775. # this assumes that w_obj is not dynamically created, but will stay alive
  776. # until w_type is modified or dies. Assuming this, we return a borrowed ref
  777. return w_obj
  778. @cpython_api([PyTypeObjectPtr], lltype.Void)
  779. def PyType_Modified(space, w_obj):
  780. """Invalidate the internal lookup cache for the type and all of its
  781. subtypes. This function must be called after any manual
  782. modification of the attributes or base classes of the type.
  783. """
  784. # Invalidate the type cache in case of a builtin type.
  785. if not isinstance(w_obj, W_TypeObject):
  786. return
  787. if w_obj.is_cpytype():
  788. w_obj.mutated(None)