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

/pypy/module/_cffi_backend/func.py

https://bitbucket.org/pypy/pypy/
Python | 273 lines | 222 code | 34 blank | 17 comment | 17 complexity | 3482842bfe0ecbfb173df3fd5617ad58 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.rtyper.annlowlevel import llstr
  2. from rpython.rtyper.lltypesystem import lltype, rffi
  3. from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
  4. from rpython.rlib.objectmodel import keepalive_until_here, we_are_translated
  5. from rpython.rlib import jit
  6. from pypy.interpreter.error import OperationError, oefmt
  7. from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
  8. from pypy.module._cffi_backend import ctypeobj, cdataobj, allocator
  9. # ____________________________________________________________
  10. @unwrap_spec(w_ctype=ctypeobj.W_CType, w_init=WrappedDefault(None))
  11. def newp(space, w_ctype, w_init):
  12. return w_ctype.newp(w_init, allocator.default_allocator)
  13. # ____________________________________________________________
  14. @unwrap_spec(w_ctype=ctypeobj.W_CType)
  15. def cast(space, w_ctype, w_ob):
  16. return w_ctype.cast(w_ob)
  17. # ____________________________________________________________
  18. @unwrap_spec(w_ctype=ctypeobj.W_CType)
  19. def callback(space, w_ctype, w_callable, w_error=None, w_onerror=None):
  20. from pypy.module._cffi_backend.ccallback import make_callback
  21. return make_callback(space, w_ctype, w_callable, w_error, w_onerror)
  22. # ____________________________________________________________
  23. @unwrap_spec(w_cdata=cdataobj.W_CData)
  24. def typeof(space, w_cdata):
  25. return w_cdata.ctype
  26. # ____________________________________________________________
  27. def sizeof(space, w_obj):
  28. if isinstance(w_obj, cdataobj.W_CData):
  29. size = w_obj._sizeof()
  30. elif isinstance(w_obj, ctypeobj.W_CType):
  31. size = w_obj.size
  32. if size < 0:
  33. raise oefmt(space.w_ValueError,
  34. "ctype '%s' is of unknown size", w_obj.name)
  35. else:
  36. raise oefmt(space.w_TypeError, "expected a 'cdata' or 'ctype' object")
  37. return space.wrap(size)
  38. @unwrap_spec(w_ctype=ctypeobj.W_CType)
  39. def alignof(space, w_ctype):
  40. align = w_ctype.alignof()
  41. return space.wrap(align)
  42. @unwrap_spec(w_ctype=ctypeobj.W_CType, following=int)
  43. def typeoffsetof(space, w_ctype, w_field_or_index, following=0):
  44. ctype, offset = w_ctype.direct_typeoffsetof(w_field_or_index, following)
  45. return space.newtuple([space.wrap(ctype), space.wrap(offset)])
  46. @unwrap_spec(w_ctype=ctypeobj.W_CType, w_cdata=cdataobj.W_CData, offset=int)
  47. def rawaddressof(space, w_ctype, w_cdata, offset):
  48. return w_ctype.rawaddressof(w_cdata, offset)
  49. # ____________________________________________________________
  50. @unwrap_spec(w_ctype=ctypeobj.W_CType, replace_with=str)
  51. def getcname(space, w_ctype, replace_with):
  52. p = w_ctype.name_position
  53. s = '%s%s%s' % (w_ctype.name[:p], replace_with, w_ctype.name[p:])
  54. return space.wrap(s)
  55. # ____________________________________________________________
  56. @unwrap_spec(w_cdata=cdataobj.W_CData, maxlen=int)
  57. def string(space, w_cdata, maxlen=-1):
  58. return w_cdata.ctype.string(w_cdata, maxlen)
  59. # ____________________________________________________________
  60. @unwrap_spec(w_cdata=cdataobj.W_CData, length=int)
  61. def unpack(space, w_cdata, length):
  62. return w_cdata.unpack(length)
  63. # ____________________________________________________________
  64. def _get_types(space):
  65. return space.newtuple([space.gettypefor(cdataobj.W_CData),
  66. space.gettypefor(ctypeobj.W_CType)])
  67. # ____________________________________________________________
  68. def _get_common_types(space, w_dict):
  69. from pypy.module._cffi_backend.parse_c_type import ll_enum_common_types
  70. index = 0
  71. while True:
  72. p = ll_enum_common_types(rffi.cast(rffi.INT, index))
  73. if not p:
  74. break
  75. key = rffi.charp2str(p)
  76. value = rffi.charp2str(rffi.ptradd(p, len(key) + 1))
  77. space.setitem_str(w_dict, key, space.wrap(value))
  78. index += 1
  79. # ____________________________________________________________
  80. def _fetch_as_read_buffer(space, w_x):
  81. # xxx do we really need to implement the same mess as in CPython 2.7
  82. # w.r.t. buffers and memoryviews??
  83. try:
  84. buf = space.readbuf_w(w_x)
  85. except OperationError as e:
  86. if not e.match(space, space.w_TypeError):
  87. raise
  88. buf = space.buffer_w(w_x, space.BUF_SIMPLE)
  89. return buf
  90. def _fetch_as_write_buffer(space, w_x):
  91. try:
  92. buf = space.writebuf_w(w_x)
  93. except OperationError as e:
  94. if not e.match(space, space.w_TypeError):
  95. raise
  96. buf = space.buffer_w(w_x, space.BUF_WRITABLE)
  97. return buf
  98. @unwrap_spec(w_ctype=ctypeobj.W_CType)
  99. def from_buffer(space, w_ctype, w_x):
  100. from pypy.module._cffi_backend import ctypearray, ctypeprim
  101. #
  102. if (not isinstance(w_ctype, ctypearray.W_CTypeArray) or
  103. not isinstance(w_ctype.ctptr.ctitem, ctypeprim.W_CTypePrimitiveChar)):
  104. raise oefmt(space.w_TypeError,
  105. "needs 'char[]', got '%s'", w_ctype.name)
  106. #
  107. return _from_buffer(space, w_ctype, w_x)
  108. def _from_buffer(space, w_ctype, w_x):
  109. buf = _fetch_as_read_buffer(space, w_x)
  110. if space.isinstance_w(w_x, space.w_str):
  111. _cdata = get_raw_address_of_string(space, w_x)
  112. else:
  113. try:
  114. _cdata = buf.get_raw_address()
  115. except ValueError:
  116. raise oefmt(space.w_TypeError,
  117. "from_buffer() got a '%T' object, which supports the "
  118. "buffer interface but cannot be rendered as a plain "
  119. "raw address on PyPy", w_x)
  120. #
  121. return cdataobj.W_CDataFromBuffer(space, _cdata, w_ctype, buf, w_x)
  122. # ____________________________________________________________
  123. class RawBytes(object):
  124. def __init__(self, string):
  125. self.ptr = rffi.str2charp(string, track_allocation=False)
  126. def __del__(self):
  127. rffi.free_charp(self.ptr, track_allocation=False)
  128. class RawBytesCache(object):
  129. def __init__(self, space):
  130. from pypy.interpreter.baseobjspace import W_Root
  131. from rpython.rlib import rweakref
  132. self.wdict = rweakref.RWeakKeyDictionary(W_Root, RawBytes)
  133. @jit.dont_look_inside
  134. def get_raw_address_of_string(space, w_x):
  135. """Special case for ffi.from_buffer(string). Returns a 'char *' that
  136. is valid as long as the string object is alive. Two calls to
  137. ffi.from_buffer(same_string) are guaranteed to return the same pointer.
  138. """
  139. from rpython.rtyper.annlowlevel import llstr
  140. from rpython.rtyper.lltypesystem.rstr import STR
  141. from rpython.rtyper.lltypesystem import llmemory
  142. from rpython.rlib import rgc
  143. cache = space.fromcache(RawBytesCache)
  144. rawbytes = cache.wdict.get(w_x)
  145. if rawbytes is None:
  146. data = space.str_w(w_x)
  147. if we_are_translated() and not rgc.can_move(data):
  148. lldata = llstr(data)
  149. data_start = (llmemory.cast_ptr_to_adr(lldata) +
  150. rffi.offsetof(STR, 'chars') +
  151. llmemory.itemoffsetof(STR.chars, 0))
  152. data_start = rffi.cast(rffi.CCHARP, data_start)
  153. data_start[len(data)] = '\x00' # write the final extra null
  154. return data_start
  155. rawbytes = RawBytes(data)
  156. cache.wdict.set(w_x, rawbytes)
  157. return rawbytes.ptr
  158. # ____________________________________________________________
  159. def unsafe_escaping_ptr_for_ptr_or_array(w_cdata):
  160. if not w_cdata.ctype.is_nonfunc_pointer_or_array:
  161. raise oefmt(w_cdata.space.w_TypeError,
  162. "expected a pointer or array ctype, got '%s'",
  163. w_cdata.ctype.name)
  164. return w_cdata.unsafe_escaping_ptr()
  165. c_memmove = rffi.llexternal('memmove', [rffi.CCHARP, rffi.CCHARP,
  166. rffi.SIZE_T], lltype.Void,
  167. _nowrapper=True)
  168. @unwrap_spec(n=int)
  169. def memmove(space, w_dest, w_src, n):
  170. if n < 0:
  171. raise oefmt(space.w_ValueError, "negative size")
  172. # cases...
  173. src_buf = None
  174. src_data = lltype.nullptr(rffi.CCHARP.TO)
  175. if isinstance(w_src, cdataobj.W_CData):
  176. src_data = unsafe_escaping_ptr_for_ptr_or_array(w_src)
  177. src_is_ptr = True
  178. else:
  179. src_buf = _fetch_as_read_buffer(space, w_src)
  180. try:
  181. src_data = src_buf.get_raw_address()
  182. src_is_ptr = True
  183. except ValueError:
  184. src_is_ptr = False
  185. if src_is_ptr:
  186. src_string = None
  187. else:
  188. if n == src_buf.getlength():
  189. src_string = src_buf.as_str()
  190. else:
  191. src_string = src_buf.getslice(0, n, 1, n)
  192. dest_buf = None
  193. dest_data = lltype.nullptr(rffi.CCHARP.TO)
  194. if isinstance(w_dest, cdataobj.W_CData):
  195. dest_data = unsafe_escaping_ptr_for_ptr_or_array(w_dest)
  196. dest_is_ptr = True
  197. else:
  198. dest_buf = _fetch_as_write_buffer(space, w_dest)
  199. try:
  200. dest_data = dest_buf.get_raw_address()
  201. dest_is_ptr = True
  202. except ValueError:
  203. dest_is_ptr = False
  204. if dest_is_ptr:
  205. if src_is_ptr:
  206. c_memmove(dest_data, src_data, rffi.cast(rffi.SIZE_T, n))
  207. else:
  208. copy_string_to_raw(llstr(src_string), dest_data, 0, n)
  209. else:
  210. # nowadays this case should be rare or impossible: as far as
  211. # I know, all common types implementing the *writable* buffer
  212. # interface now support get_raw_address()
  213. if src_is_ptr:
  214. for i in range(n):
  215. dest_buf.setitem(i, src_data[i])
  216. else:
  217. for i in range(n):
  218. dest_buf.setitem(i, src_string[i])
  219. keepalive_until_here(src_buf)
  220. keepalive_until_here(dest_buf)
  221. keepalive_until_here(w_src)
  222. keepalive_until_here(w_dest)
  223. # ____________________________________________________________
  224. @unwrap_spec(w_cdata=cdataobj.W_CData)
  225. def gcp(space, w_cdata, w_destructor):
  226. return w_cdata.with_gc(w_destructor)