[pypy-commit] pypy optresult: get back to where we were with the correct CachedField and lazy_setfield
fijal
noreply at buildbot.pypy.org
Sat Mar 14 17:51:35 CET 2015
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: optresult
Changeset: r76370:f0ac69b41467
Date: 2015-03-14 18:51 +0200
http://bitbucket.org/pypy/pypy/changeset/f0ac69b41467/
Log: get back to where we were with the correct CachedField and
lazy_setfield
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -13,49 +13,71 @@
from rpython.rlib.objectmodel import we_are_translated
+class BogusPureField(JitException):
+ pass
+
+
class CachedField(object):
def __init__(self):
# Cache information for a field descr, or for an (array descr, index)
# pair. It can be in one of two states:
#
- # 1. 'cached_fields' is a dict mapping OptValues of structs
- # to OptValues of fields. All fields on-heap are
- # synchronized with the values stored in the cache.
+ # 1. 'cached_infos' is a list listing all the infos that are
+ # caching this descr
#
# 2. we just did one setfield, which is delayed (and thus
# not synchronized). 'lazy_setfield' is the delayed
- # ResOperation. In this state, 'cached_fields' contains
+ # ResOperation. In this state, 'cached_infos' contains
# out-of-date information. More precisely, the field
# value pending in the ResOperation is *not* visible in
- # 'cached_fields'.
+ # 'cached_infos'.
#
- Xxxx
- self._cached_fields = {}
- self._cached_fields_getfield_op = {}
+ self.cached_infos = []
self._lazy_setfield = None
self._lazy_setfield_registered = False
+ def register_dirty_field(self, info):
+ self.cached_infos.append(info)
+
+ def invalidate(self, descr):
+ for info in self.cached_infos:
+ info._fields = [None] * len(info._fields)
+ self.cached_infos = []
+
+
+ def possible_aliasing(self, optheap, opinfo):
+ # If lazy_setfield is set and contains a setfield on a different
+ # structvalue, then we are annoyed, because it may point to either
+ # the same or a different structure at runtime.
+ # XXX constants?
+ return (self._lazy_setfield is not None
+ and (optheap.getptrinfo(self._lazy_setfield.getarg(0))
+ is not opinfo))
+
def do_setfield(self, optheap, op):
# Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'.
- structvalue = optheap.getvalue(op.getarg(0))
- fieldvalue = optheap.getvalue(op.getarglist()[-1])
- if self.possible_aliasing(optheap, structvalue):
+ structinfo = optheap.ensure_ptr_info_arg0(op)
+ arg1 = optheap.get_box_replacement(op.getarg(1))
+ if self.possible_aliasing(optheap, structinfo):
+ xxx
self.force_lazy_setfield(optheap)
assert not self.possible_aliasing(optheap, structvalue)
- cached_fieldvalue = self._cached_fields.get(structvalue, None)
+ cached_field = structinfo.getfield(op.getdescr())
+ if cached_field is not None:
+ cached_field = optheap.get_box_replacement(cached_field)
# Hack to ensure constants are imported from the preamble
- if cached_fieldvalue and fieldvalue.is_constant():
- optheap.optimizer.ensure_imported(cached_fieldvalue)
- cached_fieldvalue = self._cached_fields.get(structvalue, None)
+ # XXX no longer necessary?
+ #if cached_fieldvalue and fieldvalue.is_constant():
+ # optheap.optimizer.ensure_imported(cached_fieldvalue)
+ # cached_fieldvalue = self._cached_fields.get(structvalue, None)
- if not fieldvalue.same_value(cached_fieldvalue):
+ if not cached_field or not cached_field.same_box(arg1):
# common case: store the 'op' as lazy_setfield, and register
# myself in the optheap's _lazy_setfields_and_arrayitems list
self._lazy_setfield = op
- if not self._lazy_setfield_registered:
- optheap._lazy_setfields_and_arrayitems.append(self)
- self._lazy_setfield_registered = True
+ #if not self._lazy_setfield_registered:
+ # self._lazy_setfield_registered = True
else:
# this is the case where the pending setfield ends up
@@ -66,44 +88,16 @@
# cancelling its previous effects with no side effect.
self._lazy_setfield = None
- def value_updated(self, oldvalue, newvalue, exporting_state):
- try:
- fieldvalue = self._cached_fields[oldvalue]
- except KeyError:
- pass
- else:
- self._cached_fields[newvalue] = fieldvalue
- if exporting_state:
- op = self._cached_fields_getfield_op[oldvalue].clone()
- op.setarg(0, newvalue.box)
- self._cached_fields_getfield_op[newvalue] = op
-
- def possible_aliasing(self, optheap, structvalue):
- # If lazy_setfield is set and contains a setfield on a different
- # structvalue, then we are annoyed, because it may point to either
- # the same or a different structure at runtime.
- return (self._lazy_setfield is not None
- and (optheap.getvalue(self._lazy_setfield.getarg(0))
- is not structvalue))
-
- def getfield_from_cache(self, optheap, structvalue):
+ def getfield_from_cache(self, optheap, opinfo, descr):
# Returns the up-to-date field's value, or None if not cached.
- if self.possible_aliasing(optheap, structvalue):
+ if self.possible_aliasing(optheap, opinfo):
self.force_lazy_setfield(optheap)
if self._lazy_setfield is not None:
op = self._lazy_setfield
- assert optheap.getvalue(op.getarg(0)) is structvalue
- return optheap.getvalue(op.getarglist()[-1])
+ assert optheap.getptrinfo(op.getarg(0)) is opinfo
+ return optheap.get_box_replacement(op.getarg(1))
else:
- return self._cached_fields.get(structvalue, None)
-
- def remember_field_value(self, structvalue, fieldvalue, op=None,
- optimizer=None):
- assert self._lazy_setfield is None
- self._cached_fields[structvalue] = fieldvalue
- if optimizer.exporting_state:
- op = optimizer.get_op_replacement(op)
- self._cached_fields_getfield_op[structvalue] = op
+ return opinfo.getfield(descr, optheap)
def force_lazy_setfield(self, optheap, can_cache=True):
op = self._lazy_setfield
@@ -112,11 +106,12 @@
# Now we clear _cached_fields, because actually doing the
# setfield might impact any of the stored result (because of
# possible aliasing).
- self.clear()
+ self.invalidate(op.getdescr())
self._lazy_setfield = None
if optheap.postponed_op:
+ xxx
for a in op.getarglist():
- if a is optheap.postponed_op:
+ if a is optheap.postponed_op.result:
optheap.emit_postponed_op()
break
optheap.next_optimization.propagate_forward(op)
@@ -125,69 +120,19 @@
# Once it is done, we can put at least one piece of information
# back in the cache: the value of this particular structure's
# field.
- structvalue = optheap.getvalue(op.getarg(0))
- fieldvalue = optheap.getvalue(op.getarglist()[-1])
- self.remember_field_value(structvalue, fieldvalue, op,
- optheap.optimizer)
+ opinfo = optheap.ensure_ptr_info_arg0(op)
+ opinfo.setfield(op.getdescr(),
+ optheap.get_box_replacement(op.getarg(1)))
elif not can_cache:
- self.clear()
-
- def clear(self):
- self._cached_fields.clear()
- self._cached_fields_getfield_op.clear()
-
- def produce_potential_short_preamble_ops(self, optimizer, shortboxes, descr):
- assert optimizer.exporting_state
- if self._lazy_setfield is not None:
- return
- for structvalue in self._cached_fields_getfield_op.keys():
- op = self._cached_fields_getfield_op[structvalue]
- if not op:
- continue
- value = optimizer.getvalue(op.getarg(0))
- if value in optimizer.opaque_pointers:
- if value.getlevel() < LEVEL_KNOWNCLASS:
- continue
- if op.getopnum() != rop.SETFIELD_GC and op.getopnum() != rop.GETFIELD_GC:
- continue
- if structvalue in self._cached_fields:
- if op.getopnum() == rop.SETFIELD_GC:
- result = op.getarg(1)
- opnum = OpHelpers.getfield_for_descr(op.getdescr())
- getop = ResOperation(opnum, [op.getarg(0)],
- op.getdescr())
- xxx
- if isinstance(result, Const):
- optimizer.make_constant(getop, result)
- getop.is_source_op = True
- shortboxes.add_potential(getop, getop, synthetic=True)
- else:
- getop.source_op = result
- shortboxes.add_potential(result, getop, synthetic=True)
- if op.getopnum() == rop.SETARRAYITEM_GC:
- result = op.getarg(2)
- opnum = OpHelpers.getarrayitem_for_descr(op.getdescr())
- getop = ResOperation(opnum, [op.getarg(0), op.getarg(1)],
- op.getdescr())
- getop.source_op = result
- xxx
- if isinstance(result, Const):
- xxx
- optimizer.make_constant(getop, result)
- shortboxes.add_potential(result, getop, synthetic=True)
- elif op.type != 'v':
- shortboxes.add_potential(op, op)
-
-class BogusPureField(JitException):
- pass
-
+ self.invalidate()
class OptHeap(Optimization):
"""Cache repeated heap accesses"""
def __init__(self):
- # mapping descr -> infos to invalidate
- self.infos_to_invalidate = {}
+ # mapping descr -> CachedField
+ self.cached_fields = {}
+ # XXXX the rest is old
# cached array items: {array descr: {index: CachedField}}
self.cached_arrayitems = {}
# cached dict items: {dict descr: {(optval, index): box-or-const}}
@@ -240,22 +185,13 @@
for index, d in submap.items():
d.produce_potential_short_preamble_ops(self.optimizer, sb, descr)
- def invalidate_descr(self, descr, lst=None):
- if lst is None:
- lst = self.infos_to_invalidate.get(descr, None)
- if lst is None:
- return
- for info in lst:
- info.clear_cache()
- del lst[:]
-
def register_dirty_field(self, descr, info):
- self.infos_to_invalidate.setdefault(descr, []).append(info)
+ self.field_cache(descr).register_dirty_field(info)
def clean_caches(self):
del self._lazy_setfields_and_arrayitems[:]
- for descr, info in self.infos_to_invalidate.iteritems():
- self.invalidate_descr(descr, info)
+ for descr, cf in self.cached_fields.iteritems():
+ cf.invalidate(descr)
self.cached_arrayitems.clear()
self.cached_dict_reads.clear()
@@ -447,9 +383,11 @@
assert 0, "'cf' not in cached_fields/cached_arrayitems"
def force_all_lazy_setfields_and_arrayitems(self):
- for cf in self._lazy_setfields_and_arrayitems:
- self._assert_valid_cf(cf)
+ for cf in self.cached_fields.values():
cf.force_lazy_setfield(self)
+ #for cf in self._lazy_setfields_and_arrayitems:
+ # self._assert_valid_cf(cf)
+ # cf.force_lazy_setfield(self)
def force_lazy_setfields_and_arrayitems_for_guard(self):
pendingfields = []
@@ -484,6 +422,19 @@
return pendingfields
def optimize_GETFIELD_GC_I(self, op):
+ structinfo = self.ensure_ptr_info_arg0(op)
+ cf = self.field_cache(op.getdescr())
+ field = cf.getfield_from_cache(self, structinfo, op.getdescr())
+ if field is not None:
+ self.make_equal_to(op, field)
+ return
+ # default case: produce the operation
+ self.make_nonnull(op.getarg(0))
+ self.emit_operation(op)
+ # then remember the result of reading the field
+ structinfo.setfield(op.getdescr(), op, self)
+
+ def xxx_optimize_GETFIELD_GC_I(self, op):
opinfo = self.ensure_ptr_info_arg0(op)
fld = opinfo.getfield(op.getdescr(), self)
if fld is not None:
@@ -530,13 +481,6 @@
# (op.getdescr().repr_of_descr()))
# raise BogusPureField
#
- opinfo = self.ensure_ptr_info_arg0(op)
- self.invalidate_descr(op.getdescr())
- opinfo.setfield(op.getdescr(), self.get_box_replacement(op.getarg(1)),
- self)
- # clear all the caches for this descr
- self.emit_operation(op)
- return
cf = self.field_cache(op.getdescr())
cf.do_setfield(self, op)
diff --git a/rpython/jit/metainterp/optimizeopt/info.py b/rpython/jit/metainterp/optimizeopt/info.py
--- a/rpython/jit/metainterp/optimizeopt/info.py
+++ b/rpython/jit/metainterp/optimizeopt/info.py
@@ -62,7 +62,7 @@
def force_box(self, op, optforce):
if self.is_virtual():
op.set_forwarded(None)
- optforce.emit_operation(op)
+ optforce._emit_operation(op)
newop = optforce.getlastop()
op.set_forwarded(newop)
newop.set_forwarded(self)
@@ -86,11 +86,6 @@
self._fields = [None] * len(self._fields)
def setfield(self, descr, op, optheap=None):
- if not self.is_virtual():
- if self._fields[descr.index] is None:
- assert optheap is not None
- # we should only call it with virtuals without optheap
- optheap.register_dirty_field(descr, self)
self._fields[descr.index] = op
def getfield(self, descr, optheap=None):
@@ -107,7 +102,7 @@
subbox = optforce.force_box(fld)
setfieldop = ResOperation(rop.SETFIELD_GC, [op, subbox],
descr=flddescr)
- optforce.emit_operation(setfieldop)
+ optforce._emit_operation(setfieldop)
optforce.optheap.register_dirty_field(flddescr, self)
count += 1
return count
@@ -151,7 +146,7 @@
setop = ResOperation(rop.SETARRAYITEM_GC,
[op, ConstInt(i), subbox],
descr=arraydescr)
- optforce.emit_operation(setop)
+ optforce._emit_operation(setop)
# xxxx optforce.optheap
count += 1
return count
@@ -197,7 +192,7 @@
setfieldop = ResOperation(rop.SETINTERIORFIELD_GC,
[op, ConstInt(index), subbox],
descr=flddescr)
- optforce.emit_operation(setfieldop)
+ optforce._emit_operation(setfieldop)
# XXX optforce.optheap
count += 1
i += 1
@@ -226,7 +221,7 @@
info = self._get_info(descr, optheap)
return info.getfield(descr)
- def setfield(self, descr, op, optheap):
+ def setfield(self, descr, op, optheap=None):
info = self._get_info(descr, optheap)
info.setfield(descr, op, optheap)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -604,10 +604,10 @@
p3sub = getfield_gc_r(p3, descr=nextdescr)
i3 = getfield_gc_i(p3sub, descr=valuedescr)
escape_n(i3)
+ p1 = new_with_vtable(descr=nodesize)
p2sub = new_with_vtable(descr=nodesize2)
setfield_gc(p2sub, i1, descr=valuedescr)
setfield_gc(p2, p2sub, descr=nextdescr)
- p1 = new_with_vtable(descr=nodesize)
jump(i1, p1, p2)
"""
# The same as test_p123_simple, but in the end the "old" p2 contains
More information about the pypy-commit
mailing list