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

/pypy/module/cpyext/pyobject.py

https://bitbucket.org/pypy/pypy/
Python | 342 lines | 257 code | 27 blank | 58 comment | 20 complexity | 793c5e8874adb6221033374113685497 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys
  2. from pypy.interpreter.error import OperationError, oefmt
  3. from pypy.interpreter.baseobjspace import W_Root, SpaceCache
  4. from rpython.rtyper.lltypesystem import rffi, lltype
  5. from rpython.rtyper.extregistry import ExtRegistryEntry
  6. from pypy.module.cpyext.api import (
  7. cpython_api, bootstrap_function, PyObject, PyObjectP, ADDR,
  8. CANNOT_FAIL, Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr, is_PyObject,
  9. INTERPLEVEL_API, PyVarObject)
  10. from pypy.module.cpyext.state import State
  11. from pypy.objspace.std.typeobject import W_TypeObject
  12. from pypy.objspace.std.objectobject import W_ObjectObject
  13. from rpython.rlib.objectmodel import specialize
  14. from rpython.rlib.objectmodel import keepalive_until_here
  15. from rpython.rtyper.annlowlevel import llhelper
  16. from rpython.rlib import rawrefcount
  17. #________________________________________________________
  18. # type description
  19. class BaseCpyTypedescr(object):
  20. basestruct = PyObject.TO
  21. W_BaseObject = W_ObjectObject
  22. def get_dealloc(self, space):
  23. from pypy.module.cpyext.typeobject import subtype_dealloc
  24. return llhelper(
  25. subtype_dealloc.api_func.functype,
  26. subtype_dealloc.api_func.get_wrapper(space))
  27. def allocate(self, space, w_type, itemcount=0):
  28. # similar to PyType_GenericAlloc?
  29. # except that it's not related to any pypy object.
  30. # this returns a PyObject with ob_refcnt == 1.
  31. pytype = as_pyobj(space, w_type)
  32. pytype = rffi.cast(PyTypeObjectPtr, pytype)
  33. assert pytype
  34. # Don't increase refcount for non-heaptypes
  35. flags = rffi.cast(lltype.Signed, pytype.c_tp_flags)
  36. if flags & Py_TPFLAGS_HEAPTYPE:
  37. Py_IncRef(space, w_type)
  38. if pytype:
  39. size = pytype.c_tp_basicsize
  40. else:
  41. size = rffi.sizeof(self.basestruct)
  42. if pytype.c_tp_itemsize:
  43. size += itemcount * pytype.c_tp_itemsize
  44. assert size >= rffi.sizeof(PyObject.TO)
  45. buf = lltype.malloc(rffi.VOIDP.TO, size,
  46. flavor='raw', zero=True,
  47. add_memory_pressure=True)
  48. pyobj = rffi.cast(PyObject, buf)
  49. if pytype.c_tp_itemsize:
  50. pyvarobj = rffi.cast(PyVarObject, pyobj)
  51. pyvarobj.c_ob_size = itemcount
  52. pyobj.c_ob_refcnt = 1
  53. #pyobj.c_ob_pypy_link should get assigned very quickly
  54. pyobj.c_ob_type = pytype
  55. return pyobj
  56. def attach(self, space, pyobj, w_obj):
  57. pass
  58. def realize(self, space, obj):
  59. w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
  60. try:
  61. w_obj = space.allocate_instance(self.W_BaseObject, w_type)
  62. except OperationError as e:
  63. if e.match(space, space.w_TypeError):
  64. raise oefmt(space.w_SystemError,
  65. "cpyext: don't know how to make a '%N' object "
  66. "from a PyObject",
  67. w_type)
  68. raise
  69. track_reference(space, obj, w_obj)
  70. return w_obj
  71. typedescr_cache = {}
  72. def make_typedescr(typedef, **kw):
  73. """NOT_RPYTHON
  74. basestruct: The basic structure to allocate
  75. alloc : allocate and basic initialization of a raw PyObject
  76. attach : Function called to tie a raw structure to a pypy object
  77. realize : Function called to create a pypy object from a raw struct
  78. dealloc : a cpython_api(header=None), similar to PyObject_dealloc
  79. """
  80. tp_basestruct = kw.pop('basestruct', PyObject.TO)
  81. tp_alloc = kw.pop('alloc', None)
  82. tp_attach = kw.pop('attach', None)
  83. tp_realize = kw.pop('realize', None)
  84. tp_dealloc = kw.pop('dealloc', None)
  85. assert not kw, "Extra arguments to make_typedescr"
  86. null_dealloc = lltype.nullptr(lltype.FuncType([PyObject], lltype.Void))
  87. class CpyTypedescr(BaseCpyTypedescr):
  88. basestruct = tp_basestruct
  89. if tp_alloc:
  90. def allocate(self, space, w_type, itemcount=0):
  91. return tp_alloc(space, w_type, itemcount)
  92. if tp_dealloc:
  93. def get_dealloc(self, space):
  94. return llhelper(
  95. tp_dealloc.api_func.functype,
  96. tp_dealloc.api_func.get_wrapper(space))
  97. if tp_attach:
  98. def attach(self, space, pyobj, w_obj):
  99. tp_attach(space, pyobj, w_obj)
  100. if tp_realize:
  101. def realize(self, space, ref):
  102. return tp_realize(space, ref)
  103. if typedef:
  104. CpyTypedescr.__name__ = "CpyTypedescr_%s" % (typedef.name,)
  105. typedescr_cache[typedef] = CpyTypedescr()
  106. @bootstrap_function
  107. def init_pyobject(space):
  108. from pypy.module.cpyext.object import PyObject_dealloc
  109. # typedescr for the 'object' type
  110. make_typedescr(space.w_object.layout.typedef,
  111. dealloc=PyObject_dealloc)
  112. # almost all types, which should better inherit from object.
  113. make_typedescr(None)
  114. @specialize.memo()
  115. def _get_typedescr_1(typedef):
  116. try:
  117. return typedescr_cache[typedef]
  118. except KeyError:
  119. if typedef.bases:
  120. return _get_typedescr_1(typedef.bases[0])
  121. return typedescr_cache[None]
  122. def get_typedescr(typedef):
  123. if typedef is None:
  124. return typedescr_cache[None]
  125. else:
  126. return _get_typedescr_1(typedef)
  127. #________________________________________________________
  128. # refcounted object support
  129. class InvalidPointerException(Exception):
  130. pass
  131. def create_ref(space, w_obj):
  132. """
  133. Allocates a PyObject, and fills its fields with info from the given
  134. interpreter object.
  135. """
  136. w_type = space.type(w_obj)
  137. pytype = rffi.cast(PyTypeObjectPtr, as_pyobj(space, w_type))
  138. typedescr = get_typedescr(w_obj.typedef)
  139. if pytype.c_tp_itemsize != 0:
  140. itemcount = space.len_w(w_obj) # PyBytesObject and subclasses
  141. else:
  142. itemcount = 0
  143. py_obj = typedescr.allocate(space, w_type, itemcount=itemcount)
  144. track_reference(space, py_obj, w_obj)
  145. #
  146. # py_obj.c_ob_refcnt should be exactly REFCNT_FROM_PYPY + 1 here,
  147. # and we want only REFCNT_FROM_PYPY, i.e. only count as attached
  148. # to the W_Root but not with any reference from the py_obj side.
  149. assert py_obj.c_ob_refcnt > rawrefcount.REFCNT_FROM_PYPY
  150. py_obj.c_ob_refcnt -= 1
  151. #
  152. typedescr.attach(space, py_obj, w_obj)
  153. return py_obj
  154. def track_reference(space, py_obj, w_obj):
  155. """
  156. Ties together a PyObject and an interpreter object.
  157. The PyObject's refcnt is increased by REFCNT_FROM_PYPY.
  158. The reference in 'py_obj' is not stolen! Remember to Py_DecRef()
  159. it is you need to.
  160. """
  161. # XXX looks like a PyObject_GC_TRACK
  162. assert py_obj.c_ob_refcnt < rawrefcount.REFCNT_FROM_PYPY
  163. py_obj.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY
  164. rawrefcount.create_link_pypy(w_obj, py_obj)
  165. def from_ref(space, ref):
  166. """
  167. Finds the interpreter object corresponding to the given reference. If the
  168. object is not yet realized (see bytesobject.py), creates it.
  169. """
  170. assert is_pyobj(ref)
  171. if not ref:
  172. return None
  173. w_obj = rawrefcount.to_obj(W_Root, ref)
  174. if w_obj is not None:
  175. return w_obj
  176. # This reference is not yet a real interpreter object.
  177. # Realize it.
  178. ref_type = rffi.cast(PyObject, ref.c_ob_type)
  179. if ref_type == ref: # recursion!
  180. raise InvalidPointerException(str(ref))
  181. w_type = from_ref(space, ref_type)
  182. assert isinstance(w_type, W_TypeObject)
  183. return get_typedescr(w_type.layout.typedef).realize(space, ref)
  184. def as_pyobj(space, w_obj):
  185. """
  186. Returns a 'PyObject *' representing the given intepreter object.
  187. This doesn't give a new reference, but the returned 'PyObject *'
  188. is valid at least as long as 'w_obj' is. **To be safe, you should
  189. use keepalive_until_here(w_obj) some time later.** In case of
  190. doubt, use the safer make_ref().
  191. """
  192. if w_obj is not None:
  193. assert not is_pyobj(w_obj)
  194. py_obj = rawrefcount.from_obj(PyObject, w_obj)
  195. if not py_obj:
  196. py_obj = create_ref(space, w_obj)
  197. return py_obj
  198. else:
  199. return lltype.nullptr(PyObject.TO)
  200. as_pyobj._always_inline_ = 'try'
  201. INTERPLEVEL_API['as_pyobj'] = as_pyobj
  202. def pyobj_has_w_obj(pyobj):
  203. return rawrefcount.to_obj(W_Root, pyobj) is not None
  204. INTERPLEVEL_API['pyobj_has_w_obj'] = staticmethod(pyobj_has_w_obj)
  205. def is_pyobj(x):
  206. if x is None or isinstance(x, W_Root):
  207. return False
  208. elif is_PyObject(lltype.typeOf(x)):
  209. return True
  210. else:
  211. raise TypeError(repr(type(x)))
  212. INTERPLEVEL_API['is_pyobj'] = staticmethod(is_pyobj)
  213. class Entry(ExtRegistryEntry):
  214. _about_ = is_pyobj
  215. def compute_result_annotation(self, s_x):
  216. from rpython.rtyper.llannotation import SomePtr
  217. return self.bookkeeper.immutablevalue(isinstance(s_x, SomePtr))
  218. def specialize_call(self, hop):
  219. hop.exception_cannot_occur()
  220. return hop.inputconst(lltype.Bool, hop.s_result.const)
  221. @specialize.ll()
  222. def make_ref(space, obj):
  223. """Increment the reference counter of the PyObject and return it.
  224. Can be called with either a PyObject or a W_Root.
  225. """
  226. if is_pyobj(obj):
  227. pyobj = rffi.cast(PyObject, obj)
  228. else:
  229. pyobj = as_pyobj(space, obj)
  230. if pyobj:
  231. assert pyobj.c_ob_refcnt > 0
  232. pyobj.c_ob_refcnt += 1
  233. if not is_pyobj(obj):
  234. keepalive_until_here(obj)
  235. return pyobj
  236. INTERPLEVEL_API['make_ref'] = make_ref
  237. @specialize.ll()
  238. def get_w_obj_and_decref(space, obj):
  239. """Decrement the reference counter of the PyObject and return the
  240. corresponding W_Root object (so the reference count is at least
  241. REFCNT_FROM_PYPY and cannot be zero). Can be called with either
  242. a PyObject or a W_Root.
  243. """
  244. if is_pyobj(obj):
  245. pyobj = rffi.cast(PyObject, obj)
  246. w_obj = from_ref(space, pyobj)
  247. else:
  248. w_obj = obj
  249. pyobj = as_pyobj(space, w_obj)
  250. if pyobj:
  251. pyobj.c_ob_refcnt -= 1
  252. assert pyobj.c_ob_refcnt >= rawrefcount.REFCNT_FROM_PYPY
  253. keepalive_until_here(w_obj)
  254. return w_obj
  255. INTERPLEVEL_API['get_w_obj_and_decref'] = get_w_obj_and_decref
  256. @specialize.ll()
  257. def incref(space, obj):
  258. make_ref(space, obj)
  259. INTERPLEVEL_API['incref'] = incref
  260. @specialize.ll()
  261. def decref(space, obj):
  262. if is_pyobj(obj):
  263. obj = rffi.cast(PyObject, obj)
  264. if obj:
  265. assert obj.c_ob_refcnt > 0
  266. obj.c_ob_refcnt -= 1
  267. if obj.c_ob_refcnt == 0:
  268. _Py_Dealloc(space, obj)
  269. else:
  270. get_w_obj_and_decref(space, obj)
  271. INTERPLEVEL_API['decref'] = decref
  272. @cpython_api([PyObject], lltype.Void)
  273. def Py_IncRef(space, obj):
  274. incref(space, obj)
  275. @cpython_api([PyObject], lltype.Void)
  276. def Py_DecRef(space, obj):
  277. decref(space, obj)
  278. @cpython_api([PyObject], lltype.Void)
  279. def _Py_NewReference(space, obj):
  280. obj.c_ob_refcnt = 1
  281. # XXX is it always useful to create the W_Root object here?
  282. w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
  283. assert isinstance(w_type, W_TypeObject)
  284. get_typedescr(w_type.layout.typedef).realize(space, obj)
  285. @cpython_api([PyObject], lltype.Void)
  286. def _Py_Dealloc(space, obj):
  287. from pypy.module.cpyext.api import generic_cpy_call
  288. pto = obj.c_ob_type
  289. #print >>sys.stderr, "Calling dealloc slot", pto.c_tp_dealloc, "of", obj, \
  290. # "'s type which is", rffi.charp2str(pto.c_tp_name)
  291. generic_cpy_call(space, pto.c_tp_dealloc, obj)
  292. @cpython_api([rffi.VOIDP], lltype.Signed, error=CANNOT_FAIL)
  293. def _Py_HashPointer(space, ptr):
  294. return rffi.cast(lltype.Signed, ptr)