PageRenderTime 32ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/pypy/jit/codewriter/jtransform.py

http://github.com/pypy/pypy
Python | 1758 lines | 1651 code | 57 blank | 50 comment | 78 complexity | 3d02cf1626a2333d8a8d6170508e5161 MD5 | raw file
  1. import py
  2. from pypy.jit.codewriter import support, heaptracker, longlong
  3. from pypy.jit.codewriter.effectinfo import EffectInfo
  4. from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
  5. from pypy.jit.codewriter.policy import log
  6. from pypy.jit.metainterp import quasiimmut
  7. from pypy.jit.metainterp.history import getkind
  8. from pypy.jit.metainterp.typesystem import deref, arrayItem
  9. from pypy.jit.metainterp.blackhole import BlackholeInterpreter
  10. from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, c_last_exception
  11. from pypy.rlib import objectmodel
  12. from pypy.rlib.jit import _we_are_jitted
  13. from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass, rffi
  14. from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY
  15. from pypy.translator.simplify import get_funcobj
  16. from pypy.translator.unsimplify import varoftype
  17. class UnsupportedMallocFlags(Exception):
  18. pass
  19. def transform_graph(graph, cpu=None, callcontrol=None, portal_jd=None):
  20. """Transform a control flow graph to make it suitable for
  21. being flattened in a JitCode.
  22. """
  23. t = Transformer(cpu, callcontrol, portal_jd)
  24. t.transform(graph)
  25. def integer_bounds(size, unsigned):
  26. if unsigned:
  27. return 0, 1 << (8 * size)
  28. else:
  29. return -(1 << (8 * size - 1)), 1 << (8 * size - 1)
  30. class Transformer(object):
  31. vable_array_vars = None
  32. def __init__(self, cpu=None, callcontrol=None, portal_jd=None):
  33. self.cpu = cpu
  34. self.callcontrol = callcontrol
  35. self.portal_jd = portal_jd # non-None only for the portal graph(s)
  36. def transform(self, graph):
  37. self.graph = graph
  38. for block in list(graph.iterblocks()):
  39. self.optimize_block(block)
  40. def optimize_block(self, block):
  41. if block.operations == ():
  42. return
  43. self.vable_array_vars = {}
  44. self.vable_flags = {}
  45. renamings = {}
  46. renamings_constants = {} # subset of 'renamings', {Var:Const} only
  47. newoperations = []
  48. #
  49. def do_rename(var, var_or_const):
  50. if var.concretetype is lltype.Void:
  51. renamings[var] = Constant(None, lltype.Void)
  52. return
  53. renamings[var] = var_or_const
  54. if isinstance(var_or_const, Constant):
  55. value = var_or_const.value
  56. value = lltype._cast_whatever(var.concretetype, value)
  57. renamings_constants[var] = Constant(value, var.concretetype)
  58. #
  59. for op in block.operations:
  60. if renamings_constants:
  61. op = self._do_renaming(renamings_constants, op)
  62. oplist = self.rewrite_operation(op)
  63. #
  64. count_before_last_operation = len(newoperations)
  65. if not isinstance(oplist, list):
  66. oplist = [oplist]
  67. for op1 in oplist:
  68. if isinstance(op1, SpaceOperation):
  69. newoperations.append(self._do_renaming(renamings, op1))
  70. elif op1 is None:
  71. # rewrite_operation() returns None to mean "has no real
  72. # effect, the result should just be renamed to args[0]"
  73. if op.result is not None:
  74. do_rename(op.result, renamings.get(op.args[0],
  75. op.args[0]))
  76. elif isinstance(op1, Constant):
  77. do_rename(op.result, op1)
  78. else:
  79. raise TypeError(repr(op1))
  80. #
  81. if block.exitswitch == c_last_exception:
  82. if len(newoperations) == count_before_last_operation:
  83. self._killed_exception_raising_operation(block)
  84. block.operations = newoperations
  85. block.exitswitch = renamings.get(block.exitswitch, block.exitswitch)
  86. self.follow_constant_exit(block)
  87. self.optimize_goto_if_not(block)
  88. for link in block.exits:
  89. self._check_no_vable_array(link.args)
  90. self._do_renaming_on_link(renamings, link)
  91. def _do_renaming(self, rename, op):
  92. op = SpaceOperation(op.opname, op.args[:], op.result)
  93. for i, v in enumerate(op.args):
  94. if isinstance(v, Variable):
  95. if v in rename:
  96. op.args[i] = rename[v]
  97. elif isinstance(v, ListOfKind):
  98. newlst = []
  99. for x in v:
  100. if x in rename:
  101. x = rename[x]
  102. newlst.append(x)
  103. op.args[i] = ListOfKind(v.kind, newlst)
  104. return op
  105. def _check_no_vable_array(self, list):
  106. if not self.vable_array_vars:
  107. return
  108. for v in list:
  109. if v in self.vable_array_vars:
  110. raise AssertionError(
  111. "A virtualizable array is passed around; it should\n"
  112. "only be used immediately after being read. Note\n"
  113. "that a possible cause is indexing with an index not\n"
  114. "known non-negative, or catching IndexError, or\n"
  115. "not inlining at all (for tests: use listops=True).\n"
  116. "Occurred in: %r" % self.graph)
  117. # extra explanation: with the way things are organized in
  118. # rpython/rlist.py, the ll_getitem becomes a function call
  119. # that is typically meant to be inlined by the JIT, but
  120. # this does not work with vable arrays because
  121. # jtransform.py expects the getfield and the getarrayitem
  122. # to be in the same basic block. It works a bit as a hack
  123. # for simple cases where we performed the backendopt
  124. # inlining before (even with a very low threshold, because
  125. # there is _always_inline_ on the relevant functions).
  126. def _do_renaming_on_link(self, rename, link):
  127. for i, v in enumerate(link.args):
  128. if isinstance(v, Variable):
  129. if v in rename:
  130. link.args[i] = rename[v]
  131. def _killed_exception_raising_operation(self, block):
  132. assert block.exits[0].exitcase is None
  133. block.exits = block.exits[:1]
  134. block.exitswitch = None
  135. # ----------
  136. def follow_constant_exit(self, block):
  137. v = block.exitswitch
  138. if isinstance(v, Constant) and v != c_last_exception:
  139. llvalue = v.value
  140. for link in block.exits:
  141. if link.llexitcase == llvalue:
  142. break
  143. else:
  144. assert link.exitcase == 'default'
  145. block.exitswitch = None
  146. link.exitcase = link.llexitcase = None
  147. block.recloseblock(link)
  148. def optimize_goto_if_not(self, block):
  149. """Replace code like 'v = int_gt(x,y); exitswitch = v'
  150. with just 'exitswitch = ('int_gt',x,y)'."""
  151. if len(block.exits) != 2:
  152. return False
  153. v = block.exitswitch
  154. if (v == c_last_exception or isinstance(v, tuple)
  155. or v.concretetype != lltype.Bool):
  156. return False
  157. for op in block.operations[::-1]:
  158. if v in op.args:
  159. return False # variable is also used in cur block
  160. if v is op.result:
  161. if op.opname not in ('int_lt', 'int_le', 'int_eq', 'int_ne',
  162. 'int_gt', 'int_ge',
  163. 'int_is_zero', 'int_is_true',
  164. 'ptr_eq', 'ptr_ne',
  165. 'ptr_iszero', 'ptr_nonzero'):
  166. return False # not a supported operation
  167. # ok! optimize this case
  168. block.operations.remove(op)
  169. block.exitswitch = (op.opname,) + tuple(op.args)
  170. if op.opname in ('ptr_iszero', 'ptr_nonzero'):
  171. block.exitswitch += ('-live-before',)
  172. # if the variable escape to the next block along a link,
  173. # replace it with a constant, because we know its value
  174. for link in block.exits:
  175. while v in link.args:
  176. index = link.args.index(v)
  177. link.args[index] = Constant(link.llexitcase,
  178. lltype.Bool)
  179. return True
  180. return False
  181. # ----------
  182. def rewrite_operation(self, op):
  183. try:
  184. rewrite = _rewrite_ops[op.opname]
  185. except KeyError:
  186. raise Exception("the JIT doesn't support the operation %r"
  187. " in %r" % (op, getattr(self, 'graph', '?')))
  188. return rewrite(self, op)
  189. def rewrite_op_same_as(self, op):
  190. if op.args[0] in self.vable_array_vars:
  191. self.vable_array_vars[op.result]= self.vable_array_vars[op.args[0]]
  192. def rewrite_op_cast_pointer(self, op):
  193. newop = self.rewrite_op_same_as(op)
  194. assert newop is None
  195. return
  196. # disabled for now
  197. if (self._is_rclass_instance(op.args[0]) and
  198. self._is_rclass_instance(op.result)):
  199. FROM = op.args[0].concretetype.TO
  200. TO = op.result.concretetype.TO
  201. if lltype._castdepth(TO, FROM) > 0:
  202. vtable = heaptracker.get_vtable_for_gcstruct(self.cpu, TO)
  203. const_vtable = Constant(vtable, lltype.typeOf(vtable))
  204. return [None, # hack, do the right renaming from op.args[0] to op.result
  205. SpaceOperation("record_known_class", [op.args[0], const_vtable], None)]
  206. def rewrite_op_jit_record_known_class(self, op):
  207. return SpaceOperation("record_known_class", [op.args[0], op.args[1]], None)
  208. def rewrite_op_cast_bool_to_int(self, op): pass
  209. def rewrite_op_cast_bool_to_uint(self, op): pass
  210. def rewrite_op_cast_char_to_int(self, op): pass
  211. def rewrite_op_cast_unichar_to_int(self, op): pass
  212. def rewrite_op_cast_int_to_char(self, op): pass
  213. def rewrite_op_cast_int_to_unichar(self, op): pass
  214. def rewrite_op_cast_int_to_uint(self, op): pass
  215. def rewrite_op_cast_uint_to_int(self, op): pass
  216. def _rewrite_symmetric(self, op):
  217. """Rewrite 'c1+v2' into 'v2+c1' in an attempt to avoid generating
  218. too many variants of the bytecode."""
  219. if (isinstance(op.args[0], Constant) and
  220. isinstance(op.args[1], Variable)):
  221. reversename = {'int_lt': 'int_gt',
  222. 'int_le': 'int_ge',
  223. 'int_gt': 'int_lt',
  224. 'int_ge': 'int_le',
  225. 'uint_lt': 'uint_gt',
  226. 'uint_le': 'uint_ge',
  227. 'uint_gt': 'uint_lt',
  228. 'uint_ge': 'uint_le',
  229. 'float_lt': 'float_gt',
  230. 'float_le': 'float_ge',
  231. 'float_gt': 'float_lt',
  232. 'float_ge': 'float_le',
  233. }.get(op.opname, op.opname)
  234. return SpaceOperation(reversename,
  235. [op.args[1], op.args[0]] + op.args[2:],
  236. op.result)
  237. else:
  238. return op
  239. rewrite_op_int_add = _rewrite_symmetric
  240. rewrite_op_int_mul = _rewrite_symmetric
  241. rewrite_op_int_and = _rewrite_symmetric
  242. rewrite_op_int_or = _rewrite_symmetric
  243. rewrite_op_int_xor = _rewrite_symmetric
  244. rewrite_op_int_lt = _rewrite_symmetric
  245. rewrite_op_int_le = _rewrite_symmetric
  246. rewrite_op_int_gt = _rewrite_symmetric
  247. rewrite_op_int_ge = _rewrite_symmetric
  248. rewrite_op_uint_lt = _rewrite_symmetric
  249. rewrite_op_uint_le = _rewrite_symmetric
  250. rewrite_op_uint_gt = _rewrite_symmetric
  251. rewrite_op_uint_ge = _rewrite_symmetric
  252. rewrite_op_float_add = _rewrite_symmetric
  253. rewrite_op_float_mul = _rewrite_symmetric
  254. rewrite_op_float_lt = _rewrite_symmetric
  255. rewrite_op_float_le = _rewrite_symmetric
  256. rewrite_op_float_gt = _rewrite_symmetric
  257. rewrite_op_float_ge = _rewrite_symmetric
  258. def rewrite_op_int_add_ovf(self, op):
  259. op0 = self._rewrite_symmetric(op)
  260. op1 = SpaceOperation('-live-', [], None)
  261. return [op0, op1]
  262. rewrite_op_int_mul_ovf = rewrite_op_int_add_ovf
  263. def rewrite_op_int_sub_ovf(self, op):
  264. op1 = SpaceOperation('-live-', [], None)
  265. return [op, op1]
  266. def _noop_rewrite(self, op):
  267. return op
  268. rewrite_op_convert_float_bytes_to_longlong = _noop_rewrite
  269. rewrite_op_convert_longlong_bytes_to_float = _noop_rewrite
  270. # ----------
  271. # Various kinds of calls
  272. def rewrite_op_direct_call(self, op):
  273. kind = self.callcontrol.guess_call_kind(op)
  274. return getattr(self, 'handle_%s_call' % kind)(op)
  275. def rewrite_op_indirect_call(self, op):
  276. kind = self.callcontrol.guess_call_kind(op)
  277. return getattr(self, 'handle_%s_indirect_call' % kind)(op)
  278. def rewrite_call(self, op, namebase, initialargs, args=None):
  279. """Turn 'i0 = direct_call(fn, i1, i2, ref1, ref2)'
  280. into 'i0 = xxx_call_ir_i(fn, descr, [i1,i2], [ref1,ref2])'.
  281. The name is one of '{residual,direct}_call_{r,ir,irf}_{i,r,f,v}'."""
  282. if args is None:
  283. args = op.args[1:]
  284. self._check_no_vable_array(args)
  285. lst_i, lst_r, lst_f = self.make_three_lists(args)
  286. reskind = getkind(op.result.concretetype)[0]
  287. if lst_f or reskind == 'f': kinds = 'irf'
  288. elif lst_i: kinds = 'ir'
  289. else: kinds = 'r'
  290. sublists = []
  291. if 'i' in kinds: sublists.append(lst_i)
  292. if 'r' in kinds: sublists.append(lst_r)
  293. if 'f' in kinds: sublists.append(lst_f)
  294. return SpaceOperation('%s_%s_%s' % (namebase, kinds, reskind),
  295. initialargs + sublists, op.result)
  296. def make_three_lists(self, vars):
  297. args_i = []
  298. args_r = []
  299. args_f = []
  300. for v in vars:
  301. self.add_in_correct_list(v, args_i, args_r, args_f)
  302. return [ListOfKind('int', args_i),
  303. ListOfKind('ref', args_r),
  304. ListOfKind('float', args_f)]
  305. def add_in_correct_list(self, v, lst_i, lst_r, lst_f):
  306. kind = getkind(v.concretetype)
  307. if kind == 'void': return
  308. elif kind == 'int': lst = lst_i
  309. elif kind == 'ref': lst = lst_r
  310. elif kind == 'float': lst = lst_f
  311. else: raise AssertionError(kind)
  312. lst.append(v)
  313. def handle_residual_call(self, op, extraargs=[], may_call_jitcodes=False):
  314. """A direct_call turns into the operation 'residual_call_xxx' if it
  315. is calling a function that we don't want to JIT. The initial args
  316. of 'residual_call_xxx' are the function to call, and its calldescr."""
  317. calldescr = self.callcontrol.getcalldescr(op)
  318. op1 = self.rewrite_call(op, 'residual_call',
  319. [op.args[0], calldescr] + extraargs)
  320. if may_call_jitcodes or self.callcontrol.calldescr_canraise(calldescr):
  321. op1 = [op1, SpaceOperation('-live-', [], None)]
  322. return op1
  323. def handle_regular_call(self, op):
  324. """A direct_call turns into the operation 'inline_call_xxx' if it
  325. is calling a function that we want to JIT. The initial arg of
  326. 'inline_call_xxx' is the JitCode of the called function."""
  327. [targetgraph] = self.callcontrol.graphs_from(op)
  328. jitcode = self.callcontrol.get_jitcode(targetgraph,
  329. called_from=self.graph)
  330. op0 = self.rewrite_call(op, 'inline_call', [jitcode])
  331. op1 = SpaceOperation('-live-', [], None)
  332. return [op0, op1]
  333. def handle_builtin_call(self, op):
  334. oopspec_name, args = support.decode_builtin_call(op)
  335. # dispatch to various implementations depending on the oopspec_name
  336. if oopspec_name.startswith('list.') or oopspec_name.startswith('newlist'):
  337. prepare = self._handle_list_call
  338. elif oopspec_name.startswith('stroruni.'):
  339. prepare = self._handle_stroruni_call
  340. elif oopspec_name == 'str.str2unicode':
  341. prepare = self._handle_str2unicode_call
  342. elif oopspec_name.startswith('virtual_ref'):
  343. prepare = self._handle_virtual_ref_call
  344. elif oopspec_name.startswith('jit.'):
  345. prepare = self._handle_jit_call
  346. elif oopspec_name.startswith('libffi_'):
  347. prepare = self._handle_libffi_call
  348. elif oopspec_name.startswith('math.sqrt'):
  349. prepare = self._handle_math_sqrt_call
  350. else:
  351. prepare = self.prepare_builtin_call
  352. try:
  353. op1 = prepare(op, oopspec_name, args)
  354. except NotSupported:
  355. op1 = op
  356. # If the resulting op1 is still a direct_call, turn it into a
  357. # residual_call.
  358. if isinstance(op1, SpaceOperation) and op1.opname == 'direct_call':
  359. op1 = self.handle_residual_call(op1)
  360. return op1
  361. def handle_recursive_call(self, op):
  362. jitdriver_sd = self.callcontrol.jitdriver_sd_from_portal_runner_ptr(
  363. op.args[0].value)
  364. assert jitdriver_sd is not None
  365. ops = self.promote_greens(op.args[1:], jitdriver_sd.jitdriver)
  366. num_green_args = len(jitdriver_sd.jitdriver.greens)
  367. args = ([Constant(jitdriver_sd.index, lltype.Signed)] +
  368. self.make_three_lists(op.args[1:1+num_green_args]) +
  369. self.make_three_lists(op.args[1+num_green_args:]))
  370. kind = getkind(op.result.concretetype)[0]
  371. op0 = SpaceOperation('recursive_call_%s' % kind, args, op.result)
  372. op1 = SpaceOperation('-live-', [], None)
  373. return ops + [op0, op1]
  374. handle_residual_indirect_call = handle_residual_call
  375. def handle_regular_indirect_call(self, op):
  376. """An indirect call where at least one target has a JitCode."""
  377. lst = []
  378. for targetgraph in self.callcontrol.graphs_from(op):
  379. jitcode = self.callcontrol.get_jitcode(targetgraph,
  380. called_from=self.graph)
  381. lst.append(jitcode)
  382. op0 = SpaceOperation('-live-', [], None)
  383. op1 = SpaceOperation('int_guard_value', [op.args[0]], None)
  384. op2 = self.handle_residual_call(op, [IndirectCallTargets(lst)], True)
  385. result = [op0, op1]
  386. if isinstance(op2, list):
  387. result += op2
  388. else:
  389. result.append(op2)
  390. return result
  391. def prepare_builtin_call(self, op, oopspec_name, args,
  392. extra=None, extrakey=None):
  393. argtypes = [v.concretetype for v in args]
  394. resulttype = op.result.concretetype
  395. c_func, TP = support.builtin_func_for_spec(self.cpu.rtyper,
  396. oopspec_name, argtypes,
  397. resulttype, extra, extrakey)
  398. return SpaceOperation('direct_call', [c_func] + args, op.result)
  399. def _do_builtin_call(self, op, oopspec_name=None, args=None,
  400. extra=None, extrakey=None):
  401. if oopspec_name is None: oopspec_name = op.opname
  402. if args is None: args = op.args
  403. op1 = self.prepare_builtin_call(op, oopspec_name, args,
  404. extra, extrakey)
  405. return self.rewrite_op_direct_call(op1)
  406. # XXX some of the following functions should not become residual calls
  407. # but be really compiled
  408. rewrite_op_int_floordiv_ovf_zer = _do_builtin_call
  409. rewrite_op_int_floordiv_ovf = _do_builtin_call
  410. rewrite_op_int_floordiv_zer = _do_builtin_call
  411. rewrite_op_int_mod_ovf_zer = _do_builtin_call
  412. rewrite_op_int_mod_ovf = _do_builtin_call
  413. rewrite_op_int_mod_zer = _do_builtin_call
  414. rewrite_op_int_lshift_ovf = _do_builtin_call
  415. rewrite_op_int_abs = _do_builtin_call
  416. rewrite_op_llong_abs = _do_builtin_call
  417. rewrite_op_llong_floordiv = _do_builtin_call
  418. rewrite_op_llong_floordiv_zer = _do_builtin_call
  419. rewrite_op_llong_mod = _do_builtin_call
  420. rewrite_op_llong_mod_zer = _do_builtin_call
  421. rewrite_op_ullong_floordiv = _do_builtin_call
  422. rewrite_op_ullong_floordiv_zer = _do_builtin_call
  423. rewrite_op_ullong_mod = _do_builtin_call
  424. rewrite_op_ullong_mod_zer = _do_builtin_call
  425. rewrite_op_gc_identityhash = _do_builtin_call
  426. rewrite_op_gc_id = _do_builtin_call
  427. rewrite_op_uint_mod = _do_builtin_call
  428. rewrite_op_cast_float_to_uint = _do_builtin_call
  429. rewrite_op_cast_uint_to_float = _do_builtin_call
  430. # ----------
  431. # getfield/setfield/mallocs etc.
  432. def rewrite_op_hint(self, op):
  433. hints = op.args[1].value
  434. if hints.get('promote') and op.args[0].concretetype is not lltype.Void:
  435. assert op.args[0].concretetype != lltype.Ptr(rstr.STR)
  436. kind = getkind(op.args[0].concretetype)
  437. op0 = SpaceOperation('-live-', [], None)
  438. op1 = SpaceOperation('%s_guard_value' % kind, [op.args[0]], None)
  439. # the special return value None forces op.result to be considered
  440. # equal to op.args[0]
  441. return [op0, op1, None]
  442. if (hints.get('promote_string') and
  443. op.args[0].concretetype is not lltype.Void):
  444. S = lltype.Ptr(rstr.STR)
  445. assert op.args[0].concretetype == S
  446. self._register_extra_helper(EffectInfo.OS_STREQ_NONNULL,
  447. "str.eq_nonnull",
  448. [S, S],
  449. lltype.Signed,
  450. EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
  451. descr, p = self.callcontrol.callinfocollection.callinfo_for_oopspec(
  452. EffectInfo.OS_STREQ_NONNULL)
  453. # XXX this is fairly ugly way of creating a constant,
  454. # however, callinfocollection has no better interface
  455. c = Constant(p.adr.ptr, lltype.typeOf(p.adr.ptr))
  456. op1 = SpaceOperation('str_guard_value', [op.args[0], c, descr],
  457. op.result)
  458. return [SpaceOperation('-live-', [], None), op1, None]
  459. else:
  460. log.WARNING('ignoring hint %r at %r' % (hints, self.graph))
  461. def _rewrite_raw_malloc(self, op, name, args):
  462. d = op.args[1].value.copy()
  463. d.pop('flavor')
  464. add_memory_pressure = d.pop('add_memory_pressure', False)
  465. zero = d.pop('zero', False)
  466. track_allocation = d.pop('track_allocation', True)
  467. if d:
  468. raise UnsupportedMallocFlags(d)
  469. TYPE = op.args[0].value
  470. if zero:
  471. name += '_zero'
  472. if add_memory_pressure:
  473. name += '_add_memory_pressure'
  474. if not track_allocation:
  475. name += '_no_track_allocation'
  476. return self._do_builtin_call(op, name, args,
  477. extra = (TYPE,),
  478. extrakey = TYPE)
  479. def rewrite_op_malloc_varsize(self, op):
  480. if op.args[1].value['flavor'] == 'raw':
  481. return self._rewrite_raw_malloc(op, 'raw_malloc_varsize',
  482. [op.args[2]])
  483. if op.args[0].value == rstr.STR:
  484. return SpaceOperation('newstr', [op.args[2]], op.result)
  485. elif op.args[0].value == rstr.UNICODE:
  486. return SpaceOperation('newunicode', [op.args[2]], op.result)
  487. else:
  488. # XXX only strings or simple arrays for now
  489. ARRAY = op.args[0].value
  490. arraydescr = self.cpu.arraydescrof(ARRAY)
  491. return SpaceOperation('new_array', [arraydescr, op.args[2]],
  492. op.result)
  493. def rewrite_op_free(self, op):
  494. d = op.args[1].value.copy()
  495. assert d['flavor'] == 'raw'
  496. d.pop('flavor')
  497. track_allocation = d.pop('track_allocation', True)
  498. if d:
  499. raise UnsupportedMallocFlags(d)
  500. STRUCT = op.args[0].concretetype.TO
  501. name = 'raw_free'
  502. if not track_allocation:
  503. name += '_no_track_allocation'
  504. return self._do_builtin_call(op, name, [op.args[0]],
  505. extra = (STRUCT,), extrakey = STRUCT)
  506. def rewrite_op_getarrayitem(self, op):
  507. ARRAY = op.args[0].concretetype.TO
  508. if self._array_of_voids(ARRAY):
  509. return []
  510. if op.args[0] in self.vable_array_vars: # for virtualizables
  511. vars = self.vable_array_vars[op.args[0]]
  512. (v_base, arrayfielddescr, arraydescr) = vars
  513. kind = getkind(op.result.concretetype)
  514. return [SpaceOperation('-live-', [], None),
  515. SpaceOperation('getarrayitem_vable_%s' % kind[0],
  516. [v_base, arrayfielddescr, arraydescr,
  517. op.args[1]], op.result)]
  518. # normal case follows
  519. arraydescr = self.cpu.arraydescrof(ARRAY)
  520. kind = getkind(op.result.concretetype)
  521. return SpaceOperation('getarrayitem_%s_%s' % (ARRAY._gckind, kind[0]),
  522. [op.args[0], arraydescr, op.args[1]],
  523. op.result)
  524. def rewrite_op_setarrayitem(self, op):
  525. ARRAY = op.args[0].concretetype.TO
  526. if self._array_of_voids(ARRAY):
  527. return []
  528. if op.args[0] in self.vable_array_vars: # for virtualizables
  529. vars = self.vable_array_vars[op.args[0]]
  530. (v_base, arrayfielddescr, arraydescr) = vars
  531. kind = getkind(op.args[2].concretetype)
  532. return [SpaceOperation('-live-', [], None),
  533. SpaceOperation('setarrayitem_vable_%s' % kind[0],
  534. [v_base, arrayfielddescr, arraydescr,
  535. op.args[1], op.args[2]], None)]
  536. arraydescr = self.cpu.arraydescrof(ARRAY)
  537. kind = getkind(op.args[2].concretetype)
  538. return SpaceOperation('setarrayitem_%s_%s' % (ARRAY._gckind, kind[0]),
  539. [op.args[0], arraydescr, op.args[1], op.args[2]],
  540. None)
  541. def rewrite_op_getarraysize(self, op):
  542. ARRAY = op.args[0].concretetype.TO
  543. assert ARRAY._gckind == 'gc'
  544. if op.args[0] in self.vable_array_vars: # for virtualizables
  545. vars = self.vable_array_vars[op.args[0]]
  546. (v_base, arrayfielddescr, arraydescr) = vars
  547. return [SpaceOperation('-live-', [], None),
  548. SpaceOperation('arraylen_vable',
  549. [v_base, arrayfielddescr, arraydescr],
  550. op.result)]
  551. # normal case follows
  552. arraydescr = self.cpu.arraydescrof(ARRAY)
  553. return SpaceOperation('arraylen_gc', [op.args[0], arraydescr],
  554. op.result)
  555. def _array_of_voids(self, ARRAY):
  556. #if isinstance(ARRAY, ootype.Array):
  557. # return ARRAY.ITEM == ootype.Void
  558. #else:
  559. return ARRAY.OF == lltype.Void
  560. def rewrite_op_getfield(self, op):
  561. if self.is_typeptr_getset(op):
  562. return self.handle_getfield_typeptr(op)
  563. # turn the flow graph 'getfield' operation into our own version
  564. [v_inst, c_fieldname] = op.args
  565. RESULT = op.result.concretetype
  566. if RESULT is lltype.Void:
  567. return
  568. # check for virtualizable
  569. try:
  570. if self.is_virtualizable_getset(op):
  571. descr = self.get_virtualizable_field_descr(op)
  572. kind = getkind(RESULT)[0]
  573. return [SpaceOperation('-live-', [], None),
  574. SpaceOperation('getfield_vable_%s' % kind,
  575. [v_inst, descr], op.result)]
  576. except VirtualizableArrayField, e:
  577. # xxx hack hack hack
  578. vinfo = e.args[1]
  579. arrayindex = vinfo.array_field_counter[op.args[1].value]
  580. arrayfielddescr = vinfo.array_field_descrs[arrayindex]
  581. arraydescr = vinfo.array_descrs[arrayindex]
  582. self.vable_array_vars[op.result] = (op.args[0],
  583. arrayfielddescr,
  584. arraydescr)
  585. return []
  586. # check for _immutable_fields_ hints
  587. immut = v_inst.concretetype.TO._immutable_field(c_fieldname.value)
  588. if immut:
  589. if (self.callcontrol is not None and
  590. self.callcontrol.could_be_green_field(v_inst.concretetype.TO,
  591. c_fieldname.value)):
  592. pure = '_greenfield'
  593. else:
  594. pure = '_pure'
  595. else:
  596. pure = ''
  597. self.check_field_access(v_inst.concretetype.TO)
  598. argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
  599. descr = self.cpu.fielddescrof(v_inst.concretetype.TO,
  600. c_fieldname.value)
  601. kind = getkind(RESULT)[0]
  602. op1 = SpaceOperation('getfield_%s_%s%s' % (argname, kind, pure),
  603. [v_inst, descr], op.result)
  604. #
  605. if immut in (IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY):
  606. descr1 = self.cpu.fielddescrof(
  607. v_inst.concretetype.TO,
  608. quasiimmut.get_mutate_field_name(c_fieldname.value))
  609. op1 = [SpaceOperation('-live-', [], None),
  610. SpaceOperation('record_quasiimmut_field',
  611. [v_inst, descr, descr1], None),
  612. op1]
  613. return op1
  614. def rewrite_op_setfield(self, op):
  615. if self.is_typeptr_getset(op):
  616. # ignore the operation completely -- instead, it's done by 'new'
  617. return
  618. # turn the flow graph 'setfield' operation into our own version
  619. [v_inst, c_fieldname, v_value] = op.args
  620. RESULT = v_value.concretetype
  621. if RESULT is lltype.Void:
  622. return
  623. # check for virtualizable
  624. if self.is_virtualizable_getset(op):
  625. descr = self.get_virtualizable_field_descr(op)
  626. kind = getkind(RESULT)[0]
  627. return [SpaceOperation('-live-', [], None),
  628. SpaceOperation('setfield_vable_%s' % kind,
  629. [v_inst, descr, v_value], None)]
  630. self.check_field_access(v_inst.concretetype.TO)
  631. argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
  632. descr = self.cpu.fielddescrof(v_inst.concretetype.TO,
  633. c_fieldname.value)
  634. kind = getkind(RESULT)[0]
  635. return SpaceOperation('setfield_%s_%s' % (argname, kind),
  636. [v_inst, descr, v_value],
  637. None)
  638. def is_typeptr_getset(self, op):
  639. return (op.args[1].value == 'typeptr' and
  640. op.args[0].concretetype.TO._hints.get('typeptr'))
  641. def check_field_access(self, STRUCT):
  642. # check against a GcStruct with a nested GcStruct as a first argument
  643. # but which is not an object at all; see metainterp/test/test_loop,
  644. # test_regular_pointers_in_short_preamble.
  645. if not isinstance(STRUCT, lltype.GcStruct):
  646. return
  647. if STRUCT._first_struct() == (None, None):
  648. return
  649. PARENT = STRUCT
  650. while not PARENT._hints.get('typeptr'):
  651. _, PARENT = PARENT._first_struct()
  652. if PARENT is None:
  653. raise NotImplementedError("%r is a GcStruct using nesting but "
  654. "not inheriting from object" %
  655. (STRUCT,))
  656. def get_vinfo(self, v_virtualizable):
  657. if self.callcontrol is None: # for tests
  658. return None
  659. return self.callcontrol.get_vinfo(v_virtualizable.concretetype)
  660. def is_virtualizable_getset(self, op):
  661. # every access of an object of exactly the type VTYPEPTR is
  662. # likely to be a virtualizable access, but we still have to
  663. # check it in pyjitpl.py.
  664. vinfo = self.get_vinfo(op.args[0])
  665. if vinfo is None:
  666. return False
  667. res = False
  668. if op.args[1].value in vinfo.static_field_to_extra_box:
  669. res = True
  670. if op.args[1].value in vinfo.array_fields:
  671. res = VirtualizableArrayField(self.graph, vinfo)
  672. if res:
  673. flags = self.vable_flags[op.args[0]]
  674. if 'fresh_virtualizable' in flags:
  675. return False
  676. if isinstance(res, Exception):
  677. raise res
  678. return res
  679. def get_virtualizable_field_descr(self, op):
  680. fieldname = op.args[1].value
  681. vinfo = self.get_vinfo(op.args[0])
  682. index = vinfo.static_field_to_extra_box[fieldname]
  683. return vinfo.static_field_descrs[index]
  684. def handle_getfield_typeptr(self, op):
  685. if isinstance(op.args[0], Constant):
  686. cls = op.args[0].value.typeptr
  687. return Constant(cls, concretetype=rclass.CLASSTYPE)
  688. op0 = SpaceOperation('-live-', [], None)
  689. op1 = SpaceOperation('guard_class', [op.args[0]], op.result)
  690. return [op0, op1]
  691. def rewrite_op_malloc(self, op):
  692. if op.args[1].value['flavor'] == 'raw':
  693. return self._rewrite_raw_malloc(op, 'raw_malloc_fixedsize', [])
  694. #
  695. assert op.args[1].value == {'flavor': 'gc'}
  696. STRUCT = op.args[0].value
  697. vtable = heaptracker.get_vtable_for_gcstruct(self.cpu, STRUCT)
  698. if vtable:
  699. # do we have a __del__?
  700. try:
  701. rtti = lltype.getRuntimeTypeInfo(STRUCT)
  702. except ValueError:
  703. pass
  704. else:
  705. if hasattr(rtti._obj, 'destructor_funcptr'):
  706. RESULT = lltype.Ptr(STRUCT)
  707. assert RESULT == op.result.concretetype
  708. return self._do_builtin_call(op, 'alloc_with_del', [],
  709. extra = (RESULT, vtable),
  710. extrakey = STRUCT)
  711. heaptracker.register_known_gctype(self.cpu, vtable, STRUCT)
  712. opname = 'new_with_vtable'
  713. else:
  714. opname = 'new'
  715. sizedescr = self.cpu.sizeof(STRUCT)
  716. return SpaceOperation(opname, [sizedescr], op.result)
  717. def rewrite_op_getinteriorarraysize(self, op):
  718. # only supports strings and unicodes
  719. assert len(op.args) == 2
  720. assert op.args[1].value == 'chars'
  721. optype = op.args[0].concretetype
  722. if optype == lltype.Ptr(rstr.STR):
  723. opname = "strlen"
  724. else:
  725. assert optype == lltype.Ptr(rstr.UNICODE)
  726. opname = "unicodelen"
  727. return SpaceOperation(opname, [op.args[0]], op.result)
  728. def rewrite_op_getinteriorfield(self, op):
  729. assert len(op.args) == 3
  730. optype = op.args[0].concretetype
  731. if optype == lltype.Ptr(rstr.STR):
  732. opname = "strgetitem"
  733. return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
  734. elif optype == lltype.Ptr(rstr.UNICODE):
  735. opname = "unicodegetitem"
  736. return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
  737. else:
  738. v_inst, v_index, c_field = op.args
  739. if op.result.concretetype is lltype.Void:
  740. return
  741. # only GcArray of Struct supported
  742. assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
  743. STRUCT = v_inst.concretetype.TO.OF
  744. assert isinstance(STRUCT, lltype.Struct)
  745. descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
  746. c_field.value)
  747. args = [v_inst, v_index, descr]
  748. kind = getkind(op.result.concretetype)[0]
  749. return SpaceOperation('getinteriorfield_gc_%s' % kind, args,
  750. op.result)
  751. def rewrite_op_setinteriorfield(self, op):
  752. assert len(op.args) == 4
  753. optype = op.args[0].concretetype
  754. if optype == lltype.Ptr(rstr.STR):
  755. opname = "strsetitem"
  756. return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
  757. op.result)
  758. elif optype == lltype.Ptr(rstr.UNICODE):
  759. opname = "unicodesetitem"
  760. return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
  761. op.result)
  762. else:
  763. v_inst, v_index, c_field, v_value = op.args
  764. if v_value.concretetype is lltype.Void:
  765. return
  766. # only GcArray of Struct supported
  767. assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
  768. STRUCT = v_inst.concretetype.TO.OF
  769. assert isinstance(STRUCT, lltype.Struct)
  770. descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
  771. c_field.value)
  772. kind = getkind(v_value.concretetype)[0]
  773. args = [v_inst, v_index, v_value, descr]
  774. return SpaceOperation('setinteriorfield_gc_%s' % kind, args,
  775. op.result)
  776. def _rewrite_equality(self, op, opname):
  777. arg0, arg1 = op.args
  778. if isinstance(arg0, Constant) and not arg0.value:
  779. return SpaceOperation(opname, [arg1], op.result)
  780. elif isinstance(arg1, Constant) and not arg1.value:
  781. return SpaceOperation(opname, [arg0], op.result)
  782. else:
  783. return self._rewrite_symmetric(op)
  784. def _is_gc(self, v):
  785. return getattr(getattr(v.concretetype, "TO", None), "_gckind", "?") == 'gc'
  786. def _is_rclass_instance(self, v):
  787. return lltype._castdepth(v.concretetype.TO, rclass.OBJECT) >= 0
  788. def _rewrite_cmp_ptrs(self, op):
  789. if self._is_gc(op.args[0]):
  790. return op
  791. else:
  792. opname = {'ptr_eq': 'int_eq',
  793. 'ptr_ne': 'int_ne',
  794. 'ptr_iszero': 'int_is_zero',
  795. 'ptr_nonzero': 'int_is_true'}[op.opname]
  796. return SpaceOperation(opname, op.args, op.result)
  797. def rewrite_op_int_eq(self, op):
  798. return self._rewrite_equality(op, 'int_is_zero')
  799. def rewrite_op_int_ne(self, op):
  800. return self._rewrite_equality(op, 'int_is_true')
  801. def rewrite_op_ptr_eq(self, op):
  802. prefix = ''
  803. if self._is_rclass_instance(op.args[0]):
  804. assert self._is_rclass_instance(op.args[1])
  805. op = SpaceOperation('instance_ptr_eq', op.args, op.result)
  806. prefix = 'instance_'
  807. op1 = self._rewrite_equality(op, prefix + 'ptr_iszero')
  808. return self._rewrite_cmp_ptrs(op1)
  809. def rewrite_op_ptr_ne(self, op):
  810. prefix = ''
  811. if self._is_rclass_instance(op.args[0]):
  812. assert self._is_rclass_instance(op.args[1])
  813. op = SpaceOperation('instance_ptr_ne', op.args, op.result)
  814. prefix = 'instance_'
  815. op1 = self._rewrite_equality(op, prefix + 'ptr_nonzero')
  816. return self._rewrite_cmp_ptrs(op1)
  817. rewrite_op_ptr_iszero = _rewrite_cmp_ptrs
  818. rewrite_op_ptr_nonzero = _rewrite_cmp_ptrs
  819. def rewrite_op_cast_ptr_to_int(self, op):
  820. if self._is_gc(op.args[0]):
  821. return op
  822. def rewrite_op_cast_opaque_ptr(self, op):
  823. # None causes the result of this op to get aliased to op.args[0]
  824. return [SpaceOperation('mark_opaque_ptr', op.args, None), None]
  825. def rewrite_op_force_cast(self, op):
  826. v_arg = op.args[0]
  827. v_result = op.result
  828. assert not self._is_gc(v_arg)
  829. if v_arg.concretetype == v_result.concretetype:
  830. return
  831. float_arg = v_arg.concretetype in [lltype.Float, lltype.SingleFloat]
  832. float_res = v_result.concretetype in [lltype.Float, lltype.SingleFloat]
  833. if not float_arg and not float_res:
  834. # some int -> some int cast
  835. return self._int_to_int_cast(v_arg, v_result)
  836. elif float_arg and float_res:
  837. # some float -> some float cast
  838. return self._float_to_float_cast(v_arg, v_result)
  839. elif not float_arg and float_res:
  840. # some int -> some float
  841. ops = []
  842. v2 = varoftype(lltype.Float)
  843. sizesign = rffi.size_and_sign(v_arg.concretetype)
  844. if sizesign <= rffi.size_and_sign(lltype.Signed):
  845. # cast from a type that fits in an int: either the size is
  846. # smaller, or it is equal and it is not unsigned
  847. v1 = varoftype(lltype.Signed)
  848. oplist = self.rewrite_operation(
  849. SpaceOperation('force_cast', [v_arg], v1)
  850. )
  851. if oplist:
  852. ops.extend(oplist)
  853. else:
  854. v1 = v_arg
  855. op = self.rewrite_operation(
  856. SpaceOperation('cast_int_to_float', [v1], v2)
  857. )
  858. ops.append(op)
  859. else:
  860. if sizesign == rffi.size_and_sign(lltype.Unsigned):
  861. opname = 'cast_uint_to_float'
  862. elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
  863. opname = 'cast_longlong_to_float'
  864. elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
  865. opname = 'cast_ulonglong_to_float'
  866. else:
  867. raise AssertionError('cast_x_to_float: %r' % (sizesign,))
  868. ops1 = self.rewrite_operation(
  869. SpaceOperation(opname, [v_arg], v2)
  870. )
  871. if not isinstance(ops1, list): ops1 = [ops1]
  872. ops.extend(ops1)
  873. op2 = self.rewrite_operation(
  874. SpaceOperation('force_cast', [v2], v_result)
  875. )
  876. if op2:
  877. ops.append(op2)
  878. else:
  879. ops[-1].result = v_result
  880. return ops
  881. elif float_arg and not float_res:
  882. # some float -> some int
  883. ops = []
  884. v1 = varoftype(lltype.Float)
  885. op1 = self.rewrite_operation(
  886. SpaceOperation('force_cast', [v_arg], v1)
  887. )
  888. if op1:
  889. ops.append(op1)
  890. else:
  891. v1 = v_arg
  892. sizesign = rffi.size_and_sign(v_result.concretetype)
  893. if sizesign <= rffi.size_and_sign(lltype.Signed):
  894. # cast to a type that fits in an int: either the size is
  895. # smaller, or it is equal and it is not unsigned
  896. v2 = varoftype(lltype.Signed)
  897. op = self.rewrite_operation(
  898. SpaceOperation('cast_float_to_int', [v1], v2)
  899. )
  900. ops.append(op)
  901. oplist = self.rewrite_operation(
  902. SpaceOperation('force_cast', [v2], v_result)
  903. )
  904. if oplist:
  905. ops.extend(oplist)
  906. else:
  907. op.result = v_result
  908. else:
  909. if sizesign == rffi.size_and_sign(lltype.Unsigned):
  910. opname = 'cast_float_to_uint'
  911. elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
  912. opname = 'cast_float_to_longlong'
  913. elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
  914. opname = 'cast_float_to_ulonglong'
  915. else:
  916. raise AssertionError('cast_float_to_x: %r' % (sizesign,))
  917. ops1 = self.rewrite_operation(
  918. SpaceOperation(opname, [v1], v_result)
  919. )
  920. if not isinstance(ops1, list): ops1 = [ops1]
  921. ops.extend(ops1)
  922. return ops
  923. else:
  924. assert False
  925. def _int_to_int_cast(self, v_arg, v_result):
  926. longlong_arg = longlong.is_longlong(v_arg.concretetype)
  927. longlong_res = longlong.is_longlong(v_result.concretetype)
  928. size1, unsigned1 = rffi.size_and_sign(v_arg.concretetype)
  929. size2, unsigned2 = rffi.size_and_sign(v_result.concretetype)
  930. if longlong_arg and longlong_res:
  931. return
  932. elif longlong_arg:
  933. v = varoftype(lltype.Signed)
  934. op1 = self.rewrite_operation(
  935. SpaceOperation('truncate_longlong_to_int', [v_arg], v)
  936. )
  937. op2 = SpaceOperation('force_cast', [v], v_result)
  938. oplist = self.rewrite_operation(op2)
  939. if not oplist:
  940. op1.result = v_result
  941. oplist = []
  942. return [op1] + oplist
  943. elif longlong_res:
  944. if unsigned1:
  945. INTERMEDIATE = lltype.Unsigned
  946. else:
  947. INTERMEDIATE = lltype.Signed
  948. v = varoftype(INTERMEDIATE)
  949. op1 = SpaceOperation('force_cast', [v_arg], v)
  950. oplist = self.rewrite_operation(op1)
  951. if not oplist:
  952. v = v_arg
  953. oplist = []
  954. if unsigned1:
  955. if unsigned2:
  956. opname = 'cast_uint_to_ulonglong'
  957. else:
  958. opname = 'cast_uint_to_longlong'
  959. else:
  960. if unsigned2:
  961. opname = 'cast_int_to_ulonglong'
  962. else:
  963. opname = 'cast_int_to_longlong'
  964. op2 = self.rewrite_operation(
  965. SpaceOperation(opname, [v], v_result)
  966. )
  967. return oplist + [op2]
  968. # We've now, ostensibly, dealt with the longlongs, everything should be
  969. # a Signed or smaller
  970. assert size1 <= rffi.sizeof(lltype.Signed)
  971. assert size2 <= rffi.sizeof(lltype.Signed)
  972. # the target type is LONG or ULONG
  973. if size2 == rffi.sizeof(lltype.Signed):
  974. return
  975. min1, max1 = integer_bounds(size1, unsigned1)
  976. min2, max2 = integer_bounds(size2, unsigned2)
  977. # the target type includes the source range
  978. if min2 <= min1 <= max1 <= max2:
  979. return
  980. result = []
  981. if min2:
  982. c_min2 = Constant(min2, lltype.Signed)
  983. v2 = varoftype(lltype.Signed)
  984. result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2))
  985. else:
  986. v2 = v_arg
  987. c_mask = Constant(int((1 << (8 * size2)) - 1), lltype.Signed)
  988. if min2:
  989. v3 = varoftype(lltype.Signed)
  990. else:
  991. v3 = v_result
  992. result.append(SpaceOperation('int_and', [v2, c_mask], v3))
  993. if min2:
  994. result.append(SpaceOperation('int_add', [v3, c_min2], v_result))
  995. return result
  996. def _float_to_float_cast(self, v_arg, v_result):
  997. if v_arg.concretetype == lltype.SingleFloat:
  998. assert v_result.concretetype == lltype.Float, "cast %s -> %s" % (
  999. v_arg.concretetype, v_result.concretetype)
  1000. return SpaceOperation('cast_singlefloat_to_float', [v_arg],
  1001. v_result)
  1002. if v_result.concretetype == lltype.SingleFloat:
  1003. assert v_arg.concretetype == lltype.Float, "cast %s -> %s" % (
  1004. v_arg.concretetype, v_result.concretetype)
  1005. return SpaceOperation('cast_float_to_singlefloat', [v_arg],
  1006. v_result)
  1007. def rewrite_op_direct_ptradd(self, op):
  1008. # xxx otherwise, not implemented:
  1009. assert op.args[0].concretetype == rffi.CCHARP
  1010. #
  1011. return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result)
  1012. # ----------
  1013. # Long longs, for 32-bit only. Supported operations are left unmodified,
  1014. # and unsupported ones are turned into a call to a function from
  1015. # jit.codewriter.support.
  1016. for _op, _oopspec in [('llong_invert', 'INVERT'),
  1017. ('llong_lt', 'LT'),
  1018. ('llong_le', 'LE'),
  1019. ('llong_eq', 'EQ'),
  1020. ('llong_ne', 'NE'),
  1021. ('llong_gt', 'GT'),
  1022. ('llong_ge', 'GE'),
  1023. ('llong_add', 'ADD'),
  1024. ('llong_sub', 'SUB'),
  1025. ('llong_mul', 'MUL'),
  1026. ('llong_and', 'AND'),
  1027. ('llong_or', 'OR'),
  1028. ('llong_xor', 'XOR'),
  1029. ('llong_lshift', 'LSHIFT'),
  1030. ('llong_rshift', 'RSHIFT'),
  1031. ('cast_int_to_longlong', 'FROM_INT'),
  1032. ('truncate_longlong_to_int', 'TO_INT'),
  1033. ('cast_float_to_longlong', 'FROM_FLOAT'),
  1034. ('cast_longlong_to_float', 'TO_FLOAT'),
  1035. ('cast_uint_to_longlong', 'FROM_UINT'),
  1036. ]:
  1037. exec py.code.Source('''
  1038. def rewrite_op_%s(self, op):
  1039. args = op.args
  1040. op1 = self.prepare_builtin_call(op, "llong_%s", args)
  1041. op2 = self._handle_oopspec_call(op1, args,
  1042. EffectInfo.OS_LLONG_%s,
  1043. EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
  1044. if %r == "TO_INT":
  1045. assert op2.result.concretetype == lltype.Signed
  1046. return op2
  1047. ''' % (_op, _oopspec.lower(), _oopspec, _oopspec)).compile()
  1048. for _op, _oopspec in [('cast_int_to_ulonglong', 'FROM_INT'),
  1049. ('cast_uint_to_ulonglong', 'FROM_UINT'),
  1050. ('cast_float_to_ulonglong', 'FROM_FLOAT'),
  1051. ('cast_ulonglong_to_float', 'U_TO_FLOAT'),
  1052. ('ullong_invert', 'INVERT'),
  1053. ('ullong_lt', 'ULT'),
  1054. ('ullong_le', 'ULE'),
  1055. ('ullong_eq', 'EQ'),
  1056. ('ullong_ne', 'NE'),
  1057. ('ullong_gt', 'UGT'),
  1058. ('ullong_ge', 'UGE'),
  1059. ('ullong_add', 'ADD'),
  1060. ('ullong_sub', 'SUB'),
  1061. ('ullong_mul', 'MUL'),
  1062. ('ullong_and', 'AND'),
  1063. ('ullong_or', 'OR'),
  1064. ('ullong_xor', 'XOR'),
  1065. ('ullong_lshift', 'LSHIFT'),
  1066. ('ullong_rshift', 'URSHIFT'),
  1067. ]:
  1068. exec py.code.Source('''
  1069. def rewrite_op_%s(self, op):
  1070. args = op.args
  1071. op1 = self.prepare_builtin_call(op, "ullong_%s", args)
  1072. op2 = self._handle_oopspec_call(op1, args,
  1073. EffectInfo.OS_LLONG_%s,
  1074. EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
  1075. return op2
  1076. ''' % (_op, _oopspec.lower(), _oopspec)).compile()
  1077. def _normalize(self, oplist):
  1078. if isinstance(oplist, SpaceOperation):
  1079. return [oplist]
  1080. else:
  1081. assert type(oplist) is list
  1082. return oplist
  1083. def rewrite_op_llong_neg(self, op):
  1084. v = varoftype(lltype.SignedLongLong)
  1085. op0 = SpaceOperation('cast_int_to_longlong',
  1086. [Constant(0, lltype.Signed)],
  1087. v)
  1088. args = [v, op.args[0]]
  1089. op1 = SpaceOperation('llong_sub', args, op.result)
  1090. return (self._normalize(self.rewrite_operation(op0)) +
  1091. self._normalize(self.rewrite_operation(op1)))
  1092. def rewrite_op_llong_is_true(self, op):
  1093. v = varoftype(op.args[0].concretetype)
  1094. op0 = SpaceOperation('cast_primitive',
  1095. [Constant(0, lltype.Signed)],
  1096. v)
  1097. args = [op.args[0], v]
  1098. op1 = SpaceOperation('llong_ne', args, op.result)
  1099. return (self._normalize(self.rewrite_operation(op0)) +
  1100. self._normalize(self.rewrite_operation(op1)))
  1101. rewrite_op_ullong_is_true = rewrite_op_llong_is_true
  1102. def rewrite_op_cast_primitive(self, op):
  1103. return self.rewrite_op_force_cast(op)
  1104. # ----------
  1105. # Renames, from the _old opname to the _new one.
  1106. # The new operation is optionally further processed by rewrite_operation().
  1107. for _old, _new in [('bool_not', 'int_is_zero'),
  1108. ('cast_bool_to_float', 'cast_int_to_float'),
  1109. ('int_add_nonneg_ovf', 'int_add_ovf'),
  1110. ('keepalive', '-live-'),
  1111. ('char_lt', 'int_lt'),
  1112. ('char_le', 'int_le'),
  1113. ('char_eq', 'int_eq'),
  1114. ('char_ne', 'int_ne'),
  1115. ('char_gt', 'int_gt'),
  1116. ('char_ge', 'int_ge'),
  1117. ('unichar_eq', 'int_eq'),
  1118. ('unichar_ne', 'int_ne'),
  1119. ('uint_is_true', 'int_is_true'),
  1120. ('uint_invert', 'int_invert'),
  1121. ('uint_add', 'int_add'),
  1122. ('uint_sub', 'int_sub'),
  1123. ('uint_mul', 'int_mul'),
  1124. ('uint_eq', 'int_eq'),
  1125. ('uint_ne', 'int_ne'),
  1126. ('uint_and', 'int_and'),
  1127. ('uint_or', 'int_or'),
  1128. ('uint_lshift', 'int_lshift'),
  1129. ('uint_xor', 'int_xor'),
  1130. ]:
  1131. assert _old not in locals()
  1132. exec py.code.Source('''
  1133. def rewrite_op_%s(self, op):
  1134. op1 = SpaceOperation(%r, op.args, op.result)
  1135. return self.rewrite_operation(op1)
  1136. ''' % (_old, _new)).compile()
  1137. def rewrite_op_int_neg_ovf(self, op):
  1138. op1 = SpaceOperation('int_sub_ovf',
  1139. [Constant(0, lltype.Signed), op.args[0]],
  1140. op.result)
  1141. return self.rewrite_operation(op1)
  1142. def rewrite_op_float_is_true(self, op):
  1143. op1 = SpaceOperation('float_ne',
  1144. [op.args[0], Constant(0.0, lltype.Float)],
  1145. op.result)
  1146. return self.rewrite_operation(op1)
  1147. def rewrite_op_int_is_true(self, op):
  1148. if isinstance(op.args[0], Constant):
  1149. value = op.args[0].value
  1150. if value is objectmodel.malloc_zero_filled:
  1151. value = True
  1152. elif value is _we_are_jitted:
  1153. value = True
  1154. else:
  1155. raise AssertionError("don't know the truth value of %r"
  1156. % (value,))
  1157. return Constant(value, lltype.Bool)
  1158. return op
  1159. def promote_greens(self, args, jitdriver):
  1160. ops = []
  1161. num_green_args = len(jitdriver.greens)
  1162. assert len(args) == num_green_args + len(jitdriver.reds)
  1163. for v in args[:num_green_args]:
  1164. if isinstance(v, Variable) and v.concretetype is not lltype.Void:
  1165. kind = getkind(v.concretetype)
  1166. ops.append(SpaceOperation('-live-', [], None))
  1167. ops.append(SpaceOperation('%s_guard_value' % kind,
  1168. [v], None))
  1169. return ops
  1170. def rewrite_op_jit_marker(self, op):
  1171. key = op.args[0].value
  1172. jitdriver = op.args[1].value
  1173. if not jitdriver.active:
  1174. return []
  1175. return getattr(self, 'handle_jit_marker__%s' % key)(op, jitdriver)
  1176. def handle_jit_marker__jit_merge_point(self, op, jitdriver):
  1177. assert self.portal_jd is not None, (
  1178. "'jit_merge_point' in non-portal graph!")
  1179. assert jitdriver is self.portal_jd.jitdriver, (
  1180. "general mix-up of jitdrivers?")
  1181. ops = self.promote_greens(op.args[2:], jitdriver)
  1182. num_green_args = len(jitdriver.greens)
  1183. redlists = self.make_three_lists(op.args[2+num_green_args:])
  1184. for redlist in redlists:
  1185. for v in redlist:
  1186. assert isinstance(v, Variable), (
  1187. "Constant specified red in jit_merge_point()")
  1188. assert len(dict.fromkeys(redlist)) == len(list(redlist)), (
  1189. "duplicate red variable on jit_merge_point()")
  1190. args = ([Constant(self.portal_jd.index, lltype.Signed)] +
  1191. self.make_three_lists(op.args[2:2+num_green_args]) +
  1192. redlists)
  1193. op1 = SpaceOperation('jit_merge_point', args, None)
  1194. op2 = SpaceOperation('-live-', [], None)
  1195. # ^^^ we need a -live- for the case of do_recursive_call()
  1196. op3 = SpaceOperation('-live-', [], None)
  1197. # and one for inlined short preambles
  1198. return ops + [op3, op1, op2]
  1199. def handle_jit_marker__loop_header(self, op, jitdriver):
  1200. jd = self.callcontrol.jitdriver_sd_from_jitdriver(jitdriver)
  1201. assert jd is not None
  1202. c_index = Constant(jd.index, lltype.Signed)
  1203. return SpaceOperation('loop_header', [c_index], None)
  1204. # a 'can_enter_jit' in the source graph becomes a 'loop_header'
  1205. # operation in the transformed graph, as its only purpose in
  1206. # the transformed graph is to detect loops.
  1207. handle_jit_marker__can_enter_jit = handle_jit_marker__loop_header
  1208. def rewrite_op_debug_assert(self, op):
  1209. log.WARNING("found debug_assert in %r; should have be removed" %
  1210. (self.graph,))
  1211. return []
  1212. def _handle_jit_call(self, op, oopspec_name, args):
  1213. if oopspec_name == 'jit.debug':
  1214. return SpaceOperation('jit_debug', args, None)
  1215. elif oopspec_name == 'jit.assert_green':
  1216. kind = getkind(args[0].concretetype)
  1217. return SpaceOperation('%s_assert_green' % kind, args, None)
  1218. elif oopspec_name == 'jit.current_trace_length':
  1219. return SpaceOperation('current_trace_length', [], op.result)
  1220. elif oopspec_name == 'jit.isconstant':
  1221. kind = getkind(args[0].concretetype)
  1222. return SpaceOperation('%s_isconstant' % kind, args, op.result)
  1223. elif oopspec_name == 'jit.isvirtual':
  1224. kind = getkind(args[0].concretetype)
  1225. return SpaceOperation('%s_isvirtual' % kind, args, op.result)
  1226. else:
  1227. raise AssertionError("missing support for %r" % oopspec_name)
  1228. # ----------
  1229. # Lists.
  1230. def _handle_list_call(self, op, oopspec_name, args):
  1231. """Try to transform the call to a list-handling helper.
  1232. If no transformation is available, raise NotSupported
  1233. (in which case the original call is written as a residual call).
  1234. """
  1235. if oopspec_name.startswith('new'):
  1236. LIST = deref(op.result.concretetype)
  1237. else:
  1238. LIST = deref(args[0].concretetype)
  1239. resizable = isinstance(LIST, lltype.GcStruct)
  1240. assert resizable == (not isinstance(LIST, lltype.GcArray))
  1241. if resizable:
  1242. prefix = 'do_resizable_'
  1243. ARRAY = LIST.items.TO
  1244. if self._array_of_voids(ARRAY):
  1245. prefix += 'void_'
  1246. descrs = ()
  1247. else:
  1248. descrs = (self.cpu.arraydescrof(ARRAY),
  1249. self.cpu.fielddescrof(LIST, 'length'),
  1250. self.cpu.fielddescrof(LIST, 'items'),
  1251. self.cpu.sizeof(LIST))
  1252. else:
  1253. prefix = 'do_fixed_'
  1254. if self._array_of_voids(LIST):
  1255. prefix += 'void_'
  1256. descrs = ()
  1257. else:
  1258. arraydescr = self.cpu.arraydescrof(LIST)
  1259. descrs = (arraydescr,)
  1260. #
  1261. try:
  1262. meth = getattr(self, prefix + oopspec_name.replace('.', '_'))
  1263. except AttributeError:
  1264. raise NotSupported(prefix + oopspec_name)
  1265. return meth(op, args, *descrs)
  1266. def _get_list_nonneg_canraise_flags(self, op):
  1267. # XXX as far as I can see, this function will always return True
  1268. # because functions that are neither nonneg nor fast don't have an
  1269. # oopspec any more
  1270. # xxx break of abstraction:
  1271. func = get_funcobj(op.args[0].value)._callable
  1272. # base hints on the name of the ll function, which is a bit xxx-ish
  1273. # but which is safe for now
  1274. assert func.func_name.startswith('ll_')
  1275. # check that we have carefully placed the oopspec in
  1276. # pypy/rpython/rlist.py. There should not be an oopspec on
  1277. # a ll_getitem or ll_setitem that expects a 'func' argument.
  1278. # The idea is that a ll_getitem/ll_setitem with dum_checkidx
  1279. # should get inlined by the JIT, so that we see the potential
  1280. # 'raise IndexError'.
  1281. assert 'func' not in func.func_code.co_varnames
  1282. non_negative = '_nonneg' in func.func_name
  1283. fast = '_fast' in func.func_name
  1284. return non_negative or fast
  1285. def _prepare_list_getset(self, op, descr, args, checkname):
  1286. non_negative = self._get_list_nonneg_canraise_flags(op)
  1287. if non_negative:
  1288. return args[1], []
  1289. else:
  1290. v_posindex = Variable('posindex')
  1291. v_posindex.concretetype = lltype.Signed
  1292. op0 = SpaceOperation('-live-', [], None)
  1293. op1 = SpaceOperation(checkname, [args[0],
  1294. descr, args[1]], v_posindex)
  1295. return v_posindex, [op0, op1]
  1296. def _prepare_void_list_getset(self, op):
  1297. # sanity check:
  1298. self._get_list_nonneg_canraise_flags(op)
  1299. def _get_initial_newlist_length(self, op, args):
  1300. # normalize number of arguments to the 'newlist' function
  1301. if len(args) > 1:
  1302. v_default = args[1] # initial value: must be 0 or NULL
  1303. ARRAY = deref(op.result.concretetype)
  1304. if (not isinstance(v_default, Constant) or
  1305. v_default.value != arrayItem(ARRAY)._defl()):
  1306. raise NotSupported("variable or non-null initial value")
  1307. if len(args) >= 1:
  1308. return args[0]
  1309. else:
  1310. return Constant(0, lltype.Signed) # length: default to 0
  1311. # ---------- fixed lists ----------
  1312. def do_fixed_newlist(self, op, args, arraydescr):
  1313. v_length = self._get_initial_newlist_length(op, args)
  1314. return SpaceOperation('new_array', [arraydescr, v_length], op.result)
  1315. def do_fixed_list_len(self, op, args, arraydescr):
  1316. if args[0] in self.vable_array_vars: # virtualizable array
  1317. vars = self.vable_array_vars[args[0]]
  1318. (v_base, arrayfielddescr, arraydescr) = vars
  1319. return [SpaceOperation('-live-', [], None),
  1320. SpaceOperation('arraylen_vable',
  1321. [v_base, arrayfielddescr, arraydescr],
  1322. op.result)]
  1323. return SpaceOperation('arraylen_gc', [args[0], arraydescr], op.result)
  1324. do_fixed_list_len_foldable = do_fixed_list_len
  1325. def do_fixed_list_getitem(self, op, args, arraydescr, pure=False):
  1326. if args[0] in self.vable_array_vars: # virtualizable array
  1327. vars = self.vable_array_vars[args[0]]
  1328. (v_base, arrayfielddescr, arraydescr) = vars
  1329. kind = getkind(op.result.concretetype)
  1330. return [SpaceOperation('-live-', [], None),
  1331. SpaceOperation('getarrayitem_vable_%s' % kind[0],
  1332. [v_base, arrayfielddescr, arraydescr,
  1333. args[1]], op.result)]
  1334. v_index, extraop = self._prepare_list_getset(op, arraydescr, args,
  1335. 'check_neg_index')
  1336. extra = getkind(op.result.concretetype)[0]
  1337. if pure:
  1338. extra = 'pure_' + extra
  1339. op = SpaceOperation('getarrayitem_gc_%s' % extra,
  1340. [args[0], arraydescr, v_index], op.result)
  1341. return extraop + [op]
  1342. def do_fixed_list_getitem_foldable(self, op, args, arraydescr):
  1343. return self.do_fixed_list_getitem(op, args, arraydescr, pure=True)
  1344. def do_fixed_list_setitem(self, op, args, arraydescr):
  1345. if args[0] in self.vable_array_vars: # virtualizable array
  1346. vars = self.vable_array_vars[args[0]]
  1347. (v_base, arrayfielddescr, arraydescr) = vars
  1348. kind = getkind(args[2].concretetype)
  1349. return [SpaceOperation('-live-', [], None),
  1350. SpaceOperation('setarrayitem_vable_%s' % kind[0],
  1351. [v_base, arrayfielddescr, arraydescr,
  1352. args[1], args[2]], None)]
  1353. v_index, extraop = self._prepare_list_getset(op, arraydescr, args,
  1354. 'check_neg_index')
  1355. kind = getkind(args[2].concretetype)[0]
  1356. op = SpaceOperation('setarrayitem_gc_%s' % kind,
  1357. [args[0], arraydescr, v_index, args[2]], None)
  1358. return extraop + [op]
  1359. def do_fixed_list_ll_arraycopy(self, op, args, arraydescr):
  1360. return self._handle_oopspec_call(op, args, EffectInfo.OS_ARRAYCOPY)
  1361. def do_fixed_void_list_getitem(self, op, args):
  1362. self._prepare_void_list_getset(op)
  1363. return []
  1364. do_fixed_void_list_getitem_foldable = do_fixed_void_list_getitem
  1365. do_fixed_void_list_setitem = do_fixed_void_list_getitem
  1366. # ---------- resizable lists ----------
  1367. def do_resizable_newlist(self, op, args, arraydescr, lengthdescr,
  1368. itemsdescr, structdescr):
  1369. v_length = self._get_initial_newlist_length(op, args)
  1370. return SpaceOperation('newlist',
  1371. [structdescr, lengthdescr, itemsdescr,
  1372. arraydescr, v_length],
  1373. op.result)
  1374. def do_resizable_newlist_hint(self, op, args, arraydescr, lengthdescr,
  1375. itemsdescr, structdescr):
  1376. v_hint = self._get_initial_newlist_length(op, args)
  1377. return SpaceOperation('newlist_hint',
  1378. [structdescr, lengthdescr, itemsdescr,
  1379. arraydescr, v_hint],
  1380. op.result)
  1381. def do_resizable_list_getitem(self, op, args, arraydescr, lengthdescr,
  1382. itemsdescr, structdescr):
  1383. v_index, extraop = self._prepare_list_getset(op, lengthdescr, args,
  1384. 'check_resizable_neg_index')
  1385. kind = getkind(op.result.concretetype)[0]
  1386. op = SpaceOperation('getlistitem_gc_%s' % kind,
  1387. [args[0], itemsdescr, arraydescr, v_index],
  1388. op.result)
  1389. return extraop + [op]
  1390. def do_resizable_list_setitem(self, op, args, arraydescr, lengthdescr,
  1391. itemsdescr, structdescr):
  1392. v_index, extraop = self._prepare_list_getset(op, lengthdescr, args,
  1393. 'check_resizable_neg_index')
  1394. kind = getkind(args[2].concretetype)[0]
  1395. op = SpaceOperation('setlistitem_gc_%s' % kind,
  1396. [args[0], itemsdescr, arraydescr,
  1397. v_index, args[2]], None)
  1398. return extraop + [op]
  1399. def do_resizable_list_len(self, op, args, arraydescr, lengthdescr,
  1400. itemsdescr, structdescr):
  1401. return SpaceOperation('getfield_gc_i',
  1402. [args[0], lengthdescr], op.result)
  1403. def do_resizable_void_list_getitem(self, op, args):
  1404. self._prepare_void_list_getset(op)
  1405. return []
  1406. do_resizable_void_list_getitem_foldable = do_resizable_void_list_getitem
  1407. do_resizable_void_list_setitem = do_resizable_void_list_getitem
  1408. # ----------
  1409. # Strings and Unicodes.
  1410. def _handle_oopspec_call(self, op, args, oopspecindex, extraeffect=None):
  1411. calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
  1412. extraeffect)
  1413. if extraeffect is not None:
  1414. assert (is_test_calldescr(calldescr) # for tests
  1415. or calldescr.get_extra_info().extraeffect == extraeffect)
  1416. if isinstance(op.args[0].value, str):
  1417. pass # for tests only
  1418. else:
  1419. func = heaptracker.adr2int(
  1420. llmemory.cast_ptr_to_adr(op.args[0].value))
  1421. self.callcontrol.callinfocollection.add(oopspecindex,
  1422. calldescr, func)
  1423. op1 = self.rewrite_call(op, 'residual_call',
  1424. [op.args[0], calldescr],
  1425. args=args)
  1426. if self.callcontrol.calldescr_canraise(calldescr):
  1427. op1 = [op1, SpaceOperation('-live-', [], None)]
  1428. return op1
  1429. def _register_extra_helper(self, oopspecindex, oopspec_name,
  1430. argtypes, resulttype, effectinfo):
  1431. # a bit hackish
  1432. if self.callcontrol.callinfocollection.has_oopspec(oopspecindex):
  1433. return
  1434. c_func, TP = support.builtin_func_for_spec(self.cpu.rtyper,
  1435. oopspec_name, argtypes,
  1436. resulttype)
  1437. op = SpaceOperation('pseudo_call_cannot_raise',
  1438. [c_func] + [varoftype(T) for T in argtypes],
  1439. varoftype(resulttype))
  1440. calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
  1441. effectinfo)
  1442. if isinstance(c_func.value, str): # in tests only
  1443. func = c_func.value
  1444. else:
  1445. func = heaptracker.adr2int(
  1446. llmemory.cast_ptr_to_adr(c_func.value))
  1447. self.callcontrol.callinfocollection.add(oopspecindex, calldescr, func)
  1448. def _handle_stroruni_call(self, op, oopspec_name, args):
  1449. SoU = args[0].concretetype # Ptr(STR) or Ptr(UNICODE)
  1450. if SoU.TO == rstr.STR:
  1451. dict = {"stroruni.concat": EffectInfo.OS_STR_CONCAT,
  1452. "stroruni.slice": EffectInfo.OS_STR_SLICE,
  1453. "stroruni.equal": EffectInfo.OS_STR_EQUAL,
  1454. }
  1455. CHR = lltype.Char
  1456. elif SoU.TO == rstr.UNICODE:
  1457. dict = {"stroruni.concat": EffectInfo.OS_UNI_CONCAT,
  1458. "stroruni.slice": EffectInfo.OS_UNI_SLICE,
  1459. "stroruni.equal": EffectInfo.OS_UNI_EQUAL,
  1460. }
  1461. CHR = lltype.UniChar
  1462. else:
  1463. assert 0, "args[0].concretetype must be STR or UNICODE"
  1464. #
  1465. if oopspec_name == 'stroruni.copy_contents':
  1466. if SoU.TO == rstr.STR:
  1467. new_op = 'copystrcontent'
  1468. elif SoU.TO == rstr.UNICODE:
  1469. new_op = 'copyunicodecontent'
  1470. else:
  1471. assert 0
  1472. return SpaceOperation(new_op, args, op.result)
  1473. if oopspec_name == "stroruni.equal":
  1474. for otherindex, othername, argtypes, resulttype in [
  1475. (EffectInfo.OS_STREQ_SLICE_CHECKNULL,
  1476. "str.eq_slice_checknull",
  1477. [SoU, lltype.Signed, lltype.Signed, SoU],
  1478. lltype.Signed),
  1479. (EffectInfo.OS_STREQ_SLICE_NONNULL,
  1480. "str.eq_slice_nonnull",
  1481. [SoU, lltype.Signed, lltype.Signed, SoU],
  1482. lltype.Signed),
  1483. (EffectInfo.OS_STREQ_SLICE_CHAR,
  1484. "str.eq_slice_char",
  1485. [SoU, lltype.Signed, lltype.Signed, CHR],
  1486. lltype.Signed),
  1487. (EffectInfo.OS_STREQ_NONNULL,
  1488. "str.eq_nonnull",
  1489. [SoU, SoU],
  1490. lltype.Signed),
  1491. (EffectInfo.OS_STREQ_NONNULL_CHAR,
  1492. "str.eq_nonnull_char",
  1493. [SoU, CHR],
  1494. lltype.Signed),
  1495. (EffectInfo.OS_STREQ_CHECKNULL_CHAR,
  1496. "str.eq_checknull_char",
  1497. [SoU, CHR],
  1498. lltype.Signed),
  1499. (EffectInfo.OS_STREQ_LENGTHOK,
  1500. "str.eq_lengthok",
  1501. [SoU, SoU],
  1502. lltype.Signed),
  1503. ]:
  1504. if args[0].concretetype.TO == rstr.UNICODE:
  1505. otherindex += EffectInfo._OS_offset_uni
  1506. self._register_extra_helper(otherindex, othername,
  1507. argtypes, resulttype,
  1508. EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
  1509. #
  1510. return self._handle_oopspec_call(op, args, dict[oopspec_name],
  1511. EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
  1512. def _handle_str2unicode_call(self, op, oopspec_name, args):
  1513. # ll_str2unicode can raise UnicodeDecodeError
  1514. return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE,
  1515. EffectInfo.EF_ELIDABLE_CAN_RAISE)
  1516. # ----------
  1517. # VirtualRefs.
  1518. def _handle_virtual_ref_call(self, op, oopspec_name, args):
  1519. vrefinfo = self.callcontrol.virtualref_info
  1520. heaptracker.register_known_gctype(self.cpu,
  1521. vrefinfo.jit_virtual_ref_vtable,
  1522. vrefinfo.JIT_VIRTUAL_REF)
  1523. return SpaceOperation(oopspec_name, list(args), op.result)
  1524. # -----------
  1525. # rlib.libffi
  1526. def _handle_libffi_call(self, op, oopspec_name, args):
  1527. if oopspec_name == 'libffi_prepare_call':
  1528. oopspecindex = EffectInfo.OS_LIBFFI_PREPARE
  1529. extraeffect = EffectInfo.EF_CANNOT_RAISE
  1530. elif oopspec_name.startswith('libffi_push_'):
  1531. oopspecindex = EffectInfo.OS_LIBFFI_PUSH_ARG
  1532. extraeffect = EffectInfo.EF_CANNOT_RAISE
  1533. elif oopspec_name.startswith('libffi_call_'):
  1534. oopspecindex = EffectInfo.OS_LIBFFI_CALL
  1535. extraeffect = EffectInfo.EF_RANDOM_EFFECTS
  1536. elif oopspec_name == 'libffi_struct_getfield':
  1537. oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_GETFIELD
  1538. extraeffect = EffectInfo.EF_CANNOT_RAISE
  1539. elif oopspec_name == 'libffi_struct_setfield':
  1540. oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_SETFIELD
  1541. extraeffect = EffectInfo.EF_CANNOT_RAISE
  1542. elif oopspec_name == 'libffi_array_getitem':
  1543. oopspecindex = EffectInfo.OS_LIBFFI_GETARRAYITEM
  1544. extraeffect = EffectInfo.EF_CANNOT_RAISE
  1545. elif oopspec_name == 'libffi_array_setitem':
  1546. oopspecindex = EffectInfo.OS_LIBFFI_SETARRAYITEM
  1547. extraeffect = EffectInfo.EF_CANNOT_RAISE
  1548. else:
  1549. assert False, 'unsupported oopspec: %s' % oopspec_name
  1550. return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)
  1551. def rewrite_op_jit_force_virtual(self, op):
  1552. return self._do_builtin_call(op)
  1553. def rewrite_op_jit_is_virtual(self, op):
  1554. raise Exception, (
  1555. "'vref.virtual' should not be used from jit-visible code")
  1556. def rewrite_op_jit_force_virtualizable(self, op):
  1557. # this one is for virtualizables
  1558. vinfo = self.get_vinfo(op.args[0])
  1559. assert vinfo is not None
  1560. self.vable_flags[op.args[0]] = op.args[2].value
  1561. return []
  1562. # ---------
  1563. # ll_math.sqrt_nonneg()
  1564. def _handle_math_sqrt_call(self, op, oopspec_name, args):
  1565. return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT,
  1566. EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
  1567. def rewrite_op_jit_force_quasi_immutable(self, op):
  1568. v_inst, c_fieldname = op.args
  1569. descr1 = self.cpu.fielddescrof(v_inst.concretetype.TO,
  1570. c_fieldname.value)
  1571. op0 = SpaceOperation('-live-', [], None)
  1572. op1 = SpaceOperation('jit_force_quasi_immutable', [v_inst, descr1],
  1573. None)
  1574. return [op0, op1]
  1575. # ____________________________________________________________
  1576. class NotSupported(Exception):
  1577. pass
  1578. class VirtualizableArrayField(Exception):
  1579. def __str__(self):
  1580. return "using virtualizable array in illegal way in %r" % (
  1581. self.args[0],)
  1582. def is_test_calldescr(calldescr):
  1583. return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False)
  1584. def _with_prefix(prefix):
  1585. result = {}
  1586. for name in dir(Transformer):
  1587. if name.startswith(prefix):
  1588. result[name[len(prefix):]] = getattr(Transformer, name)
  1589. return result
  1590. def keep_operation_unchanged(jtransform, op):
  1591. return op
  1592. def _add_default_ops(rewrite_ops):
  1593. # All operations present in the BlackholeInterpreter as bhimpl_xxx
  1594. # but not explicitly listed in this file are supposed to be just
  1595. # passed in unmodified. All other operations are forbidden.
  1596. for key, value in BlackholeInterpreter.__dict__.items():
  1597. if key.startswith('bhimpl_'):
  1598. opname = key[len('bhimpl_'):]
  1599. rewrite_ops.setdefault(opname, keep_operation_unchanged)
  1600. rewrite_ops.setdefault('-live-', keep_operation_unchanged)
  1601. _rewrite_ops = _with_prefix('rewrite_op_')
  1602. _add_default_ops(_rewrite_ops)