PageRenderTime 59ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/jit/metainterp/optimizeopt/heap.py

https://bitbucket.org/pypy/pypy/
Python | 680 lines | 473 code | 69 blank | 138 comment | 140 complexity | 8123a0b7af4d1964785afa81b352cffe MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import os
  2. from collections import OrderedDict
  3. from rpython.jit.codewriter.effectinfo import EffectInfo
  4. from rpython.jit.metainterp.optimizeopt.util import args_dict
  5. from rpython.jit.metainterp.history import Const, ConstInt
  6. from rpython.jit.metainterp.jitexc import JitException
  7. from rpython.jit.metainterp.optimizeopt.optimizer import Optimization, REMOVED
  8. from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
  9. from rpython.jit.metainterp.optimizeopt.intutils import IntBound
  10. from rpython.jit.metainterp.optimizeopt.shortpreamble import PreambleOp
  11. from rpython.jit.metainterp.optimize import InvalidLoop
  12. from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers,\
  13. AbstractResOp, GuardResOp
  14. from rpython.rlib.objectmodel import we_are_translated
  15. from rpython.jit.metainterp.optimizeopt import info
  16. class BogusImmutableField(JitException):
  17. pass
  18. class AbstractCachedEntry(object):
  19. """ abstract base class abstracting over the difference between caching
  20. struct fields and array items. """
  21. def __init__(self):
  22. # Cache information for a field descr, or for an (array descr, index)
  23. # pair. It can be in one of two states:
  24. #
  25. # 1. 'cached_infos' is a list listing all the infos that are
  26. # caching this descr
  27. #
  28. # 2. we just did one set(field/arrayitem), which is delayed (and thus
  29. # not synchronized). '_lazy_set' is the delayed
  30. # ResOperation. In this state, 'cached_infos' contains
  31. # out-of-date information. More precisely, the field
  32. # value pending in the ResOperation is *not* visible in
  33. # 'cached_infos'.
  34. #
  35. self.cached_infos = []
  36. self.cached_structs = []
  37. self._lazy_set = None
  38. def register_info(self, structop, info):
  39. # invariant: every struct or array ptr info, that is not virtual and
  40. # that has a non-None entry at
  41. # info._fields[descr.get_index()]
  42. # must be in cache_infos
  43. self.cached_structs.append(structop)
  44. self.cached_infos.append(info)
  45. def produce_potential_short_preamble_ops(self, optimizer, shortboxes,
  46. descr, index=-1):
  47. assert self._lazy_set is None
  48. for i, info in enumerate(self.cached_infos):
  49. structbox = optimizer.get_box_replacement(self.cached_structs[i])
  50. info.produce_short_preamble_ops(structbox, descr, index, optimizer,
  51. shortboxes)
  52. def possible_aliasing(self, optheap, opinfo):
  53. # If lazy_set is set and contains a setfield on a different
  54. # structvalue, then we are annoyed, because it may point to either
  55. # the same or a different structure at runtime.
  56. # XXX constants?
  57. return (self._lazy_set is not None
  58. and (not optheap.getptrinfo(
  59. self._lazy_set.getarg(0)).same_info(opinfo)))
  60. def do_setfield(self, optheap, op):
  61. # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'.
  62. structinfo = optheap.ensure_ptr_info_arg0(op)
  63. arg1 = optheap.get_box_replacement(self._get_rhs_from_set_op(op))
  64. if self.possible_aliasing(optheap, structinfo):
  65. self.force_lazy_set(optheap, op.getdescr())
  66. assert not self.possible_aliasing(optheap, structinfo)
  67. cached_field = self._getfield(structinfo, op.getdescr(), optheap, False)
  68. if cached_field is not None:
  69. cached_field = optheap.get_box_replacement(cached_field)
  70. # Hack to ensure constants are imported from the preamble
  71. # XXX no longer necessary?
  72. #if cached_fieldvalue and fieldvalue.is_constant():
  73. # optheap.optimizer.ensure_imported(cached_fieldvalue)
  74. # cached_fieldvalue = self._cached_fields.get(structvalue, None)
  75. if not cached_field or not cached_field.same_box(arg1):
  76. # common case: store the 'op' as lazy_set
  77. self._lazy_set = op
  78. else:
  79. # this is the case where the pending setfield ends up
  80. # storing precisely the value that is already there,
  81. # as proved by 'cached_fields'. In this case, we don't
  82. # need any _lazy_set: the heap value is already right.
  83. # Note that this may reset to None a non-None lazy_set,
  84. # cancelling its previous effects with no side effect.
  85. # Now, we have to force the item in the short preamble
  86. self._getfield(structinfo, op.getdescr(), optheap)
  87. self._lazy_set = None
  88. def getfield_from_cache(self, optheap, opinfo, descr):
  89. # Returns the up-to-date field's value, or None if not cached.
  90. if self.possible_aliasing(optheap, opinfo):
  91. self.force_lazy_set(optheap, descr)
  92. if self._lazy_set is not None:
  93. op = self._lazy_set
  94. return optheap.get_box_replacement(self._get_rhs_from_set_op(op))
  95. else:
  96. res = self._getfield(opinfo, descr, optheap)
  97. if res is not None:
  98. return res.get_box_replacement()
  99. return None
  100. def force_lazy_set(self, optheap, descr, can_cache=True):
  101. op = self._lazy_set
  102. if op is not None:
  103. # This is the way _lazy_set is usually reset to None.
  104. # Now we clear _cached_fields, because actually doing the
  105. # setfield might impact any of the stored result (because of
  106. # possible aliasing).
  107. self.invalidate(descr)
  108. self._lazy_set = None
  109. if optheap.postponed_op:
  110. for a in op.getarglist():
  111. if a is optheap.postponed_op:
  112. optheap.emit_postponed_op()
  113. break
  114. optheap.next_optimization.propagate_forward(op)
  115. if not can_cache:
  116. return
  117. # Once it is done, we can put at least one piece of information
  118. # back in the cache: the value of this particular structure's
  119. # field.
  120. opinfo = optheap.ensure_ptr_info_arg0(op)
  121. self.put_field_back_to_info(op, opinfo, optheap)
  122. elif not can_cache:
  123. self.invalidate(descr)
  124. # abstract methods
  125. def _get_rhs_from_set_op(self, op):
  126. """ given a set(field or arrayitem) op, return the rhs argument """
  127. raise NotImplementedError("abstract method")
  128. def put_field_back_to_info(self, op, opinfo, optheap):
  129. """ this method is called just after a lazy setfield was ommitted. it
  130. puts the information of the lazy setfield back into the proper cache in
  131. the info. """
  132. raise NotImplementedError("abstract method")
  133. def _getfield(self, opinfo, descr, optheap, true_force=True):
  134. raise NotImplementedError("abstract method")
  135. def invalidate(self, descr):
  136. """ clear all the cached knowledge in the infos in self.cached_infos.
  137. """
  138. raise NotImplementedError("abstract method")
  139. class CachedField(AbstractCachedEntry):
  140. def _get_rhs_from_set_op(self, op):
  141. return op.getarg(1)
  142. def put_field_back_to_info(self, op, opinfo, optheap):
  143. arg = optheap.get_box_replacement(op.getarg(1))
  144. struct = optheap.get_box_replacement(op.getarg(0))
  145. opinfo.setfield(op.getdescr(), struct, arg, optheap=optheap, cf=self)
  146. def _getfield(self, opinfo, descr, optheap, true_force=True):
  147. res = opinfo.getfield(descr, optheap)
  148. if not we_are_translated() and res:
  149. if isinstance(opinfo, info.AbstractStructPtrInfo):
  150. assert opinfo in self.cached_infos
  151. if isinstance(res, PreambleOp):
  152. if not true_force:
  153. return res.op
  154. res = optheap.optimizer.force_op_from_preamble(res)
  155. opinfo.setfield(descr, None, res, optheap=optheap)
  156. return res
  157. def invalidate(self, descr):
  158. if descr.is_always_pure():
  159. return
  160. for opinfo in self.cached_infos:
  161. assert isinstance(opinfo, info.AbstractStructPtrInfo)
  162. opinfo._fields[descr.get_index()] = None
  163. self.cached_infos = []
  164. self.cached_structs = []
  165. class ArrayCachedItem(AbstractCachedEntry):
  166. def __init__(self, index):
  167. self.index = index
  168. AbstractCachedEntry.__init__(self)
  169. def _get_rhs_from_set_op(self, op):
  170. return op.getarg(2)
  171. def _getfield(self, opinfo, descr, optheap, true_force=True):
  172. res = opinfo.getitem(descr, self.index, optheap)
  173. if not we_are_translated() and res:
  174. if isinstance(opinfo, info.ArrayPtrInfo):
  175. assert opinfo in self.cached_infos
  176. if (isinstance(res, PreambleOp) and
  177. optheap.optimizer.cpu.supports_guard_gc_type):
  178. if not true_force:
  179. return res.op
  180. index = res.preamble_op.getarg(1).getint()
  181. res = optheap.optimizer.force_op_from_preamble(res)
  182. opinfo.setitem(descr, index, None, res, optheap=optheap)
  183. return res
  184. def put_field_back_to_info(self, op, opinfo, optheap):
  185. arg = optheap.get_box_replacement(op.getarg(2))
  186. struct = optheap.get_box_replacement(op.getarg(0))
  187. opinfo.setitem(op.getdescr(), self.index, struct, arg, optheap=optheap, cf=self)
  188. def invalidate(self, descr):
  189. for opinfo in self.cached_infos:
  190. assert isinstance(opinfo, info.ArrayPtrInfo)
  191. opinfo._items = None
  192. self.cached_infos = []
  193. self.cached_structs = []
  194. class OptHeap(Optimization):
  195. """Cache repeated heap accesses"""
  196. def __init__(self):
  197. # mapping descr -> CachedField
  198. self.cached_fields = OrderedDict()
  199. self.cached_arrayitems = OrderedDict()
  200. self.postponed_op = None
  201. # cached dict items: {dict descr: {(optval, index): box-or-const}}
  202. self.cached_dict_reads = {}
  203. # cache of corresponding {array descrs: dict 'entries' field descr}
  204. self.corresponding_array_descrs = {}
  205. #
  206. self._remove_guard_not_invalidated = False
  207. self._seen_guard_not_invalidated = False
  208. def setup(self):
  209. self.optimizer.optheap = self
  210. # mapping const value -> info corresponding to it's heap cache
  211. self.const_infos = self.optimizer.cpu.ts.new_ref_dict()
  212. def flush(self):
  213. self.cached_dict_reads.clear()
  214. self.corresponding_array_descrs.clear()
  215. self.force_all_lazy_sets()
  216. self.emit_postponed_op()
  217. def emit_postponed_op(self):
  218. if self.postponed_op:
  219. postponed_op = self.postponed_op
  220. self.postponed_op = None
  221. self.next_optimization.propagate_forward(postponed_op)
  222. def produce_potential_short_preamble_ops(self, sb):
  223. descrkeys = self.cached_fields.keys()
  224. if not we_are_translated():
  225. # XXX Pure operation of boxes that are cached in several places will
  226. # only be removed from the peeled loop when read from the first
  227. # place discovered here. This is far from ideal, as it makes
  228. # the effectiveness of our optimization a bit random. It should
  229. # howevere always generate correct results. For tests we dont
  230. # want this randomness.
  231. descrkeys.sort(key=str, reverse=True)
  232. for descr in descrkeys:
  233. d = self.cached_fields[descr]
  234. d.produce_potential_short_preamble_ops(self.optimizer, sb, descr)
  235. for descr, submap in self.cached_arrayitems.items():
  236. for index, d in submap.items():
  237. d.produce_potential_short_preamble_ops(self.optimizer, sb,
  238. descr, index)
  239. def clean_caches(self):
  240. items = self.cached_fields.items()
  241. if not we_are_translated():
  242. items.sort(key=str, reverse=True)
  243. for descr, cf in items:
  244. if not descr.is_always_pure():
  245. cf.invalidate(descr)
  246. for descr, submap in self.cached_arrayitems.iteritems():
  247. if not descr.is_always_pure():
  248. for index, cf in submap.iteritems():
  249. cf.invalidate(None)
  250. #self.cached_arrayitems.clear()
  251. self.cached_dict_reads.clear()
  252. def field_cache(self, descr):
  253. try:
  254. cf = self.cached_fields[descr]
  255. except KeyError:
  256. cf = self.cached_fields[descr] = CachedField()
  257. return cf
  258. def arrayitem_cache(self, descr, index):
  259. try:
  260. submap = self.cached_arrayitems[descr]
  261. except KeyError:
  262. submap = self.cached_arrayitems[descr] = {}
  263. try:
  264. cf = submap[index]
  265. except KeyError:
  266. cf = submap[index] = ArrayCachedItem(index)
  267. return cf
  268. def emit_operation(self, op):
  269. self.emitting_operation(op)
  270. self.emit_postponed_op()
  271. opnum = op.opnum
  272. if (rop.is_comparison(opnum) or rop.is_call_may_force(opnum)
  273. or rop.is_ovf(opnum)):
  274. self.postponed_op = op
  275. else:
  276. Optimization.emit_operation(self, op)
  277. def emitting_operation(self, op):
  278. if rop.has_no_side_effect(op.opnum):
  279. return
  280. if rop.is_ovf(op.opnum):
  281. return
  282. if rop.is_guard(op.opnum):
  283. self.optimizer.pendingfields = (
  284. self.force_lazy_sets_for_guard())
  285. return
  286. opnum = op.getopnum()
  287. if (opnum == rop.SETFIELD_GC or # handled specially
  288. opnum == rop.SETFIELD_RAW or # no effect on GC struct/array
  289. opnum == rop.SETARRAYITEM_GC or # handled specially
  290. opnum == rop.SETARRAYITEM_RAW or # no effect on GC struct
  291. opnum == rop.SETINTERIORFIELD_RAW or # no effect on GC struct
  292. opnum == rop.RAW_STORE or # no effect on GC struct
  293. opnum == rop.STRSETITEM or # no effect on GC struct/array
  294. opnum == rop.UNICODESETITEM or # no effect on GC struct/array
  295. opnum == rop.DEBUG_MERGE_POINT or # no effect whatsoever
  296. opnum == rop.JIT_DEBUG or # no effect whatsoever
  297. opnum == rop.ENTER_PORTAL_FRAME or # no effect whatsoever
  298. opnum == rop.LEAVE_PORTAL_FRAME or # no effect whatsoever
  299. opnum == rop.COPYSTRCONTENT or # no effect on GC struct/array
  300. opnum == rop.COPYUNICODECONTENT or # no effect on GC struct/array
  301. opnum == rop.CHECK_MEMORY_ERROR): # may only abort the whole loop
  302. return
  303. if rop.is_call(op.opnum):
  304. if rop.is_call_assembler(op.getopnum()):
  305. self._seen_guard_not_invalidated = False
  306. else:
  307. effectinfo = op.getdescr().get_extra_info()
  308. if effectinfo.check_can_invalidate():
  309. self._seen_guard_not_invalidated = False
  310. if not effectinfo.has_random_effects():
  311. self.force_from_effectinfo(effectinfo)
  312. return
  313. self.force_all_lazy_sets()
  314. self.clean_caches()
  315. def optimize_CALL_I(self, op):
  316. # dispatch based on 'oopspecindex' to a method that handles
  317. # specifically the given oopspec call. For non-oopspec calls,
  318. # oopspecindex is just zero.
  319. effectinfo = op.getdescr().get_extra_info()
  320. oopspecindex = effectinfo.oopspecindex
  321. if oopspecindex == EffectInfo.OS_DICT_LOOKUP:
  322. if self._optimize_CALL_DICT_LOOKUP(op):
  323. return
  324. self.emit_operation(op)
  325. optimize_CALL_F = optimize_CALL_I
  326. optimize_CALL_R = optimize_CALL_I
  327. optimize_CALL_N = optimize_CALL_I
  328. def _optimize_CALL_DICT_LOOKUP(self, op):
  329. # Cache consecutive lookup() calls on the same dict and key,
  330. # depending on the 'flag_store' argument passed:
  331. # FLAG_LOOKUP: always cache and use the cached result.
  332. # FLAG_STORE: don't cache (it might return -1, which would be
  333. # incorrect for future lookups); but if found in
  334. # the cache and the cached value was already checked
  335. # non-negative, then we can reuse it.
  336. # FLAG_DELETE: never cache, never use the cached result (because
  337. # if there is a cached result, the FLAG_DELETE call
  338. # is needed for its side-effect of removing it).
  339. # In theory we could cache a -1 for the case where
  340. # the delete is immediately followed by a lookup,
  341. # but too obscure.
  342. #
  343. from rpython.rtyper.lltypesystem.rordereddict import FLAG_LOOKUP
  344. from rpython.rtyper.lltypesystem.rordereddict import FLAG_STORE
  345. flag_value = self.getintbound(op.getarg(4))
  346. if not flag_value.is_constant():
  347. return False
  348. flag = flag_value.getint()
  349. if flag != FLAG_LOOKUP and flag != FLAG_STORE:
  350. return False
  351. #
  352. descrs = op.getdescr().get_extra_info().extradescrs
  353. assert descrs # translation hint
  354. descr1 = descrs[0]
  355. try:
  356. d = self.cached_dict_reads[descr1]
  357. except KeyError:
  358. d = self.cached_dict_reads[descr1] = args_dict()
  359. self.corresponding_array_descrs[descrs[1]] = descr1
  360. #
  361. key = [self.optimizer.get_box_replacement(op.getarg(1)), # dict
  362. self.optimizer.get_box_replacement(op.getarg(2))] # key
  363. # other args can be ignored here (hash, store_flag)
  364. try:
  365. res_v = d[key]
  366. except KeyError:
  367. if flag == FLAG_LOOKUP:
  368. d[key] = op
  369. return False
  370. else:
  371. if flag != FLAG_LOOKUP:
  372. if not self.getintbound(res_v).known_ge(IntBound(0, 0)):
  373. return False
  374. self.make_equal_to(op, res_v)
  375. self.last_emitted_operation = REMOVED
  376. return True
  377. def optimize_GUARD_NO_EXCEPTION(self, op):
  378. if self.last_emitted_operation is REMOVED:
  379. return
  380. self.emit_operation(op)
  381. optimize_GUARD_EXCEPTION = optimize_GUARD_NO_EXCEPTION
  382. def force_from_effectinfo(self, effectinfo):
  383. # Note: this version of the code handles effectively
  384. # effectinfos that store arbitrarily many descrs, by looping
  385. # on self.cached_{fields, arrayitems} and looking them up in
  386. # the bitstrings stored in the effectinfo.
  387. for fielddescr, cf in self.cached_fields.items():
  388. if effectinfo.check_readonly_descr_field(fielddescr):
  389. cf.force_lazy_set(self, fielddescr)
  390. if effectinfo.check_write_descr_field(fielddescr):
  391. if fielddescr.is_always_pure():
  392. continue
  393. try:
  394. del self.cached_dict_reads[fielddescr]
  395. except KeyError:
  396. pass
  397. cf.force_lazy_set(self, fielddescr, can_cache=False)
  398. #
  399. for arraydescr, submap in self.cached_arrayitems.items():
  400. if effectinfo.check_readonly_descr_array(arraydescr):
  401. self.force_lazy_setarrayitem_submap(submap)
  402. if effectinfo.check_write_descr_array(arraydescr):
  403. self.force_lazy_setarrayitem_submap(submap, can_cache=False)
  404. #
  405. for arraydescr, dictdescr in self.corresponding_array_descrs.items():
  406. if effectinfo.check_write_descr_array(arraydescr):
  407. try:
  408. del self.cached_dict_reads[dictdescr]
  409. except KeyError:
  410. pass # someone did it already
  411. #
  412. if effectinfo.check_forces_virtual_or_virtualizable():
  413. vrefinfo = self.optimizer.metainterp_sd.virtualref_info
  414. self.force_lazy_set(vrefinfo.descr_forced)
  415. # ^^^ we only need to force this field; the other fields
  416. # of virtualref_info and virtualizable_info are not gcptrs.
  417. def force_lazy_set(self, descr, can_cache=True):
  418. try:
  419. cf = self.cached_fields[descr]
  420. except KeyError:
  421. return
  422. cf.force_lazy_set(self, descr, can_cache)
  423. def force_lazy_setarrayitem(self, arraydescr, indexb=None, can_cache=True):
  424. try:
  425. submap = self.cached_arrayitems[arraydescr]
  426. except KeyError:
  427. return
  428. for idx, cf in submap.iteritems():
  429. if indexb is None or indexb.contains(idx):
  430. cf.force_lazy_set(self, None, can_cache)
  431. def force_lazy_setarrayitem_submap(self, submap, can_cache=True):
  432. for cf in submap.itervalues():
  433. cf.force_lazy_set(self, None, can_cache)
  434. def force_all_lazy_sets(self):
  435. items = self.cached_fields.items()
  436. if not we_are_translated():
  437. items.sort(key=str, reverse=True)
  438. for descr, cf in items:
  439. cf.force_lazy_set(self, descr)
  440. for submap in self.cached_arrayitems.itervalues():
  441. for index, cf in submap.iteritems():
  442. cf.force_lazy_set(self, None)
  443. def force_lazy_sets_for_guard(self):
  444. pendingfields = []
  445. items = self.cached_fields.items()
  446. if not we_are_translated():
  447. items.sort(key=str, reverse=True)
  448. for descr, cf in items:
  449. op = cf._lazy_set
  450. if op is None:
  451. continue
  452. val = op.getarg(1)
  453. if self.optimizer.is_virtual(val):
  454. pendingfields.append(op)
  455. continue
  456. cf.force_lazy_set(self, descr)
  457. for descr, submap in self.cached_arrayitems.iteritems():
  458. for index, cf in submap.iteritems():
  459. op = cf._lazy_set
  460. if op is None:
  461. continue
  462. # the only really interesting case that we need to handle in the
  463. # guards' resume data is that of a virtual object that is stored
  464. # into a field of a non-virtual object. Here, 'op' in either
  465. # SETFIELD_GC or SETARRAYITEM_GC.
  466. opinfo = self.getptrinfo(op.getarg(0))
  467. assert not opinfo.is_virtual() # it must be a non-virtual
  468. if self.optimizer.is_virtual(op.getarg(2)):
  469. pendingfields.append(op)
  470. else:
  471. cf.force_lazy_set(self, descr)
  472. return pendingfields
  473. def optimize_GETFIELD_GC_I(self, op):
  474. descr = op.getdescr()
  475. if descr.is_always_pure() and self.get_constant_box(op.getarg(0)) is not None:
  476. resbox = self.optimizer.constant_fold(op)
  477. self.optimizer.make_constant(op, resbox)
  478. return
  479. structinfo = self.ensure_ptr_info_arg0(op)
  480. cf = self.field_cache(descr)
  481. field = cf.getfield_from_cache(self, structinfo, descr)
  482. if field is not None:
  483. self.make_equal_to(op, field)
  484. return
  485. # default case: produce the operation
  486. self.make_nonnull(op.getarg(0))
  487. self.emit_operation(op)
  488. # then remember the result of reading the field
  489. structinfo.setfield(descr, op.getarg(0), op, optheap=self, cf=cf)
  490. optimize_GETFIELD_GC_R = optimize_GETFIELD_GC_I
  491. optimize_GETFIELD_GC_F = optimize_GETFIELD_GC_I
  492. def optimize_SETFIELD_GC(self, op):
  493. self.setfield(op)
  494. #opnum = OpHelpers.getfield_pure_for_descr(op.getdescr())
  495. #if self.has_pure_result(opnum, [op.getarg(0)],
  496. # op.getdescr()):
  497. # os.write(2, '[bogus _immutable_field_ declaration: %s]\n' %
  498. # (op.getdescr().repr_of_descr()))
  499. # raise BogusImmutableField
  500. #
  501. def setfield(self, op):
  502. cf = self.field_cache(op.getdescr())
  503. cf.do_setfield(self, op)
  504. def optimize_GETARRAYITEM_GC_I(self, op):
  505. arrayinfo = self.ensure_ptr_info_arg0(op)
  506. indexb = self.getintbound(op.getarg(1))
  507. cf = None
  508. if indexb.is_constant():
  509. index = indexb.getint()
  510. arrayinfo.getlenbound(None).make_gt_const(index)
  511. # use the cache on (arraydescr, index), which is a constant
  512. cf = self.arrayitem_cache(op.getdescr(), index)
  513. field = cf.getfield_from_cache(self, arrayinfo, op.getdescr())
  514. if field is not None:
  515. self.make_equal_to(op, field)
  516. return
  517. else:
  518. # variable index, so make sure the lazy setarrayitems are done
  519. self.force_lazy_setarrayitem(op.getdescr(),
  520. self.getintbound(op.getarg(1)))
  521. # default case: produce the operation
  522. self.make_nonnull(op.getarg(0))
  523. self.emit_operation(op)
  524. # then remember the result of reading the array item
  525. if cf is not None:
  526. arrayinfo.setitem(op.getdescr(), indexb.getint(),
  527. self.get_box_replacement(op.getarg(0)),
  528. self.get_box_replacement(op), optheap=self,
  529. cf=cf)
  530. optimize_GETARRAYITEM_GC_R = optimize_GETARRAYITEM_GC_I
  531. optimize_GETARRAYITEM_GC_F = optimize_GETARRAYITEM_GC_I
  532. def optimize_GETARRAYITEM_GC_PURE_I(self, op):
  533. arrayinfo = self.ensure_ptr_info_arg0(op)
  534. indexb = self.getintbound(op.getarg(1))
  535. cf = None
  536. if indexb.is_constant():
  537. index = indexb.getint()
  538. arrayinfo.getlenbound(None).make_gt_const(index)
  539. # use the cache on (arraydescr, index), which is a constant
  540. cf = self.arrayitem_cache(op.getdescr(), index)
  541. fieldvalue = cf.getfield_from_cache(self, arrayinfo, op.getdescr())
  542. if fieldvalue is not None:
  543. self.make_equal_to(op, fieldvalue)
  544. return
  545. else:
  546. # variable index, so make sure the lazy setarrayitems are done
  547. self.force_lazy_setarrayitem(op.getdescr(), self.getintbound(op.getarg(1)))
  548. # default case: produce the operation
  549. self.make_nonnull(op.getarg(0))
  550. self.emit_operation(op)
  551. optimize_GETARRAYITEM_GC_PURE_R = optimize_GETARRAYITEM_GC_PURE_I
  552. optimize_GETARRAYITEM_GC_PURE_F = optimize_GETARRAYITEM_GC_PURE_I
  553. def optimize_SETARRAYITEM_GC(self, op):
  554. #opnum = OpHelpers.getarrayitem_pure_for_descr(op.getdescr())
  555. #if self.has_pure_result(opnum, [op.getarg(0), op.getarg(1)],
  556. # op.getdescr()):
  557. # os.write(2, '[bogus immutable array declaration: %s]\n' %
  558. # (op.getdescr().repr_of_descr()))
  559. # raise BogusImmutableField
  560. #
  561. indexb = self.getintbound(op.getarg(1))
  562. if indexb.is_constant():
  563. arrayinfo = self.ensure_ptr_info_arg0(op)
  564. # arraybound
  565. arrayinfo.getlenbound(None).make_gt_const(indexb.getint())
  566. cf = self.arrayitem_cache(op.getdescr(), indexb.getint())
  567. cf.do_setfield(self, op)
  568. else:
  569. # variable index, so make sure the lazy setarrayitems are done
  570. self.force_lazy_setarrayitem(op.getdescr(), indexb, can_cache=False)
  571. # and then emit the operation
  572. self.emit_operation(op)
  573. def optimize_QUASIIMMUT_FIELD(self, op):
  574. # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr)
  575. # x = GETFIELD_GC(s, descr='inst_x') # pure
  576. # If 's' is a constant (after optimizations) we rely on the rest of the
  577. # optimizations to constant-fold the following pure getfield_gc.
  578. # in addition, we record the dependency here to make invalidation work
  579. # correctly.
  580. # NB: emitting the pure GETFIELD_GC is only safe because the
  581. # QUASIIMMUT_FIELD is also emitted to make sure the dependency is
  582. # registered.
  583. structvalue = self.ensure_ptr_info_arg0(op)
  584. if not structvalue.is_constant():
  585. self._remove_guard_not_invalidated = True
  586. return # not a constant at all; ignore QUASIIMMUT_FIELD
  587. #
  588. from rpython.jit.metainterp.quasiimmut import QuasiImmutDescr
  589. qmutdescr = op.getdescr()
  590. assert isinstance(qmutdescr, QuasiImmutDescr)
  591. # check that the value is still correct; it could have changed
  592. # already between the tracing and now. In this case, we mark the loop
  593. # as invalid
  594. if not qmutdescr.is_still_valid_for(
  595. self.get_box_replacement(op.getarg(0))):
  596. raise InvalidLoop('quasi immutable field changed during tracing')
  597. # record as an out-of-line guard
  598. if self.optimizer.quasi_immutable_deps is None:
  599. self.optimizer.quasi_immutable_deps = {}
  600. self.optimizer.quasi_immutable_deps[qmutdescr.qmut] = None
  601. self._remove_guard_not_invalidated = False
  602. def optimize_GUARD_NOT_INVALIDATED(self, op):
  603. if self._remove_guard_not_invalidated:
  604. return
  605. if self._seen_guard_not_invalidated:
  606. return
  607. self._seen_guard_not_invalidated = True
  608. self.emit_operation(op)
  609. dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_',
  610. default=OptHeap.emit_operation)
  611. OptHeap.propagate_forward = dispatch_opt