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

/pypy/objspace/std/marshal_impl.py

https://bitbucket.org/pypy/pypy/
Python | 427 lines | 342 code | 73 blank | 12 comment | 42 complexity | a118e8796e1488fba26208055b820e50 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_uint
  2. from rpython.rlib.rstring import StringBuilder
  3. from rpython.rlib.rstruct import ieee
  4. from rpython.rlib.unroll import unrolling_iterable
  5. from pypy.interpreter.error import OperationError, oefmt
  6. from pypy.interpreter.special import Ellipsis
  7. from pypy.interpreter.pycode import PyCode
  8. from pypy.interpreter import unicodehelper
  9. from pypy.objspace.std.boolobject import W_BoolObject
  10. from pypy.objspace.std.bytesobject import W_BytesObject
  11. from pypy.objspace.std.complexobject import W_ComplexObject
  12. from pypy.objspace.std.dictmultiobject import W_DictMultiObject
  13. from pypy.objspace.std.intobject import W_IntObject
  14. from pypy.objspace.std.floatobject import W_FloatObject
  15. from pypy.objspace.std.listobject import W_ListObject
  16. from pypy.objspace.std.longobject import W_AbstractLongObject
  17. from pypy.objspace.std.noneobject import W_NoneObject
  18. from pypy.objspace.std.setobject import W_FrozensetObject, W_SetObject
  19. from pypy.objspace.std.tupleobject import W_AbstractTupleObject
  20. from pypy.objspace.std.typeobject import W_TypeObject
  21. from pypy.objspace.std.unicodeobject import W_UnicodeObject
  22. TYPE_NULL = '0'
  23. TYPE_NONE = 'N'
  24. TYPE_FALSE = 'F'
  25. TYPE_TRUE = 'T'
  26. TYPE_STOPITER = 'S'
  27. TYPE_ELLIPSIS = '.'
  28. TYPE_INT = 'i'
  29. TYPE_INT64 = 'I'
  30. TYPE_FLOAT = 'f'
  31. TYPE_BINARY_FLOAT = 'g'
  32. TYPE_COMPLEX = 'x'
  33. TYPE_BINARY_COMPLEX = 'y'
  34. TYPE_LONG = 'l'
  35. TYPE_STRING = 's'
  36. TYPE_INTERNED = 't'
  37. TYPE_STRINGREF = 'R'
  38. TYPE_TUPLE = '('
  39. TYPE_LIST = '['
  40. TYPE_DICT = '{'
  41. TYPE_CODE = 'c'
  42. TYPE_UNICODE = 'u'
  43. TYPE_UNKNOWN = '?'
  44. TYPE_SET = '<'
  45. TYPE_FROZENSET = '>'
  46. _marshallers = []
  47. _unmarshallers = []
  48. def marshaller(type):
  49. def _decorator(f):
  50. _marshallers.append((type, f))
  51. return f
  52. return _decorator
  53. def unmarshaller(tc):
  54. def _decorator(f):
  55. _unmarshallers.append((tc, f))
  56. return f
  57. return _decorator
  58. def marshal(space, w_obj, m):
  59. # _marshallers_unroll is defined at the end of the file
  60. for type, func in _marshallers_unroll:
  61. if isinstance(w_obj, type):
  62. func(space, w_obj, m)
  63. return
  64. # any unknown object implementing the buffer protocol is
  65. # accepted and encoded as a plain string
  66. try:
  67. s = space.readbuf_w(w_obj)
  68. except OperationError as e:
  69. if e.match(space, space.w_TypeError):
  70. raise oefmt(space.w_ValueError, "unmarshallable object")
  71. raise
  72. m.atom_str(TYPE_STRING, s.as_str())
  73. def get_unmarshallers():
  74. return _unmarshallers
  75. @marshaller(W_NoneObject)
  76. def marshal_none(space, w_none, m):
  77. m.atom(TYPE_NONE)
  78. @unmarshaller(TYPE_NONE)
  79. def unmarshal_none(space, u, tc):
  80. return space.w_None
  81. @marshaller(W_BoolObject)
  82. def marshal_bool(space, w_bool, m):
  83. m.atom(TYPE_TRUE if w_bool.intval else TYPE_FALSE)
  84. @unmarshaller(TYPE_TRUE)
  85. def unmarshal_bool(space, u, tc):
  86. return space.w_True
  87. @unmarshaller(TYPE_FALSE)
  88. def unmarshal_false(space, u, tc):
  89. return space.w_False
  90. @marshaller(W_TypeObject)
  91. def marshal_stopiter(space, w_type, m):
  92. if not space.is_w(w_type, space.w_StopIteration):
  93. raise oefmt(space.w_ValueError, "unmarshallable object")
  94. m.atom(TYPE_STOPITER)
  95. @unmarshaller(TYPE_STOPITER)
  96. def unmarshal_stopiter(space, u, tc):
  97. return space.w_StopIteration
  98. @marshaller(Ellipsis)
  99. def marshal_ellipsis(space, w_ellipsis, m):
  100. m.atom(TYPE_ELLIPSIS)
  101. @unmarshaller(TYPE_ELLIPSIS)
  102. def unmarshal_ellipsis(space, u, tc):
  103. return space.w_Ellipsis
  104. @marshaller(W_IntObject)
  105. def marshal_int(space, w_int, m):
  106. if LONG_BIT == 32:
  107. m.atom_int(TYPE_INT, w_int.intval)
  108. else:
  109. y = w_int.intval >> 31
  110. if y and y != -1:
  111. m.atom_int64(TYPE_INT64, w_int.intval)
  112. else:
  113. m.atom_int(TYPE_INT, w_int.intval)
  114. @unmarshaller(TYPE_INT)
  115. def unmarshal_int(space, u, tc):
  116. return space.newint(u.get_int())
  117. @unmarshaller(TYPE_INT64)
  118. def unmarshal_int64(space, u, tc):
  119. lo = u.get_int() # get the first 32 bits
  120. hi = u.get_int() # get the next 32 bits
  121. if LONG_BIT >= 64:
  122. x = (hi << 32) | (lo & (2**32-1)) # result fits in an int
  123. else:
  124. x = (r_longlong(hi) << 32) | r_longlong(r_uint(lo)) # get a r_longlong
  125. return space.wrap(x)
  126. @marshaller(W_AbstractLongObject)
  127. def marshal_long(space, w_long, m):
  128. from rpython.rlib.rarithmetic import r_ulonglong
  129. m.start(TYPE_LONG)
  130. SHIFT = 15
  131. MASK = (1 << SHIFT) - 1
  132. num = w_long.asbigint()
  133. sign = num.sign
  134. num = num.abs()
  135. total_length = (num.bit_length() + (SHIFT - 1)) / SHIFT
  136. m.put_int(total_length * sign)
  137. bigshiftcount = r_ulonglong(0)
  138. for i in range(total_length):
  139. next = num.abs_rshift_and_mask(bigshiftcount, MASK)
  140. m.put_short(next)
  141. bigshiftcount += SHIFT
  142. @unmarshaller(TYPE_LONG)
  143. def unmarshal_long(space, u, tc):
  144. from rpython.rlib.rbigint import rbigint
  145. lng = u.get_int()
  146. if lng < 0:
  147. negative = True
  148. lng = -lng
  149. else:
  150. negative = False
  151. digits = [u.get_short() for i in range(lng)]
  152. result = rbigint.from_list_n_bits(digits, 15)
  153. if lng and not result.tobool():
  154. raise oefmt(space.w_ValueError, "bad marshal data")
  155. if negative:
  156. result = result.neg()
  157. return space.newlong_from_rbigint(result)
  158. def pack_float(f):
  159. result = StringBuilder(8)
  160. ieee.pack_float(result, f, 8, False)
  161. return result.build()
  162. def unpack_float(s):
  163. return ieee.unpack_float(s, False)
  164. @marshaller(W_FloatObject)
  165. def marshal_float(space, w_float, m):
  166. if m.version > 1:
  167. m.start(TYPE_BINARY_FLOAT)
  168. m.put(pack_float(w_float.floatval))
  169. else:
  170. m.start(TYPE_FLOAT)
  171. m.put_pascal(space.str_w(space.repr(w_float)))
  172. @unmarshaller(TYPE_FLOAT)
  173. def unmarshal_float(space, u, tc):
  174. return space.call_function(space.builtin.get('float'),
  175. space.wrap(u.get_pascal()))
  176. @unmarshaller(TYPE_BINARY_FLOAT)
  177. def unmarshal_float_bin(space, u, tc):
  178. return space.newfloat(unpack_float(u.get(8)))
  179. @marshaller(W_ComplexObject)
  180. def marshal_complex(space, w_complex, m):
  181. if m.version > 1:
  182. m.start(TYPE_BINARY_COMPLEX)
  183. m.put(pack_float(w_complex.realval))
  184. m.put(pack_float(w_complex.imagval))
  185. else:
  186. # XXX a bit too wrap-happy
  187. w_real = space.wrap(w_complex.realval)
  188. w_imag = space.wrap(w_complex.imagval)
  189. m.start(TYPE_COMPLEX)
  190. m.put_pascal(space.str_w(space.repr(w_real)))
  191. m.put_pascal(space.str_w(space.repr(w_imag)))
  192. @unmarshaller(TYPE_COMPLEX)
  193. def unmarshal_complex(space, u, tc):
  194. w_real = space.call_function(space.builtin.get('float'),
  195. space.wrap(u.get_pascal()))
  196. w_imag = space.call_function(space.builtin.get('float'),
  197. space.wrap(u.get_pascal()))
  198. w_t = space.builtin.get('complex')
  199. return space.call_function(w_t, w_real, w_imag)
  200. @unmarshaller(TYPE_BINARY_COMPLEX)
  201. def unmarshal_complex_bin(space, u, tc):
  202. real = unpack_float(u.get(8))
  203. imag = unpack_float(u.get(8))
  204. return space.newcomplex(real, imag)
  205. @marshaller(W_BytesObject)
  206. def marshal_bytes(space, w_str, m):
  207. s = space.str_w(w_str)
  208. if m.version >= 1 and space.is_interned_str(s):
  209. # we use a native rtyper stringdict for speed
  210. try:
  211. idx = m.stringtable[s]
  212. except KeyError:
  213. idx = len(m.stringtable)
  214. m.stringtable[s] = idx
  215. m.atom_str(TYPE_INTERNED, s)
  216. else:
  217. m.atom_int(TYPE_STRINGREF, idx)
  218. else:
  219. m.atom_str(TYPE_STRING, s)
  220. @unmarshaller(TYPE_STRING)
  221. def unmarshal_bytes(space, u, tc):
  222. return space.wrap(u.get_str())
  223. @unmarshaller(TYPE_INTERNED)
  224. def unmarshal_interned(space, u, tc):
  225. w_ret = space.new_interned_str(u.get_str())
  226. u.stringtable_w.append(w_ret)
  227. return w_ret
  228. @unmarshaller(TYPE_STRINGREF)
  229. def unmarshal_stringref(space, u, tc):
  230. idx = u.get_int()
  231. try:
  232. return u.stringtable_w[idx]
  233. except IndexError:
  234. raise oefmt(space.w_ValueError, "bad marshal data")
  235. @marshaller(W_AbstractTupleObject)
  236. def marshal_tuple(space, w_tuple, m):
  237. items = w_tuple.tolist()
  238. m.put_tuple_w(TYPE_TUPLE, items)
  239. @unmarshaller(TYPE_TUPLE)
  240. def unmarshal_tuple(space, u, tc):
  241. items_w = u.get_tuple_w()
  242. return space.newtuple(items_w)
  243. @marshaller(W_ListObject)
  244. def marshal_list(space, w_list, m):
  245. items = w_list.getitems()[:]
  246. m.put_tuple_w(TYPE_LIST, items)
  247. @unmarshaller(TYPE_LIST)
  248. def unmarshal_list(space, u, tc):
  249. items_w = u.get_list_w()
  250. return space.newlist(items_w)
  251. @marshaller(W_DictMultiObject)
  252. def marshal_dict(space, w_dict, m):
  253. m.start(TYPE_DICT)
  254. for w_tuple in w_dict.items():
  255. w_key, w_value = space.fixedview(w_tuple, 2)
  256. m.put_w_obj(w_key)
  257. m.put_w_obj(w_value)
  258. m.atom(TYPE_NULL)
  259. @unmarshaller(TYPE_DICT)
  260. def unmarshal_dict(space, u, tc):
  261. # since primitive lists are not optimized and we don't know
  262. # the dict size in advance, use the dict's setitem instead
  263. # of building a list of tuples.
  264. w_dic = space.newdict()
  265. while 1:
  266. w_key = u.get_w_obj(allow_null=True)
  267. if w_key is None:
  268. break
  269. w_value = u.get_w_obj()
  270. space.setitem(w_dic, w_key, w_value)
  271. return w_dic
  272. @unmarshaller(TYPE_NULL)
  273. def unmarshal_NULL(self, u, tc):
  274. return None
  275. def _put_interned_str_list(space, m, strlist):
  276. lst = [None] * len(strlist)
  277. for i in range(len(strlist)):
  278. lst[i] = space.new_interned_str(strlist[i])
  279. m.put_tuple_w(TYPE_TUPLE, lst)
  280. @marshaller(PyCode)
  281. def marshal_pycode(space, w_pycode, m):
  282. m.start(TYPE_CODE)
  283. # see pypy.interpreter.pycode for the layout
  284. x = space.interp_w(PyCode, w_pycode)
  285. m.put_int(x.co_argcount)
  286. m.put_int(x.co_nlocals)
  287. m.put_int(x.co_stacksize)
  288. m.put_int(x.co_flags)
  289. m.atom_str(TYPE_STRING, x.co_code)
  290. m.put_tuple_w(TYPE_TUPLE, x.co_consts_w)
  291. m.put_tuple_w(TYPE_TUPLE, x.co_names_w)
  292. _put_interned_str_list(space, m, x.co_varnames)
  293. _put_interned_str_list(space, m, x.co_freevars)
  294. _put_interned_str_list(space, m, x.co_cellvars)
  295. m.put_w_obj(space.new_interned_str(x.co_filename))
  296. m.put_w_obj(space.new_interned_str(x.co_name))
  297. m.put_int(x.co_firstlineno)
  298. m.atom_str(TYPE_STRING, x.co_lnotab)
  299. # helper for unmarshalling "tuple of string" objects
  300. # into rpython-level lists of strings. Only for code objects.
  301. def unmarshal_str(u):
  302. w_obj = u.get_w_obj()
  303. try:
  304. return u.space.str_w(w_obj)
  305. except OperationError as e:
  306. if e.match(u.space, u.space.w_TypeError):
  307. u.raise_exc('invalid marshal data for code object')
  308. raise
  309. def unmarshal_strlist(u, tc):
  310. lng = u.atom_lng(tc)
  311. return [unmarshal_str(u) for i in range(lng)]
  312. @unmarshaller(TYPE_CODE)
  313. def unmarshal_pycode(space, u, tc):
  314. argcount = u.get_int()
  315. nlocals = u.get_int()
  316. stacksize = u.get_int()
  317. flags = u.get_int()
  318. code = unmarshal_str(u)
  319. u.start(TYPE_TUPLE)
  320. consts_w = u.get_tuple_w()
  321. # copy in order not to merge it with anything else
  322. names = unmarshal_strlist(u, TYPE_TUPLE)
  323. varnames = unmarshal_strlist(u, TYPE_TUPLE)
  324. freevars = unmarshal_strlist(u, TYPE_TUPLE)
  325. cellvars = unmarshal_strlist(u, TYPE_TUPLE)
  326. filename = unmarshal_str(u)
  327. name = unmarshal_str(u)
  328. firstlineno = u.get_int()
  329. lnotab = unmarshal_str(u)
  330. return PyCode(space, argcount, nlocals, stacksize, flags,
  331. code, consts_w[:], names, varnames, filename,
  332. name, firstlineno, lnotab, freevars, cellvars)
  333. @marshaller(W_UnicodeObject)
  334. def marshal_unicode(space, w_unicode, m):
  335. s = unicodehelper.encode_utf8(space, space.unicode_w(w_unicode))
  336. m.atom_str(TYPE_UNICODE, s)
  337. @unmarshaller(TYPE_UNICODE)
  338. def unmarshal_unicode(space, u, tc):
  339. return space.wrap(unicodehelper.decode_utf8(space, u.get_str()))
  340. @marshaller(W_SetObject)
  341. def marshal_set(space, w_set, m):
  342. lis_w = space.fixedview(w_set)
  343. m.put_tuple_w(TYPE_SET, lis_w)
  344. @unmarshaller(TYPE_SET)
  345. def unmarshal_set(space, u, tc):
  346. return space.newset(u.get_tuple_w())
  347. @marshaller(W_FrozensetObject)
  348. def marshal_frozenset(space, w_frozenset, m):
  349. lis_w = space.fixedview(w_frozenset)
  350. m.put_tuple_w(TYPE_FROZENSET, lis_w)
  351. @unmarshaller(TYPE_FROZENSET)
  352. def unmarshal_frozenset(space, u, tc):
  353. return space.newfrozenset(u.get_tuple_w())
  354. _marshallers_unroll = unrolling_iterable(_marshallers)