PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/jit/backend/llsupport/descr.py

https://bitbucket.org/pypy/pypy/
Python | 480 lines | 444 code | 30 blank | 6 comment | 40 complexity | c7dc9746cd706838ff62a49d2e68e386 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. from pypy.rpython.lltypesystem import lltype, rffi, llmemory
  3. from pypy.rpython.lltypesystem.lloperation import llop
  4. from pypy.jit.backend.llsupport import symbolic, support
  5. from pypy.jit.metainterp.history import AbstractDescr, getkind
  6. from pypy.jit.metainterp import history
  7. from pypy.jit.codewriter import heaptracker, longlong
  8. from pypy.jit.codewriter.longlong import is_longlong
  9. class GcCache(object):
  10. def __init__(self, translate_support_code, rtyper=None):
  11. self.translate_support_code = translate_support_code
  12. self.rtyper = rtyper
  13. self._cache_size = {}
  14. self._cache_field = {}
  15. self._cache_array = {}
  16. self._cache_arraylen = {}
  17. self._cache_call = {}
  18. self._cache_interiorfield = {}
  19. def init_size_descr(self, STRUCT, sizedescr):
  20. assert isinstance(STRUCT, lltype.GcStruct)
  21. def init_array_descr(self, ARRAY, arraydescr):
  22. assert (isinstance(ARRAY, lltype.GcArray) or
  23. isinstance(ARRAY, lltype.GcStruct) and ARRAY._arrayfld)
  24. # ____________________________________________________________
  25. # SizeDescrs
  26. class SizeDescr(AbstractDescr):
  27. size = 0 # help translation
  28. tid = llop.combine_ushort(lltype.Signed, 0, 0)
  29. def __init__(self, size, count_fields_if_immut=-1):
  30. self.size = size
  31. self.count_fields_if_immut = count_fields_if_immut
  32. def count_fields_if_immutable(self):
  33. return self.count_fields_if_immut
  34. def repr_of_descr(self):
  35. return '<SizeDescr %s>' % self.size
  36. class SizeDescrWithVTable(SizeDescr):
  37. def as_vtable_size_descr(self):
  38. return self
  39. BaseSizeDescr = SizeDescr
  40. def get_size_descr(gccache, STRUCT):
  41. cache = gccache._cache_size
  42. try:
  43. return cache[STRUCT]
  44. except KeyError:
  45. size = symbolic.get_size(STRUCT, gccache.translate_support_code)
  46. count_fields_if_immut = heaptracker.count_fields_if_immutable(STRUCT)
  47. if heaptracker.has_gcstruct_a_vtable(STRUCT):
  48. sizedescr = SizeDescrWithVTable(size, count_fields_if_immut)
  49. else:
  50. sizedescr = SizeDescr(size, count_fields_if_immut)
  51. gccache.init_size_descr(STRUCT, sizedescr)
  52. cache[STRUCT] = sizedescr
  53. return sizedescr
  54. # ____________________________________________________________
  55. # FieldDescrs
  56. FLAG_POINTER = 'P'
  57. FLAG_FLOAT = 'F'
  58. FLAG_UNSIGNED = 'U'
  59. FLAG_SIGNED = 'S'
  60. FLAG_STRUCT = 'X'
  61. FLAG_VOID = 'V'
  62. class FieldDescr(AbstractDescr):
  63. name = ''
  64. offset = 0 # help translation
  65. field_size = 0
  66. flag = '\x00'
  67. def __init__(self, name, offset, field_size, flag):
  68. self.name = name
  69. self.offset = offset
  70. self.field_size = field_size
  71. self.flag = flag
  72. def is_pointer_field(self):
  73. return self.flag == FLAG_POINTER
  74. def is_float_field(self):
  75. return self.flag == FLAG_FLOAT
  76. def is_field_signed(self):
  77. return self.flag == FLAG_SIGNED
  78. def sort_key(self):
  79. return self.offset
  80. def repr_of_descr(self):
  81. return '<Field%s %s %s>' % (self.flag, self.name, self.offset)
  82. def get_field_descr(gccache, STRUCT, fieldname):
  83. cache = gccache._cache_field
  84. try:
  85. return cache[STRUCT][fieldname]
  86. except KeyError:
  87. offset, size = symbolic.get_field_token(STRUCT, fieldname,
  88. gccache.translate_support_code)
  89. FIELDTYPE = getattr(STRUCT, fieldname)
  90. flag = get_type_flag(FIELDTYPE)
  91. name = '%s.%s' % (STRUCT._name, fieldname)
  92. fielddescr = FieldDescr(name, offset, size, flag)
  93. cachedict = cache.setdefault(STRUCT, {})
  94. cachedict[fieldname] = fielddescr
  95. return fielddescr
  96. def get_type_flag(TYPE):
  97. if isinstance(TYPE, lltype.Ptr):
  98. if TYPE.TO._gckind == 'gc':
  99. return FLAG_POINTER
  100. else:
  101. return FLAG_UNSIGNED
  102. if isinstance(TYPE, lltype.Struct):
  103. return FLAG_STRUCT
  104. if TYPE is lltype.Float or is_longlong(TYPE):
  105. return FLAG_FLOAT
  106. if (TYPE is not lltype.Bool and isinstance(TYPE, lltype.Number) and
  107. rffi.cast(TYPE, -1) == -1):
  108. return FLAG_SIGNED
  109. return FLAG_UNSIGNED
  110. def get_field_arraylen_descr(gccache, ARRAY_OR_STRUCT):
  111. cache = gccache._cache_arraylen
  112. try:
  113. return cache[ARRAY_OR_STRUCT]
  114. except KeyError:
  115. tsc = gccache.translate_support_code
  116. (_, _, ofs) = symbolic.get_array_token(ARRAY_OR_STRUCT, tsc)
  117. size = symbolic.get_size(lltype.Signed, tsc)
  118. result = FieldDescr("len", ofs, size, get_type_flag(lltype.Signed))
  119. cache[ARRAY_OR_STRUCT] = result
  120. return result
  121. # ____________________________________________________________
  122. # ArrayDescrs
  123. class ArrayDescr(AbstractDescr):
  124. tid = 0
  125. basesize = 0 # workaround for the annotator
  126. itemsize = 0
  127. lendescr = None
  128. flag = '\x00'
  129. def __init__(self, basesize, itemsize, lendescr, flag):
  130. self.basesize = basesize
  131. self.itemsize = itemsize
  132. self.lendescr = lendescr # or None, if no length
  133. self.flag = flag
  134. def is_array_of_pointers(self):
  135. return self.flag == FLAG_POINTER
  136. def is_array_of_floats(self):
  137. return self.flag == FLAG_FLOAT
  138. def is_item_signed(self):
  139. return self.flag == FLAG_SIGNED
  140. def is_array_of_structs(self):
  141. return self.flag == FLAG_STRUCT
  142. def repr_of_descr(self):
  143. return '<Array%s %s>' % (self.flag, self.itemsize)
  144. def get_array_descr(gccache, ARRAY_OR_STRUCT):
  145. cache = gccache._cache_array
  146. try:
  147. return cache[ARRAY_OR_STRUCT]
  148. except KeyError:
  149. tsc = gccache.translate_support_code
  150. basesize, itemsize, _ = symbolic.get_array_token(ARRAY_OR_STRUCT, tsc)
  151. if isinstance(ARRAY_OR_STRUCT, lltype.Array):
  152. ARRAY_INSIDE = ARRAY_OR_STRUCT
  153. else:
  154. ARRAY_INSIDE = ARRAY_OR_STRUCT._flds[ARRAY_OR_STRUCT._arrayfld]
  155. if ARRAY_INSIDE._hints.get('nolength', False):
  156. lendescr = None
  157. else:
  158. lendescr = get_field_arraylen_descr(gccache, ARRAY_OR_STRUCT)
  159. flag = get_type_flag(ARRAY_INSIDE.OF)
  160. arraydescr = ArrayDescr(basesize, itemsize, lendescr, flag)
  161. if ARRAY_OR_STRUCT._gckind == 'gc':
  162. gccache.init_array_descr(ARRAY_OR_STRUCT, arraydescr)
  163. cache[ARRAY_OR_STRUCT] = arraydescr
  164. return arraydescr
  165. # ____________________________________________________________
  166. # InteriorFieldDescr
  167. class InteriorFieldDescr(AbstractDescr):
  168. arraydescr = ArrayDescr(0, 0, None, '\x00') # workaround for the annotator
  169. fielddescr = FieldDescr('', 0, 0, '\x00')
  170. def __init__(self, arraydescr, fielddescr):
  171. assert arraydescr.flag == FLAG_STRUCT
  172. self.arraydescr = arraydescr
  173. self.fielddescr = fielddescr
  174. def sort_key(self):
  175. return self.fielddescr.sort_key()
  176. def is_pointer_field(self):
  177. return self.fielddescr.is_pointer_field()
  178. def is_float_field(self):
  179. return self.fielddescr.is_float_field()
  180. def repr_of_descr(self):
  181. return '<InteriorFieldDescr %s>' % self.fielddescr.repr_of_descr()
  182. def get_interiorfield_descr(gc_ll_descr, ARRAY, name):
  183. cache = gc_ll_descr._cache_interiorfield
  184. try:
  185. return cache[(ARRAY, name)]
  186. except KeyError:
  187. arraydescr = get_array_descr(gc_ll_descr, ARRAY)
  188. fielddescr = get_field_descr(gc_ll_descr, ARRAY.OF, name)
  189. descr = InteriorFieldDescr(arraydescr, fielddescr)
  190. cache[(ARRAY, name)] = descr
  191. return descr
  192. def get_dynamic_interiorfield_descr(gc_ll_descr, offset, width, fieldsize,
  193. is_pointer, is_float, is_signed):
  194. arraydescr = ArrayDescr(0, width, None, FLAG_STRUCT)
  195. if is_pointer:
  196. assert not is_float
  197. flag = FLAG_POINTER
  198. elif is_float:
  199. flag = FLAG_FLOAT
  200. elif is_signed:
  201. flag = FLAG_SIGNED
  202. else:
  203. flag = FLAG_UNSIGNED
  204. fielddescr = FieldDescr('dynamic', offset, fieldsize, flag)
  205. return InteriorFieldDescr(arraydescr, fielddescr)
  206. # ____________________________________________________________
  207. # CallDescrs
  208. class CallDescr(AbstractDescr):
  209. arg_classes = '' # <-- annotation hack
  210. result_type = '\x00'
  211. result_flag = '\x00'
  212. ffi_flags = 1
  213. call_stub_i = staticmethod(lambda func, args_i, args_r, args_f:
  214. 0)
  215. call_stub_r = staticmethod(lambda func, args_i, args_r, args_f:
  216. lltype.nullptr(llmemory.GCREF.TO))
  217. call_stub_f = staticmethod(lambda func,args_i,args_r,args_f:
  218. longlong.ZEROF)
  219. def __init__(self, arg_classes, result_type, result_signed, result_size,
  220. extrainfo=None, ffi_flags=1):
  221. """
  222. 'arg_classes' is a string of characters, one per argument:
  223. 'i', 'r', 'f', 'L', 'S'
  224. 'result_type' is one character from the same list or 'v'
  225. 'result_signed' is a boolean True/False
  226. """
  227. self.arg_classes = arg_classes
  228. self.result_type = result_type
  229. self.result_size = result_size
  230. self.extrainfo = extrainfo
  231. self.ffi_flags = ffi_flags
  232. # NB. the default ffi_flags is 1, meaning FUNCFLAG_CDECL, which
  233. # makes sense on Windows as it's the one for all the C functions
  234. # we are compiling together with the JIT. On non-Windows platforms
  235. # it is just ignored anyway.
  236. if result_type == 'v':
  237. result_flag = FLAG_VOID
  238. elif result_type == 'i':
  239. if result_signed:
  240. result_flag = FLAG_SIGNED
  241. else:
  242. result_flag = FLAG_UNSIGNED
  243. elif result_type == history.REF:
  244. result_flag = FLAG_POINTER
  245. elif result_type == history.FLOAT or result_type == 'L':
  246. result_flag = FLAG_FLOAT
  247. elif result_type == 'S':
  248. result_flag = FLAG_UNSIGNED
  249. else:
  250. raise NotImplementedError("result_type = '%s'" % (result_type,))
  251. self.result_flag = result_flag
  252. def __repr__(self):
  253. res = 'CallDescr(%s)' % (self.arg_classes,)
  254. extraeffect = getattr(self.extrainfo, 'extraeffect', None)
  255. if extraeffect is not None:
  256. res += ' EF=%r' % extraeffect
  257. oopspecindex = getattr(self.extrainfo, 'oopspecindex', 0)
  258. if oopspecindex:
  259. from pypy.jit.codewriter.effectinfo import EffectInfo
  260. for key, value in EffectInfo.__dict__.items():
  261. if key.startswith('OS_') and value == oopspecindex:
  262. break
  263. else:
  264. key = 'oopspecindex=%r' % oopspecindex
  265. res += ' ' + key
  266. return '<%s>' % res
  267. def get_extra_info(self):
  268. return self.extrainfo
  269. def get_ffi_flags(self):
  270. return self.ffi_flags
  271. def get_call_conv(self):
  272. from pypy.rlib.clibffi import get_call_conv
  273. return get_call_conv(self.ffi_flags, True)
  274. def get_arg_types(self):
  275. return self.arg_classes
  276. def get_result_type(self):
  277. return self.result_type
  278. def get_result_size(self):
  279. return self.result_size
  280. def is_result_signed(self):
  281. return self.result_flag == FLAG_SIGNED
  282. def create_call_stub(self, rtyper, RESULT):
  283. from pypy.rlib.clibffi import FFI_DEFAULT_ABI
  284. assert self.get_call_conv() == FFI_DEFAULT_ABI, (
  285. "%r: create_call_stub() with a non-default call ABI" % (self,))
  286. def process(c):
  287. if c == 'L':
  288. assert longlong.supports_longlong
  289. c = 'f'
  290. elif c == 'f' and longlong.supports_longlong:
  291. return 'longlong.getrealfloat(%s)' % (process('L'),)
  292. elif c == 'S':
  293. return 'longlong.int2singlefloat(%s)' % (process('i'),)
  294. arg = 'args_%s[%d]' % (c, seen[c])
  295. seen[c] += 1
  296. return arg
  297. def TYPE(arg):
  298. if arg == 'i':
  299. return lltype.Signed
  300. elif arg == 'f':
  301. return lltype.Float
  302. elif arg == 'r':
  303. return llmemory.GCREF
  304. elif arg == 'v':
  305. return lltype.Void
  306. elif arg == 'L':
  307. return lltype.SignedLongLong
  308. elif arg == 'S':
  309. return lltype.SingleFloat
  310. else:
  311. raise AssertionError(arg)
  312. seen = {'i': 0, 'r': 0, 'f': 0}
  313. args = ", ".join([process(c) for c in self.arg_classes])
  314. result_type = self.get_result_type()
  315. if result_type == history.INT:
  316. result = 'rffi.cast(lltype.Signed, res)'
  317. category = 'i'
  318. elif result_type == history.REF:
  319. assert RESULT == llmemory.GCREF # should be ensured by the caller
  320. result = 'lltype.cast_opaque_ptr(llmemory.GCREF, res)'
  321. category = 'r'
  322. elif result_type == history.FLOAT:
  323. result = 'longlong.getfloatstorage(res)'
  324. category = 'f'
  325. elif result_type == 'L':
  326. result = 'rffi.cast(lltype.SignedLongLong, res)'
  327. category = 'f'
  328. elif result_type == history.VOID:
  329. result = '0'
  330. category = 'i'
  331. elif result_type == 'S':
  332. result = 'longlong.singlefloat2int(res)'
  333. category = 'i'
  334. else:
  335. assert 0
  336. source = py.code.Source("""
  337. def call_stub(func, args_i, args_r, args_f):
  338. fnptr = rffi.cast(lltype.Ptr(FUNC), func)
  339. res = support.maybe_on_top_of_llinterp(rtyper, fnptr)(%(args)s)
  340. return %(result)s
  341. """ % locals())
  342. ARGS = [TYPE(arg) for arg in self.arg_classes]
  343. FUNC = lltype.FuncType(ARGS, RESULT)
  344. d = globals().copy()
  345. d.update(locals())
  346. exec source.compile() in d
  347. call_stub = d['call_stub']
  348. # store the function into one of three attributes, to preserve
  349. # type-correctness of the return value
  350. setattr(self, 'call_stub_%s' % category, call_stub)
  351. def verify_types(self, args_i, args_r, args_f, return_type):
  352. assert self.result_type in return_type
  353. assert (self.arg_classes.count('i') +
  354. self.arg_classes.count('S')) == len(args_i or ())
  355. assert self.arg_classes.count('r') == len(args_r or ())
  356. assert (self.arg_classes.count('f') +
  357. self.arg_classes.count('L')) == len(args_f or ())
  358. def repr_of_descr(self):
  359. res = 'Call%s %d' % (self.result_type, self.result_size)
  360. if self.arg_classes:
  361. res += ' ' + self.arg_classes
  362. if self.extrainfo:
  363. res += ' EF=%d' % self.extrainfo.extraeffect
  364. oopspecindex = self.extrainfo.oopspecindex
  365. if oopspecindex:
  366. res += ' OS=%d' % oopspecindex
  367. return '<%s>' % res
  368. def map_type_to_argclass(ARG, accept_void=False):
  369. kind = getkind(ARG)
  370. if kind == 'int':
  371. if ARG is lltype.SingleFloat: return 'S'
  372. else: return 'i'
  373. elif kind == 'ref': return 'r'
  374. elif kind == 'float':
  375. if is_longlong(ARG): return 'L'
  376. else: return 'f'
  377. elif kind == 'void':
  378. if accept_void: return 'v'
  379. raise NotImplementedError('ARG = %r' % (ARG,))
  380. def get_call_descr(gccache, ARGS, RESULT, extrainfo=None):
  381. arg_classes = map(map_type_to_argclass, ARGS)
  382. arg_classes = ''.join(arg_classes)
  383. result_type = map_type_to_argclass(RESULT, accept_void=True)
  384. RESULT_ERASED = RESULT
  385. if RESULT is lltype.Void:
  386. result_size = 0
  387. result_signed = False
  388. else:
  389. if isinstance(RESULT, lltype.Ptr):
  390. # avoid too many CallDescrs
  391. if result_type == 'r':
  392. RESULT_ERASED = llmemory.GCREF
  393. else:
  394. RESULT_ERASED = llmemory.Address
  395. result_size = symbolic.get_size(RESULT_ERASED,
  396. gccache.translate_support_code)
  397. result_signed = get_type_flag(RESULT) == FLAG_SIGNED
  398. key = (arg_classes, result_type, result_signed, RESULT_ERASED, extrainfo)
  399. cache = gccache._cache_call
  400. try:
  401. calldescr = cache[key]
  402. except KeyError:
  403. calldescr = CallDescr(arg_classes, result_type, result_signed,
  404. result_size, extrainfo)
  405. calldescr.create_call_stub(gccache.rtyper, RESULT_ERASED)
  406. cache[key] = calldescr
  407. assert repr(calldescr.result_size) == repr(result_size)
  408. return calldescr