PageRenderTime 29ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/jit/codewriter/assembler.py

https://bitbucket.org/halgari/pypy
Python | 304 lines | 298 code | 6 blank | 0 comment | 0 complexity | 5a1af463747f3f65ab59453705da57e3 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, AGPL-3.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. descr.dict = {}
  208. for key, switchlabel in descr._labels:
  209. target = self.label_positions[switchlabel.name]
  210. descr.dict[key] = target
  211. def check_result(self):
  212. # Limitation of the number of registers, from the single-byte encoding
  213. assert self.count_regs['int'] + len(self.constants_i) <= 256
  214. assert self.count_regs['ref'] + len(self.constants_r) <= 256
  215. assert self.count_regs['float'] + len(self.constants_f) <= 256
  216. def make_jitcode(self, jitcode):
  217. jitcode.setup(''.join(self.code),
  218. self.constants_i,
  219. self.constants_r,
  220. self.constants_f,
  221. self.count_regs['int'],
  222. self.count_regs['ref'],
  223. self.count_regs['float'],
  224. liveness=self.liveness,
  225. startpoints=self.startpoints,
  226. alllabels=self.alllabels,
  227. resulttypes=self.resulttypes)
  228. def see_raw_object(self, value):
  229. if value._obj not in self._seen_raw_objects:
  230. self._seen_raw_objects.add(value._obj)
  231. if not value: # filter out NULL pointers
  232. return
  233. TYPE = lltype.typeOf(value).TO
  234. if isinstance(TYPE, lltype.FuncType):
  235. name = value._obj._name
  236. elif TYPE == rclass.OBJECT_VTABLE:
  237. name = ''.join(value.name.chars)
  238. else:
  239. return
  240. addr = llmemory.cast_ptr_to_adr(value)
  241. self.list_of_addr2name.append((addr, name))
  242. def finished(self, callinfocollection):
  243. # Helper called at the end of assembling. Registers the extra
  244. # functions shown in _callinfo_for_oopspec.
  245. for func in callinfocollection.all_function_addresses_as_int():
  246. func = heaptracker.int2adr(func)
  247. self.see_raw_object(func.ptr)
  248. # A set of instructions that use the 'c' encoding for small constants.
  249. # Allowing it anywhere causes the number of instruction variants to
  250. # expode, growing past 256. So we list here only the most common
  251. # instructions where the 'c' variant might be useful.
  252. USE_C_FORM = set([
  253. 'copystrcontent',
  254. 'getarrayitem_gc_pure_i',
  255. 'getarrayitem_gc_pure_r',
  256. 'getarrayitem_gc_i',
  257. 'getarrayitem_gc_r',
  258. 'goto_if_not_int_eq',
  259. 'goto_if_not_int_ge',
  260. 'goto_if_not_int_gt',
  261. 'goto_if_not_int_le',
  262. 'goto_if_not_int_lt',
  263. 'goto_if_not_int_ne',
  264. 'int_add',
  265. 'int_and',
  266. 'int_copy',
  267. 'int_eq',
  268. 'int_ge',
  269. 'int_gt',
  270. 'int_le',
  271. 'int_lt',
  272. 'int_ne',
  273. 'int_return',
  274. 'int_sub',
  275. 'jit_merge_point',
  276. 'new_array',
  277. 'new_array_clear',
  278. 'newstr',
  279. 'setarrayitem_gc_i',
  280. 'setarrayitem_gc_r',
  281. 'setfield_gc_i',
  282. 'strgetitem',
  283. 'strsetitem',
  284. 'foobar', 'baz', # for tests
  285. ])