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

/rpython/jit/codewriter/assembler.py

https://bitbucket.org/pypy/pypy/
Python | 307 lines | 301 code | 6 blank | 0 comment | 0 complexity | d311d6ddef04ae592fb0d7c8c52fe791 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.jit.metainterp.history import AbstractDescr, getkind
  2. from rpython.jit.codewriter.flatten import Register, Label, TLabel, KINDS
  3. from rpython.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
  4. from rpython.jit.codewriter.format import format_assembler
  5. from rpython.jit.codewriter.jitcode import SwitchDictDescr, JitCode
  6. from rpython.jit.codewriter import heaptracker, longlong
  7. from rpython.rlib.objectmodel import ComputedIntSymbolic
  8. from rpython.flowspace.model import Constant
  9. from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
  10. from rpython.rtyper import rclass
  11. class AssemblerError(Exception):
  12. pass
  13. class Assembler(object):
  14. def __init__(self):
  15. self.insns = {}
  16. self.descrs = []
  17. self.indirectcalltargets = set() # set of JitCodes
  18. self.list_of_addr2name = []
  19. self._descr_dict = {}
  20. self._count_jitcodes = 0
  21. self._seen_raw_objects = set()
  22. def assemble(self, ssarepr, jitcode=None):
  23. """Take the 'ssarepr' representation of the code and assemble
  24. it inside the 'jitcode'. If jitcode is None, make a new one.
  25. """
  26. self.setup(ssarepr.name)
  27. ssarepr._insns_pos = []
  28. for insn in ssarepr.insns:
  29. ssarepr._insns_pos.append(len(self.code))
  30. self.write_insn(insn)
  31. self.fix_labels()
  32. self.check_result()
  33. if jitcode is None:
  34. jitcode = JitCode(ssarepr.name)
  35. jitcode._ssarepr = ssarepr
  36. self.make_jitcode(jitcode)
  37. if self._count_jitcodes < 20: # stop if we have a lot of them
  38. jitcode._dump = format_assembler(ssarepr)
  39. self._count_jitcodes += 1
  40. return jitcode
  41. def setup(self, name):
  42. self.code = []
  43. self.constants_dict = {}
  44. self.constants_i = []
  45. self.constants_r = []
  46. self.constants_f = []
  47. self.label_positions = {}
  48. self.tlabel_positions = []
  49. self.switchdictdescrs = []
  50. self.count_regs = dict.fromkeys(KINDS, 0)
  51. self.liveness = {}
  52. self.startpoints = set()
  53. self.alllabels = set()
  54. self.resulttypes = {}
  55. self.ssareprname = name
  56. def emit_reg(self, reg):
  57. if reg.index >= self.count_regs[reg.kind]:
  58. self.count_regs[reg.kind] = reg.index + 1
  59. self.code.append(chr(reg.index))
  60. def emit_const(self, const, kind, allow_short=False):
  61. value = const.value
  62. if kind == 'int':
  63. TYPE = const.concretetype
  64. if isinstance(TYPE, lltype.Ptr):
  65. assert TYPE.TO._gckind == 'raw'
  66. self.see_raw_object(value)
  67. value = llmemory.cast_ptr_to_adr(value)
  68. TYPE = llmemory.Address
  69. if TYPE == llmemory.Address:
  70. value = heaptracker.adr2int(value)
  71. if TYPE is lltype.SingleFloat:
  72. value = longlong.singlefloat2int(value)
  73. if not isinstance(value, (llmemory.AddressAsInt,
  74. ComputedIntSymbolic)):
  75. value = lltype.cast_primitive(lltype.Signed, value)
  76. if allow_short:
  77. try:
  78. short_num = -128 <= value <= 127
  79. except TypeError: # "Symbolics cannot be compared!"
  80. short_num = False
  81. if short_num:
  82. # emit the constant as a small integer
  83. self.code.append(chr(value & 0xFF))
  84. return True
  85. constants = self.constants_i
  86. elif kind == 'ref':
  87. value = lltype.cast_opaque_ptr(llmemory.GCREF, value)
  88. constants = self.constants_r
  89. elif kind == 'float':
  90. if const.concretetype == lltype.Float:
  91. value = longlong.getfloatstorage(value)
  92. else:
  93. assert longlong.is_longlong(const.concretetype)
  94. value = rffi.cast(lltype.SignedLongLong, value)
  95. constants = self.constants_f
  96. else:
  97. raise AssemblerError('unimplemented %r in %r' %
  98. (const, self.ssareprname))
  99. key = (kind, Constant(value))
  100. if key not in self.constants_dict:
  101. constants.append(value)
  102. val = 256 - len(constants)
  103. assert val >= 0, "too many constants"
  104. self.constants_dict[key] = val
  105. # emit the constant normally, as one byte that is an index in the
  106. # list of constants
  107. self.code.append(chr(self.constants_dict[key]))
  108. return False
  109. def write_insn(self, insn):
  110. if insn[0] == '---':
  111. return
  112. if isinstance(insn[0], Label):
  113. self.label_positions[insn[0].name] = len(self.code)
  114. return
  115. if insn[0] == '-live-':
  116. key = len(self.code)
  117. live_i, live_r, live_f = self.liveness.get(key, ("", "", ""))
  118. live_i = self.get_liveness_info(live_i, insn[1:], 'int')
  119. live_r = self.get_liveness_info(live_r, insn[1:], 'ref')
  120. live_f = self.get_liveness_info(live_f, insn[1:], 'float')
  121. self.liveness[key] = live_i, live_r, live_f
  122. return
  123. startposition = len(self.code)
  124. self.code.append("temporary placeholder")
  125. #
  126. argcodes = []
  127. allow_short = (insn[0] in USE_C_FORM)
  128. for x in insn[1:]:
  129. if isinstance(x, Register):
  130. self.emit_reg(x)
  131. argcodes.append(x.kind[0])
  132. elif isinstance(x, Constant):
  133. kind = getkind(x.concretetype)
  134. is_short = self.emit_const(x, kind, allow_short=allow_short)
  135. if is_short:
  136. argcodes.append('c')
  137. else:
  138. argcodes.append(kind[0])
  139. elif isinstance(x, TLabel):
  140. self.alllabels.add(len(self.code))
  141. self.tlabel_positions.append((x.name, len(self.code)))
  142. self.code.append("temp 1")
  143. self.code.append("temp 2")
  144. argcodes.append('L')
  145. elif isinstance(x, ListOfKind):
  146. itemkind = x.kind
  147. lst = list(x)
  148. assert len(lst) <= 255, "list too long!"
  149. self.code.append(chr(len(lst)))
  150. for item in lst:
  151. if isinstance(item, Register):
  152. assert itemkind == item.kind
  153. self.emit_reg(item)
  154. elif isinstance(item, Constant):
  155. assert itemkind == getkind(item.concretetype)
  156. self.emit_const(item, itemkind)
  157. else:
  158. raise NotImplementedError("found in ListOfKind(): %r"
  159. % (item,))
  160. argcodes.append(itemkind[0].upper())
  161. elif isinstance(x, AbstractDescr):
  162. if x not in self._descr_dict:
  163. self._descr_dict[x] = len(self.descrs)
  164. self.descrs.append(x)
  165. if isinstance(x, SwitchDictDescr):
  166. self.switchdictdescrs.append(x)
  167. num = self._descr_dict[x]
  168. assert 0 <= num <= 0xFFFF, "too many AbstractDescrs!"
  169. self.code.append(chr(num & 0xFF))
  170. self.code.append(chr(num >> 8))
  171. argcodes.append('d')
  172. elif isinstance(x, IndirectCallTargets):
  173. self.indirectcalltargets.update(x.lst)
  174. elif x == '->':
  175. assert '>' not in argcodes
  176. argcodes.append('>')
  177. else:
  178. raise NotImplementedError(x)
  179. #
  180. opname = insn[0]
  181. if '>' in argcodes:
  182. assert argcodes.index('>') == len(argcodes) - 2
  183. self.resulttypes[len(self.code)] = argcodes[-1]
  184. key = opname + '/' + ''.join(argcodes)
  185. num = self.insns.setdefault(key, len(self.insns))
  186. self.code[startposition] = chr(num)
  187. self.startpoints.add(startposition)
  188. def get_liveness_info(self, prevlives, args, kind):
  189. """Return a string whose characters are register numbers.
  190. We sort the numbers, too, to increase the chances of duplicate
  191. strings (which are collapsed into a single string during translation).
  192. """
  193. lives = set(prevlives) # set of characters
  194. for reg in args:
  195. if isinstance(reg, Register) and reg.kind == kind:
  196. lives.add(chr(reg.index))
  197. return lives
  198. def fix_labels(self):
  199. for name, pos in self.tlabel_positions:
  200. assert self.code[pos ] == "temp 1"
  201. assert self.code[pos+1] == "temp 2"
  202. target = self.label_positions[name]
  203. assert 0 <= target <= 0xFFFF
  204. self.code[pos ] = chr(target & 0xFF)
  205. self.code[pos+1] = chr(target >> 8)
  206. for descr in self.switchdictdescrs:
  207. as_dict = {}
  208. for key, switchlabel in descr._labels:
  209. target = self.label_positions[switchlabel.name]
  210. as_dict[key] = target
  211. descr.attach(as_dict)
  212. def check_result(self):
  213. # Limitation of the number of registers, from the single-byte encoding
  214. assert self.count_regs['int'] + len(self.constants_i) <= 256
  215. assert self.count_regs['ref'] + len(self.constants_r) <= 256
  216. assert self.count_regs['float'] + len(self.constants_f) <= 256
  217. def make_jitcode(self, jitcode):
  218. jitcode.setup(''.join(self.code),
  219. self.constants_i,
  220. self.constants_r,
  221. self.constants_f,
  222. self.count_regs['int'],
  223. self.count_regs['ref'],
  224. self.count_regs['float'],
  225. liveness=self.liveness,
  226. startpoints=self.startpoints,
  227. alllabels=self.alllabels,
  228. resulttypes=self.resulttypes)
  229. def see_raw_object(self, value):
  230. if value._obj not in self._seen_raw_objects:
  231. self._seen_raw_objects.add(value._obj)
  232. if not value: # filter out NULL pointers
  233. return
  234. TYPE = lltype.typeOf(value).TO
  235. if isinstance(TYPE, lltype.FuncType):
  236. name = value._obj._name
  237. elif TYPE == rclass.OBJECT_VTABLE:
  238. if not value.name: # this is really the "dummy" class
  239. return # pointer from some dict
  240. name = ''.join(value.name.chars)
  241. else:
  242. return
  243. addr = llmemory.cast_ptr_to_adr(value)
  244. self.list_of_addr2name.append((addr, name))
  245. def finished(self, callinfocollection):
  246. # Helper called at the end of assembling. Registers the extra
  247. # functions shown in _callinfo_for_oopspec.
  248. for func in callinfocollection.all_function_addresses_as_int():
  249. func = heaptracker.int2adr(func)
  250. self.see_raw_object(func.ptr)
  251. # A set of instructions that use the 'c' encoding for small constants.
  252. # Allowing it anywhere causes the number of instruction variants to
  253. # expode, growing past 256. So we list here only the most common
  254. # instructions where the 'c' variant might be useful.
  255. USE_C_FORM = set([
  256. 'copystrcontent',
  257. 'getarrayitem_gc_pure_i',
  258. 'getarrayitem_gc_pure_r',
  259. 'getarrayitem_gc_i',
  260. 'getarrayitem_gc_r',
  261. 'goto_if_not_int_eq',
  262. 'goto_if_not_int_ge',
  263. 'goto_if_not_int_gt',
  264. 'goto_if_not_int_le',
  265. 'goto_if_not_int_lt',
  266. 'goto_if_not_int_ne',
  267. 'int_add',
  268. 'int_and',
  269. 'int_copy',
  270. 'int_eq',
  271. 'int_ge',
  272. 'int_gt',
  273. 'int_le',
  274. 'int_lt',
  275. 'int_ne',
  276. 'int_return',
  277. 'int_sub',
  278. 'jit_merge_point',
  279. 'new_array',
  280. 'new_array_clear',
  281. 'newstr',
  282. 'setarrayitem_gc_i',
  283. 'setarrayitem_gc_r',
  284. 'setfield_gc_i',
  285. 'strgetitem',
  286. 'strsetitem',
  287. 'foobar', 'baz', # for tests
  288. ])