PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/cpyext/typeobject.py

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