Author: Richard Plangger <planri...@gmail.com> Branch: s390x-backend Changeset: r81758:7cc617cb941e Date: 2016-01-14 10:29 +0100 http://bitbucket.org/pypy/pypy/changeset/7cc617cb941e/
Log: merged default diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -39,5 +39,5 @@ # runs. We cannot get their original value either: # http://lists.gnu.org/archive/html/help-make/2010-08/msg00106.html -cffi_imports: +cffi_imports: pypy-c PYTHONPATH=. ./pypy-c pypy/tool/build_cffi_imports.py diff --git a/pypy/module/_continuation/interp_continuation.py b/pypy/module/_continuation/interp_continuation.py --- a/pypy/module/_continuation/interp_continuation.py +++ b/pypy/module/_continuation/interp_continuation.py @@ -195,7 +195,7 @@ class SThread(StackletThread): def __init__(self, space, ec): - StackletThread.__init__(self, space.config) + StackletThread.__init__(self) self.space = space self.ec = ec # for unpickling diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -372,7 +372,7 @@ def arg_int_w(self, w_obj, minimum, errormsg): space = self.space try: - result = space.int_w(w_obj) + result = space.int_w(space.int(w_obj)) # CPython allows floats as parameters except OperationError, e: if e.async(space): raise diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -225,6 +225,12 @@ assert it.next() == x raises(StopIteration, it.next) + # CPython implementation allows floats + it = itertools.islice([1, 2, 3, 4, 5], 0.0, 3.0, 2.0) + for x in [1, 3]: + assert it.next() == x + raises(StopIteration, it.next) + it = itertools.islice([1, 2, 3], 0, None) for x in [1, 2, 3]: assert it.next() == x diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py --- a/rpython/jit/codewriter/effectinfo.py +++ b/rpython/jit/codewriter/effectinfo.py @@ -330,15 +330,11 @@ return op.opname == 'jit_force_quasi_immutable' class RandomEffectsAnalyzer(BoolGraphAnalyzer): - def analyze_external_call(self, op, seen=None): - try: - funcobj = op.args[0].value._obj - if funcobj.random_effects_on_gcobjs: - return True - except (AttributeError, lltype.DelayedPointer): - return True # better safe than sorry + def analyze_external_call(self, funcobj, seen=None): + if funcobj.random_effects_on_gcobjs: + return True return super(RandomEffectsAnalyzer, self).analyze_external_call( - op, seen) + funcobj, seen) def analyze_simple_operation(self, op, graphinfo): return False 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 @@ -21,7 +21,10 @@ pass -class CachedField(object): +class AbstractCachedEntry(object): + """ abstract base class abstracting over the difference between caching + struct fields and array items. """ + def __init__(self): # Cache information for a field descr, or for an (array descr, index) # pair. It can be in one of two states: @@ -29,8 +32,8 @@ # 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 + # 2. we just did one set(field/arrayitem), which is delayed (and thus + # not synchronized). '_lazy_set' is the delayed # ResOperation. In this state, 'cached_infos' contains # out-of-date information. More precisely, the field # value pending in the ResOperation is *not* visible in @@ -38,43 +41,39 @@ # self.cached_infos = [] self.cached_structs = [] - self._lazy_setfield = None - self._lazy_setfield_registered = False + self._lazy_set = None - def register_dirty_field(self, structop, info): + def register_info(self, structop, info): + # invariant: every struct or array ptr info, that is not virtual and + # that has a non-None entry at + # info._fields[descr.get_index()] + # must be in cache_infos self.cached_structs.append(structop) self.cached_infos.append(info) - def invalidate(self, descr): - for opinfo in self.cached_infos: - assert isinstance(opinfo, info.AbstractStructPtrInfo) - opinfo._fields[descr.get_index()] = None - self.cached_infos = [] - self.cached_structs = [] - def produce_potential_short_preamble_ops(self, optimizer, shortboxes, descr, index=-1): - assert self._lazy_setfield is None + assert self._lazy_set is None for i, info in enumerate(self.cached_infos): structbox = optimizer.get_box_replacement(self.cached_structs[i]) info.produce_short_preamble_ops(structbox, descr, index, optimizer, shortboxes) def possible_aliasing(self, optheap, opinfo): - # If lazy_setfield is set and contains a setfield on a different + # If lazy_set 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 + return (self._lazy_set is not None and (not optheap.getptrinfo( - self._lazy_setfield.getarg(0)).same_info(opinfo))) + self._lazy_set.getarg(0)).same_info(opinfo))) def do_setfield(self, optheap, op): # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structinfo = optheap.ensure_ptr_info_arg0(op) - arg1 = optheap.get_box_replacement(self._getvalue(op)) + arg1 = optheap.get_box_replacement(self._get_rhs_from_set_op(op)) if self.possible_aliasing(optheap, structinfo): - self.force_lazy_setfield(optheap, op.getdescr()) + self.force_lazy_set(optheap, op.getdescr()) assert not self.possible_aliasing(optheap, structinfo) cached_field = self._getfield(structinfo, op.getdescr(), optheap, False) if cached_field is not None: @@ -87,58 +86,43 @@ # cached_fieldvalue = self._cached_fields.get(structvalue, None) 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: - # self._lazy_setfield_registered = True + # common case: store the 'op' as lazy_set + self._lazy_set = op else: # this is the case where the pending setfield ends up # storing precisely the value that is already there, # as proved by 'cached_fields'. In this case, we don't - # need any _lazy_setfield: the heap value is already right. - # Note that this may reset to None a non-None lazy_setfield, + # need any _lazy_set: the heap value is already right. + # Note that this may reset to None a non-None lazy_set, # cancelling its previous effects with no side effect. # Now, we have to force the item in the short preamble self._getfield(structinfo, op.getdescr(), optheap) - self._lazy_setfield = None + self._lazy_set = None 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, opinfo): - self.force_lazy_setfield(optheap, descr) - if self._lazy_setfield is not None: - op = self._lazy_setfield - return optheap.get_box_replacement(self._getvalue(op)) + self.force_lazy_set(optheap, descr) + if self._lazy_set is not None: + op = self._lazy_set + return optheap.get_box_replacement(self._get_rhs_from_set_op(op)) else: res = self._getfield(opinfo, descr, optheap) if res is not None: return res.get_box_replacement() return None - def _getvalue(self, op): - return op.getarg(1) - - def _getfield(self, opinfo, descr, optheap, true_force=True): - res = opinfo.getfield(descr, optheap) - if isinstance(res, PreambleOp): - if not true_force: - return res.op - res = optheap.optimizer.force_op_from_preamble(res) - opinfo.setfield(descr, None, res, optheap) - return res - - def force_lazy_setfield(self, optheap, descr, can_cache=True): - op = self._lazy_setfield + def force_lazy_set(self, optheap, descr, can_cache=True): + op = self._lazy_set if op is not None: - # This is the way _lazy_setfield is usually reset to None. + # This is the way _lazy_set is usually reset to None. # Now we clear _cached_fields, because actually doing the # setfield might impact any of the stored result (because of # possible aliasing). self.invalidate(descr) - self._lazy_setfield = None + self._lazy_set = None if optheap.postponed_op: for a in op.getarglist(): if a is optheap.postponed_op: @@ -151,25 +135,74 @@ # back in the cache: the value of this particular structure's # field. opinfo = optheap.ensure_ptr_info_arg0(op) - self._setfield(op, opinfo, optheap) + self.put_field_back_to_info(op, opinfo, optheap) elif not can_cache: self.invalidate(descr) - def _setfield(self, op, opinfo, optheap): + + # abstract methods + + def _get_rhs_from_set_op(self, op): + """ given a set(field or arrayitem) op, return the rhs argument """ + raise NotImplementedError("abstract method") + + def put_field_back_to_info(self, op, opinfo, optheap): + """ this method is called just after a lazy setfield was ommitted. it + puts the information of the lazy setfield back into the proper cache in + the info. """ + raise NotImplementedError("abstract method") + + def _getfield(self, opinfo, descr, optheap, true_force=True): + raise NotImplementedError("abstract method") + + def invalidate(self, descr): + """ clear all the cached knowledge in the infos in self.cached_infos. + """ + raise NotImplementedError("abstract method") + + +class CachedField(AbstractCachedEntry): + def _get_rhs_from_set_op(self, op): + return op.getarg(1) + + def put_field_back_to_info(self, op, opinfo, optheap): arg = optheap.get_box_replacement(op.getarg(1)) struct = optheap.get_box_replacement(op.getarg(0)) - opinfo.setfield(op.getdescr(), struct, arg, optheap, self) + opinfo.setfield(op.getdescr(), struct, arg, optheap=optheap, cf=self) -class ArrayCachedField(CachedField): + def _getfield(self, opinfo, descr, optheap, true_force=True): + res = opinfo.getfield(descr, optheap) + if not we_are_translated() and res: + if isinstance(opinfo, info.AbstractStructPtrInfo): + assert opinfo in self.cached_infos + if isinstance(res, PreambleOp): + if not true_force: + return res.op + res = optheap.optimizer.force_op_from_preamble(res) + opinfo.setfield(descr, None, res, optheap=optheap) + return res + + def invalidate(self, descr): + for opinfo in self.cached_infos: + assert isinstance(opinfo, info.AbstractStructPtrInfo) + opinfo._fields[descr.get_index()] = None + self.cached_infos = [] + self.cached_structs = [] + + +class ArrayCachedItem(AbstractCachedEntry): def __init__(self, index): self.index = index - CachedField.__init__(self) + AbstractCachedEntry.__init__(self) - def _getvalue(self, op): + def _get_rhs_from_set_op(self, op): return op.getarg(2) def _getfield(self, opinfo, descr, optheap, true_force=True): res = opinfo.getitem(descr, self.index, optheap) + if not we_are_translated() and res: + if isinstance(opinfo, info.ArrayPtrInfo): + assert opinfo in self.cached_infos if (isinstance(res, PreambleOp) and optheap.optimizer.cpu.supports_guard_gc_type): if not true_force: @@ -179,10 +212,10 @@ opinfo.setitem(descr, index, None, res, optheap=optheap) return res - def _setfield(self, op, opinfo, optheap): + def put_field_back_to_info(self, op, opinfo, optheap): arg = optheap.get_box_replacement(op.getarg(2)) struct = optheap.get_box_replacement(op.getarg(0)) - opinfo.setitem(op.getdescr(), self.index, struct, arg, self, optheap) + opinfo.setitem(op.getdescr(), self.index, struct, arg, optheap=optheap, cf=self) def invalidate(self, descr): for opinfo in self.cached_infos: @@ -201,15 +234,11 @@ self.postponed_op = None - # 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}} self.cached_dict_reads = {} # cache of corresponding {array descrs: dict 'entries' field descr} self.corresponding_array_descrs = {} # - self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -221,7 +250,7 @@ def flush(self): self.cached_dict_reads.clear() self.corresponding_array_descrs.clear() - self.force_all_lazy_setfields_and_arrayitems() + self.force_all_lazy_sets() self.emit_postponed_op() def emit_postponed_op(self): @@ -234,7 +263,7 @@ descrkeys = self.cached_fields.keys() if not we_are_translated(): # XXX Pure operation of boxes that are cached in several places will - # only be removed from the peeled loop when red from the first + # only be removed from the peeled loop when read from the first # place discovered here. This is far from ideal, as it makes # the effectiveness of our optimization a bit random. It should # howevere always generate correct results. For tests we dont @@ -249,14 +278,7 @@ d.produce_potential_short_preamble_ops(self.optimizer, sb, descr, index) - def register_dirty_field(self, descr, op, info): - self.field_cache(descr).register_dirty_field(op, info) - - def register_dirty_array_field(self, arraydescr, op, index, info): - self.arrayitem_cache(arraydescr, index).register_dirty_field(op, info) - def clean_caches(self): - del self._lazy_setfields_and_arrayitems[:] items = self.cached_fields.items() if not we_are_translated(): items.sort(key=str, reverse=True) @@ -285,7 +307,7 @@ try: cf = submap[index] except KeyError: - cf = submap[index] = ArrayCachedField(index) + cf = submap[index] = ArrayCachedItem(index) return cf def emit_operation(self, op): @@ -304,7 +326,7 @@ return if op.is_guard(): self.optimizer.pendingfields = ( - self.force_lazy_setfields_and_arrayitems_for_guard()) + self.force_lazy_sets_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -332,7 +354,7 @@ if not effectinfo.has_random_effects(): self.force_from_effectinfo(effectinfo) return - self.force_all_lazy_setfields_and_arrayitems() + self.force_all_lazy_sets() self.clean_caches() def optimize_CALL_I(self, op): @@ -410,7 +432,7 @@ # XXX we can get the wrong complexity here, if the lists # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: - self.force_lazy_setfield(fielddescr) + self.force_lazy_set(fielddescr) for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: @@ -420,7 +442,7 @@ del self.cached_dict_reads[fielddescr] except KeyError: pass - self.force_lazy_setfield(fielddescr, can_cache=False) + self.force_lazy_set(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: self.force_lazy_setarrayitem(arraydescr, can_cache=False) if arraydescr in self.corresponding_array_descrs: @@ -431,16 +453,16 @@ pass # someone did it already if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info - self.force_lazy_setfield(vrefinfo.descr_forced) + self.force_lazy_set(vrefinfo.descr_forced) # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. - def force_lazy_setfield(self, descr, can_cache=True): + def force_lazy_set(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self, descr, can_cache) + cf.force_lazy_set(self, descr, can_cache) def force_lazy_setarrayitem(self, arraydescr, indexb=None, can_cache=True): try: @@ -449,35 +471,35 @@ return for idx, cf in submap.iteritems(): if indexb is None or indexb.contains(idx): - cf.force_lazy_setfield(self, None, can_cache) + cf.force_lazy_set(self, None, can_cache) - def force_all_lazy_setfields_and_arrayitems(self): + def force_all_lazy_sets(self): items = self.cached_fields.items() if not we_are_translated(): items.sort(key=str, reverse=True) for descr, cf in items: - cf.force_lazy_setfield(self, descr) + cf.force_lazy_set(self, descr) for submap in self.cached_arrayitems.itervalues(): for index, cf in submap.iteritems(): - cf.force_lazy_setfield(self, None) + cf.force_lazy_set(self, None) - def force_lazy_setfields_and_arrayitems_for_guard(self): + def force_lazy_sets_for_guard(self): pendingfields = [] items = self.cached_fields.items() if not we_are_translated(): items.sort(key=str, reverse=True) for descr, cf in items: - op = cf._lazy_setfield + op = cf._lazy_set if op is None: continue val = op.getarg(1) if self.optimizer.is_virtual(val): pendingfields.append(op) continue - cf.force_lazy_setfield(self, descr) + cf.force_lazy_set(self, descr) for descr, submap in self.cached_arrayitems.iteritems(): for index, cf in submap.iteritems(): - op = cf._lazy_setfield + op = cf._lazy_set if op is None: continue # the only really interesting case that we need to handle in the @@ -489,7 +511,7 @@ if self.optimizer.is_virtual(op.getarg(2)): pendingfields.append(op) else: - cf.force_lazy_setfield(self, descr) + cf.force_lazy_set(self, descr) return pendingfields def optimize_GETFIELD_GC_I(self, op): @@ -503,7 +525,7 @@ self.make_nonnull(op.getarg(0)) self.emit_operation(op) # then remember the result of reading the field - structinfo.setfield(op.getdescr(), op.getarg(0), op, self, cf) + structinfo.setfield(op.getdescr(), op.getarg(0), op, optheap=self, cf=cf) optimize_GETFIELD_GC_R = optimize_GETFIELD_GC_I optimize_GETFIELD_GC_F = optimize_GETFIELD_GC_I @@ -554,12 +576,12 @@ # default case: produce the operation self.make_nonnull(op.getarg(0)) self.emit_operation(op) - # the remember the result of reading the array item + # then remember the result of reading the array item if cf is not None: arrayinfo.setitem(op.getdescr(), indexb.getint(), self.get_box_replacement(op.getarg(0)), - self.get_box_replacement(op), cf, - self) + self.get_box_replacement(op), optheap=self, + cf=cf) optimize_GETARRAYITEM_GC_R = optimize_GETARRAYITEM_GC_I optimize_GETARRAYITEM_GC_F = optimize_GETARRAYITEM_GC_I 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 @@ -196,28 +196,28 @@ def all_items(self): return self._fields - def setfield(self, descr, struct, op, optheap=None, cf=None): - self.init_fields(descr.get_parent_descr(), descr.get_index()) + def setfield(self, fielddescr, struct, op, optheap=None, cf=None): + self.init_fields(fielddescr.get_parent_descr(), fielddescr.get_index()) assert isinstance(op, AbstractValue) - self._fields[descr.get_index()] = op + self._fields[fielddescr.get_index()] = op if cf is not None: assert not self.is_virtual() assert struct is not None - cf.register_dirty_field(struct, self) + cf.register_info(struct, self) - def getfield(self, descr, optheap=None): - self.init_fields(descr.get_parent_descr(), descr.get_index()) - return self._fields[descr.get_index()] + def getfield(self, fielddescr, optheap=None): + self.init_fields(fielddescr.get_parent_descr(), fielddescr.get_index()) + return self._fields[fielddescr.get_index()] def _force_elements(self, op, optforce, descr): if self._fields is None: return - for i, flddescr in enumerate(descr.get_all_fielddescrs()): + for i, fielddescr in enumerate(descr.get_all_fielddescrs()): fld = self._fields[i] if fld is not None: subbox = optforce.force_box(fld) setfieldop = ResOperation(rop.SETFIELD_GC, [op, subbox], - descr=flddescr) + descr=fielddescr) self._fields[i] = None optforce.emit_operation(setfieldop) @@ -249,16 +249,16 @@ if fieldinfo and fieldinfo.is_virtual(): fieldinfo.visitor_walk_recursive(op, visitor, optimizer) - def produce_short_preamble_ops(self, structbox, descr, index, optimizer, + def produce_short_preamble_ops(self, structbox, fielddescr, index, optimizer, shortboxes): if self._fields is None: return - if descr.get_index() >= len(self._fields): + if fielddescr.get_index() >= len(self._fields): # we don't know about this item return - op = optimizer.get_box_replacement(self._fields[descr.get_index()]) - opnum = OpHelpers.getfield_for_descr(descr) - getfield_op = ResOperation(opnum, [structbox], descr=descr) + op = optimizer.get_box_replacement(self._fields[fielddescr.get_index()]) + opnum = OpHelpers.getfield_for_descr(fielddescr) + getfield_op = ResOperation(opnum, [structbox], descr=fielddescr) shortboxes.add_heap_op(op, getfield_op) def _is_immutable_and_filled_with_constants(self, optimizer, memo=None): @@ -294,12 +294,12 @@ return True def _force_elements_immutable(self, descr, constptr, optforce): - for i, flddescr in enumerate(descr.get_all_fielddescrs()): + for i, fielddescr in enumerate(descr.get_all_fielddescrs()): fld = self._fields[i] subbox = optforce.force_box(fld) assert isinstance(subbox, Const) execute(optforce.optimizer.cpu, None, rop.SETFIELD_GC, - flddescr, constptr, subbox) + fielddescr, constptr, subbox) class InstancePtrInfo(AbstractStructPtrInfo): _attrs_ = ('_known_class',) @@ -505,6 +505,7 @@ info._items = self._items[:] def _force_elements(self, op, optforce, descr): + # XXX descr = op.getdescr() const = optforce.new_const_item(self.descr) for i in range(self.length): @@ -523,15 +524,16 @@ optforce.emit_operation(setop) optforce.pure_from_args(rop.ARRAYLEN_GC, [op], ConstInt(len(self._items))) - def setitem(self, descr, index, struct, op, cf=None, optheap=None): + def setitem(self, descr, index, struct, op, optheap=None, cf=None): if self._items is None: self._items = [None] * (index + 1) if index >= len(self._items): + assert not self.is_virtual() self._items = self._items + [None] * (index - len(self._items) + 1) self._items[index] = op if cf is not None: assert not self.is_virtual() - cf.register_dirty_field(struct, self) + cf.register_info(struct, self) def getitem(self, descr, index, optheap=None): if self._items is None or index >= len(self._items): @@ -626,13 +628,13 @@ i = 0 fielddescrs = op.getdescr().get_all_fielddescrs() for index in range(self.length): - for flddescr in fielddescrs: + for fielddescr in fielddescrs: fld = self._items[i] if fld is not None: subbox = optforce.force_box(fld) setfieldop = ResOperation(rop.SETINTERIORFIELD_GC, [op, ConstInt(index), subbox], - descr=flddescr) + descr=fielddescr) optforce.emit_operation(setfieldop) # heapcache does not work for interiorfields # if it does, we would need a fix here @@ -645,7 +647,7 @@ fielddescrs = self.descr.get_all_fielddescrs() i = 0 for index in range(self.getlength()): - for flddescr in fielddescrs: + for fielddescr in fielddescrs: itemop = self._items[i] if (itemop is not None and not isinstance(itemop, Const)): @@ -691,21 +693,21 @@ optheap.const_infos[ref] = info return info - def getfield(self, descr, optheap=None): - info = self._get_info(descr.get_parent_descr(), optheap) - return info.getfield(descr) + def getfield(self, fielddescr, optheap=None): + info = self._get_info(fielddescr.get_parent_descr(), optheap) + return info.getfield(fielddescr) def getitem(self, descr, index, optheap=None): info = self._get_array_info(descr, optheap) return info.getitem(descr, index) - def setitem(self, descr, index, struct, op, cf=None, optheap=None): + def setitem(self, descr, index, struct, op, optheap=None, cf=None): info = self._get_array_info(descr, optheap) - info.setitem(descr, index, struct, op, cf) + info.setitem(descr, index, struct, op, optheap=optheap, cf=cf) - def setfield(self, descr, struct, op, optheap=None, cf=None): - info = self._get_info(descr.get_parent_descr(), optheap) - info.setfield(descr, struct, op, optheap, cf) + def setfield(self, fielddescr, struct, op, optheap=None, cf=None): + info = self._get_info(fielddescr.get_parent_descr(), optheap) + info.setfield(fielddescr, struct, op, optheap=optheap, cf=cf) def is_null(self): return not bool(self._const.getref_base()) diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py --- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py +++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py @@ -81,7 +81,7 @@ assert index >= 0 cf = optheap.arrayitem_cache(descr, index) opinfo.setitem(self.getfield_op.getdescr(), index, self.res, - pop, cf, optheap=optheap) + pop, optheap, cf) def repr(self, memo): return "HeapOp(%s, %s)" % (self.res.repr(memo), 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 @@ -696,58 +696,6 @@ # ---------- - def test_virtual_1(self): - ops = """ - [i, p0] - i0 = getfield_gc(p0, descr=valuedescr) - i1 = int_add(i0, i) - setfield_gc(p0, i1, descr=valuedescr) - jump(i, p0) - """ - expected = """ - [i, i2] - i1 = int_add(i2, i) - jump(i, i1) - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)', - expected) - - def test_virtual_float(self): - ops = """ - [f, p0] - f0 = getfield_gc(p0, descr=floatdescr) - f1 = float_add(f0, f) - setfield_gc(p0, f1, descr=floatdescr) - jump(f, p0) - """ - expected = """ - [f, f2] - f1 = float_add(f2, f) - jump(f, f1) - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Not, Virtual(node_vtable, floatdescr=Not)', - expected) - - def test_virtual_2(self): - py.test.skip("XXX") - ops = """ - [i, p0] - i0 = getfield_gc(p0, descr=valuedescr) - i1 = int_add(i0, i) - p1 = new_with_vtable(ConstClass(node_vtable)) - setfield_gc(p1, i1, descr=valuedescr) - jump(i, p1) - """ - expected = """ - [i, i2] - i1 = int_add(i2, i) - jump(i, i1) - """ - self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)', - expected) - def test_virtual_oois(self): ops = """ [p0, p1, p2] @@ -774,20 +722,6 @@ guard_false(i12) [] jump(p0, p1, p2) """ - expected = """ - [p2] - # all constant-folded :-) - jump(p2) - """ - py.test.skip("XXX") - self.optimize_loop(ops, '''Virtual(node_vtable), - Virtual(node_vtable), - Not''', - expected) - # - # to be complete, we also check the no-opt case where most comparisons - # are not removed. The exact set of comparisons removed depends on - # the details of the algorithm... expected2 = """ [p0, p1, p2] guard_nonnull(p0) [] @@ -801,26 +735,6 @@ """ self.optimize_loop(ops, expected2) - def test_virtual_default_field(self): - py.test.skip("XXX") - ops = """ - [p0] - i0 = getfield_gc(p0, descr=valuedescr) - guard_value(i0, 0) [] - p1 = new_with_vtable(ConstClass(node_vtable)) - # the field 'value' has its default value of 0 - jump(p1) - """ - expected = """ - [i] - guard_value(i, 0) [] - jump(0) - """ - # the 'expected' is sub-optimal, but it should be done by another later - # optimization step. See test_find_nodes_default_field() for why. - self.optimize_loop(ops, 'Virtual(node_vtable, valuedescr=Not)', - expected) - def test_virtual_3(self): ops = """ [i] @@ -837,55 +751,6 @@ """ self.optimize_loop(ops, expected) - def test_virtual_4(self): - py.test.skip("XXX") - ops = """ - [i0, p0] - guard_class(p0, ConstClass(node_vtable)) [] - i1 = getfield_gc(p0, descr=valuedescr) - i2 = int_sub(i1, 1) - i3 = int_add(i0, i1) - p1 = new_with_vtable(descr=nodesize) - setfield_gc(p1, i2, descr=valuedescr) - jump(i3, p1) - """ - expected = """ - [i0, i1] - i2 = int_sub(i1, 1) - i3 = int_add(i0, i1) - jump(i3, i2) - """ - self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)', - expected) - - def test_virtual_5(self): - py.test.skip("XXX") - ops = """ - [i0, p0] - guard_class(p0, ConstClass(node_vtable)) [] - i1 = getfield_gc(p0, descr=valuedescr) - i2 = int_sub(i1, 1) - i3 = int_add(i0, i1) - p2 = new_with_vtable(descr=nodesize2) - setfield_gc(p2, i1, descr=valuedescr) - p1 = new_with_vtable(descr=nodesize) - setfield_gc(p1, i2, descr=valuedescr) - setfield_gc(p1, p2, descr=nextdescr) - jump(i3, p1) - """ - expected = """ - [i0, i1, i1bis] - i2 = int_sub(i1, 1) - i3 = int_add(i0, i1) - jump(i3, i2, i1) - """ - self.optimize_loop(ops, - '''Not, Virtual(node_vtable, - valuedescr=Not, - nextdescr=Virtual(node_vtable2, - valuedescr=Not))''', - expected) - def test_virtual_constant_isnull(self): ops = """ [i0] @@ -1209,27 +1074,6 @@ """ self.optimize_loop(ops, expected) - def test_varray_2(self): - ops = """ - [i0, p1] - i1 = getarrayitem_gc(p1, 0, descr=arraydescr) - i2 = getarrayitem_gc(p1, 1, descr=arraydescr) - i3 = int_sub(i1, i2) - guard_value(i3, 15) [] - p2 = new_array(2, descr=arraydescr) - setarrayitem_gc(p2, 1, i0, descr=arraydescr) - setarrayitem_gc(p2, 0, 20, descr=arraydescr) - jump(i0, p2) - """ - expected = """ - [i0, i1, i2] - i3 = int_sub(i1, i2) - guard_value(i3, 15) [] - jump(i0, 20, i0) - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Not, VArray(arraydescr, Not, Not)', expected) - def test_p123_array(self): ops = """ [i1, p2, p3] @@ -1264,23 +1108,6 @@ """ self.optimize_loop(ops, expected) - def test_vstruct_1(self): - py.test.skip("XXX") - ops = """ - [i1, p2] - i2 = getfield_gc(p2, descr=adescr) - escape_n(i2) - p3 = new(descr=ssize) - setfield_gc(p3, i1, descr=adescr) - jump(i1, p3) - """ - expected = """ - [i1, i2] - escape_n(i2) - jump(i1, i1) - """ - self.optimize_loop(ops, 'Not, VStruct(ssize, adescr=Not)', expected) - def test_p123_vstruct(self): ops = """ [i1, p2, p3] @@ -1443,26 +1270,6 @@ """ self.optimize_loop(ops, expected) - def test_duplicate_getfield_guard_value_const(self): - ops = """ - [p1] - guard_value(p1, ConstPtr(myptr)) [] - i1 = getfield_gc_i(p1, descr=valuedescr) - i2 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr) - escape_n(i1) - escape_n(i2) - jump(p1) - """ - expected = """ - [] - i1 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr) - escape_n(i1) - escape_n(i1) - jump() - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Constant(myptr)', expected) - def test_duplicate_getfield_sideeffects_1(self): ops = """ [p1] @@ -1688,12 +1495,12 @@ jump(p1, i1, i2) """ expected = """ - [i1, i2] + [p1, i1, i2] + guard_value(p1, ConstPtr(myptr)) [] setfield_gc(ConstPtr(myptr), i2, descr=valuedescr) - jump(i1, i2) - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Constant(myptr), Not, Not', expected) + jump(ConstPtr(myptr), i1, i2) + """ + self.optimize_loop(ops, expected) def test_duplicate_getarrayitem_1(self): ops = """ @@ -1870,163 +1677,7 @@ """ self.optimize_loop(ops, expected) - def test_bug_1(self): - ops = """ - [i0, p1] - p4 = getfield_gc_r(p1, descr=nextdescr) - guard_nonnull(p4) [] - escape_n(p4) - # - p2 = new_with_vtable(descr=nodesize) - p3 = escape_r() - setfield_gc(p2, p3, descr=nextdescr) - jump(i0, p2) - """ - expected = """ - [i0, p4] - guard_nonnull(p4) [] - escape_n(p4) - # - p3 = escape_r() - jump(i0, p3) - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Not, Virtual(node_vtable, nextdescr=Not)', - expected) - - def test_bug_2(self): - ops = """ - [i0, p1] - p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) - guard_nonnull(p4) [] - escape_n(p4) - # - p2 = new_array(1, descr=arraydescr2) - p3 = escape_r() - setarrayitem_gc(p2, 0, p3, descr=arraydescr2) - jump(i0, p2) - """ - expected = """ - [i0, p4] - guard_nonnull(p4) [] - escape_n(p4) - # - p3 = escape_r() - jump(i0, p3) - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Not, VArray(arraydescr2, Not)', - expected) - - def test_bug_3(self): - ops = """ - [p1] - guard_nonnull(p1) [] - guard_class(p1, ConstClass(node_vtable2)) [] - p2 = getfield_gc_r(p1, descr=nextdescr) - guard_nonnull(12) [] - guard_class(p2, ConstClass(node_vtable)) [] - p3 = getfield_gc_r(p1, descr=otherdescr) - guard_nonnull(12) [] - guard_class(p3, ConstClass(node_vtable)) [] - setfield_gc(p3, p2, descr=otherdescr) - p1a = new_with_vtable(ConstClass(node_vtable2)) - p2a = new_with_vtable(descr=nodesize) - p3a = new_with_vtable(descr=nodesize) - escape_n(p3a) - setfield_gc(p1a, p2a, descr=nextdescr) - setfield_gc(p1a, p3a, descr=otherdescr) - jump(p1a) - """ - expected = """ - [p2, p3] - guard_class(p2, ConstClass(node_vtable)) [] - guard_class(p3, ConstClass(node_vtable)) [] - setfield_gc(p3, p2, descr=otherdescr) - p3a = new_with_vtable(descr=nodesize) - escape_n(p3a) - p2a = new_with_vtable(descr=nodesize) - jump(p2a, p3a) - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)', expected) - - def test_bug_3bis(self): - ops = """ - [p1] - guard_nonnull(p1) [] - guard_class(p1, ConstClass(node_vtable2)) [] - p2 = getfield_gc_r(p1, descr=nextdescr) - guard_nonnull(12) [] - guard_class(p2, ConstClass(node_vtable)) [] - p3 = getfield_gc_r(p1, descr=otherdescr) - guard_nonnull(12) [] - guard_class(p3, ConstClass(node_vtable)) [] - p1a = new_with_vtable(ConstClass(node_vtable2)) - p2a = new_with_vtable(descr=nodesize) - setfield_gc(p3, p2a, descr=otherdescr) - p3a = new_with_vtable(descr=nodesize) - escape_n(p3a) - setfield_gc(p1a, p2a, descr=nextdescr) - setfield_gc(p1a, p3a, descr=otherdescr) - jump(p1a) - """ - expected = """ - [p2, p3] - guard_class(p2, ConstClass(node_vtable)) [] - guard_class(p3, ConstClass(node_vtable)) [] - p2a = new_with_vtable(descr=nodesize) - setfield_gc(p3, p2a, descr=otherdescr) - p3a = new_with_vtable(descr=nodesize) - escape_n(p3a) - jump(p2a, p3a) - """ - py.test.skip("XXX") - self.optimize_loop(ops, 'Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)', expected) - - def test_invalid_loop_1(self): - ops = """ - [p1] - guard_isnull(p1) [] - # - p2 = new_with_vtable(descr=nodesize) - jump(p2) - """ - py.test.skip("XXX") - py.test.raises(InvalidLoop, self.optimize_loop, - ops, 'Virtual(node_vtable)', None) - - def test_invalid_loop_2(self): - py.test.skip("this would fail if we had Fixed again in the specnodes") - ops = """ - [p1] - guard_class(p1, ConstClass(node_vtable2)) [] - # - p2 = new_with_vtable(descr=nodesize) - escape_n(p2) # prevent it from staying Virtual - jump(p2) - """ - py.test.raises(InvalidLoop, self.optimize_loop, - ops, '...', None) - - def test_invalid_loop_3(self): - ops = """ - [p1] - p2 = getfield_gc_r(p1, descr=nextdescr) - guard_isnull(p2) [] - # - p3 = new_with_vtable(descr=nodesize) - p4 = new_with_vtable(descr=nodesize) - setfield_gc(p3, p4, descr=nextdescr) - jump(p3) - """ - py.test.skip("XXX") - py.test.raises(InvalidLoop, self.optimize_loop, ops, - 'Virtual(node_vtable, nextdescr=Virtual(node_vtable))', - None) - def test_merge_guard_class_guard_value(self): - py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_class(p1, ConstClass(node_vtable)) [i0] @@ -2060,7 +1711,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1) [i0] @@ -2078,7 +1728,6 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1) [i0] @@ -2625,26 +2274,6 @@ where p2 is a node_vtable, valuedescr=i2, nextdescr=p1 ''', rop.GUARD_TRUE) - def test_expand_fail_6(self): - ops = """ - [p0, i0, i1] - guard_true(i0) [p0] - p1 = new_with_vtable(descr=nodesize) - setfield_gc(p1, i1, descr=valuedescr) - jump(p1, i1, i1) - """ - expected = """ - [i1b, i0, i1] - guard_true(i0) [i1b] - jump(i1, i1, i1) - """ - py.test.skip("XXX") - self.optimize_loop(ops, '''Virtual(node_vtable, valuedescr=Not), - Not, Not''', expected) - self.check_expanded_fail_descr('''p0 - where p0 is a node_vtable, valuedescr=i1b - ''', rop.GUARD_TRUE) - def test_expand_fail_varray(self): ops = """ [i1] @@ -2686,47 +2315,6 @@ where p2 is a vstruct ssize, adescr=i1, bdescr=p1 ''', rop.GUARD_TRUE) - def test_expand_fail_v_all_1(self): - ops = """ - [i1, p1a, i2] - p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2) - p7v = getfield_gc_r(p6s, descr=bdescr) - p5s = new(descr=ssize) - setfield_gc(p5s, i2, descr=adescr) - setfield_gc(p5s, p7v, descr=bdescr) - setarrayitem_gc(p1a, 1, p5s, descr=arraydescr2) - guard_true(i1) [p1a] - p2s = new(descr=ssize) - p3v = new_with_vtable(descr=nodesize) - p4a = new_array(2, descr=arraydescr2) - setfield_gc(p2s, i1, descr=adescr) - setfield_gc(p2s, p3v, descr=bdescr) - setfield_gc(p3v, i2, descr=valuedescr) - setarrayitem_gc(p4a, 0, p2s, descr=arraydescr2) - jump(i1, p4a, i2) - """ - expected = """ - [i1, ia, iv, pnull, i2] - guard_true(i1) [ia, iv, i2] - jump(1, 1, i2, NULL, i2) - """ - py.test.skip("XXX") - self.optimize_loop(ops, ''' - Not, - VArray(arraydescr2, - VStruct(ssize, - adescr=Not, - bdescr=Virtual(node_vtable, - valuedescr=Not)), - Not), - Not''', expected) - self.check_expanded_fail_descr('''p1a - where p1a is a varray arraydescr2: p6s, p5s - where p6s is a vstruct ssize, adescr=ia, bdescr=p7v - where p5s is a vstruct ssize, adescr=i2, bdescr=p7v - where p7v is a node_vtable, valuedescr=iv - ''', rop.GUARD_TRUE) - def test_expand_fail_lazy_setfield_1(self): ops = """ [p1, i2, i3] @@ -5179,6 +4767,8 @@ """ self.optimize_loop(ops, expected) + def test_intmod_bounds_harder(self): + py.test.skip("harder") # Of course any 'maybe-negative % power-of-two' can be turned into # int_and(), but that's a bit harder to detect here because it turns # into several operations, and of course it is wrong to just turn @@ -5196,7 +4786,6 @@ i4 = int_and(i0, 15) finish(i4) """ - py.test.skip("harder") self.optimize_loop(ops, expected) def test_intmod_bounds_bug1(self): @@ -5357,7 +4946,7 @@ i5 = int_lt(i2, i1) guard_true(i5) [] - i6 = getarrayitem_gc(p0, i2) + i6 = getarrayitem_gc_i(p0, i2, descr=chararraydescr) finish(i6) """ expected = """ @@ -5368,7 +4957,7 @@ i4 = int_lt(i2, i0) guard_true(i4) [] - i6 = getarrayitem_gc(p0, i3) + i6 = getarrayitem_gc_i(p0, i3, descr=chararraydescr) finish(i6) """ self.optimize_loop(ops, expected) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2969,7 +2969,6 @@ assert "promote of a virtual" in exc.msg def test_merge_guard_class_guard_value(self): - py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_class(p1, ConstClass(node_vtable)) [i0] @@ -3015,7 +3014,6 @@ #self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): - py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1) [i0] @@ -3039,7 +3037,6 @@ #self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): - py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1) [i0] diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -35,15 +35,11 @@ return True return graphanalyze.BoolGraphAnalyzer.analyze_direct_call(self, graph, seen) - def analyze_external_call(self, op, seen=None): - try: - funcobj = op.args[0].value._obj - except lltype.DelayedPointer: + def analyze_external_call(self, funcobj, seen=None): + if funcobj.random_effects_on_gcobjs: return True - if getattr(funcobj, 'random_effects_on_gcobjs', False): - return True - return graphanalyze.BoolGraphAnalyzer.analyze_external_call(self, op, - seen) + return graphanalyze.BoolGraphAnalyzer.analyze_external_call( + self, funcobj, seen) def analyze_simple_operation(self, op, graphinfo): if op.opname in ('malloc', 'malloc_varsize'): flags = op.args[1].value diff --git a/rpython/rlib/rstacklet.py b/rpython/rlib/rstacklet.py --- a/rpython/rlib/rstacklet.py +++ b/rpython/rlib/rstacklet.py @@ -1,7 +1,7 @@ import sys from rpython.rlib import _rffi_stacklet as _c from rpython.rlib import jit -from rpython.rlib.objectmodel import we_are_translated +from rpython.rlib.objectmodel import fetch_translated_config from rpython.rtyper.lltypesystem import lltype, llmemory DEBUG = False @@ -10,8 +10,8 @@ class StackletThread(object): @jit.dont_look_inside - def __init__(self, config): - self._gcrootfinder = _getgcrootfinder(config, we_are_translated()) + def __init__(self, _argument_ignored_for_backward_compatibility=None): + self._gcrootfinder = _getgcrootfinder(fetch_translated_config()) self._thrd = _c.newthread() if not self._thrd: raise MemoryError @@ -67,11 +67,8 @@ # ____________________________________________________________ -def _getgcrootfinder(config, translated): - if translated: - assert config is not None, ("you have to pass a valid config, " - "e.g. from 'driver.config'") - elif '__pypy__' in sys.builtin_module_names: +def _getgcrootfinder(config): + if config is None and '__pypy__' in sys.builtin_module_names: import py py.test.skip("cannot run the stacklet tests on top of pypy: " "calling directly the C function stacklet_switch() " diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -17,10 +17,9 @@ class Runner: STATUSMAX = 5000 - config = None def init(self, seed): - self.sthread = rstacklet.StackletThread(self.config) + self.sthread = rstacklet.StackletThread() self.random = rrandom.Random(seed) def done(self): @@ -301,12 +300,11 @@ config.translation.gcrootfinder = cls.gcrootfinder GCROOTFINDER = cls.gcrootfinder cls.config = config - cls.old_values = Runner.config, Runner.STATUSMAX - Runner.config = config + cls.old_status_max = Runner.STATUSMAX Runner.STATUSMAX = 25000 def teardown_class(cls): - Runner.config, Runner.STATUSMAX = cls.old_values + Runner.STATUSMAX = cls.old_status_max def test_demo1(self): t, cbuilder = self.compile(entry_point) diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py --- a/rpython/rtyper/rtyper.py +++ b/rpython/rtyper/rtyper.py @@ -22,7 +22,7 @@ from rpython.rtyper.error import TyperError from rpython.rtyper.exceptiondata import ExceptionData from rpython.rtyper.lltypesystem.lltype import (Signed, Void, LowLevelType, - Ptr, ContainerType, FuncType, functionptr, typeOf, RuntimeTypeInfo, + Ptr, ContainerType, FuncType, typeOf, RuntimeTypeInfo, attachRuntimeTypeInfo, Primitive, getfunctionptr) from rpython.rtyper.rmodel import Repr, inputconst, BrokenReprTyperError from rpython.rtyper import rclass @@ -876,18 +876,6 @@ return self.genop('direct_call', [c]+newargs_v, resulttype = typeOf(fobj).RESULT) - def genexternalcall(self, fnname, args_v, resulttype=None, **flags): - if isinstance(resulttype, Repr): - resulttype = resulttype.lowleveltype - argtypes = [v.concretetype for v in args_v] - FUNCTYPE = FuncType(argtypes, resulttype or Void) - f = functionptr(FUNCTYPE, fnname, **flags) - cf = inputconst(typeOf(f), f) - return self.genop('direct_call', [cf]+list(args_v), resulttype) - - def gencapicall(self, cfnname, args_v, resulttype=None, **flags): - return self.genexternalcall(cfnname, args_v, resulttype=resulttype, external="CPython", **flags) - def genconst(self, ll_value): return inputconst(typeOf(ll_value), ll_value) diff --git a/rpython/translator/backendopt/canraise.py b/rpython/translator/backendopt/canraise.py --- a/rpython/translator/backendopt/canraise.py +++ b/rpython/translator/backendopt/canraise.py @@ -22,8 +22,7 @@ log.WARNING("Unknown operation: %s" % op.opname) return True - def analyze_external_call(self, op, seen=None): - fnobj = op.args[0].value._obj + def analyze_external_call(self, fnobj, seen=None): return getattr(fnobj, 'canraise', True) analyze_exceptblock = None # don't call this diff --git a/rpython/translator/backendopt/gilanalysis.py b/rpython/translator/backendopt/gilanalysis.py --- a/rpython/translator/backendopt/gilanalysis.py +++ b/rpython/translator/backendopt/gilanalysis.py @@ -21,12 +21,8 @@ self, graph, seen) def analyze_external_call(self, op, seen=None): - funcobj = op.args[0].value._obj - if getattr(funcobj, 'transactionsafe', False): - return False - else: - return False - + return False + def analyze_simple_operation(self, op, graphinfo): return False diff --git a/rpython/translator/backendopt/graphanalyze.py b/rpython/translator/backendopt/graphanalyze.py --- a/rpython/translator/backendopt/graphanalyze.py +++ b/rpython/translator/backendopt/graphanalyze.py @@ -1,5 +1,4 @@ from rpython.rtyper.lltypesystem.lltype import DelayedPointer -from rpython.translator.simplify import get_graph from rpython.tool.algo.unionfind import UnionFind @@ -55,11 +54,7 @@ def analyze_startblock(self, block, seen=None): return self.bottom_result() - def analyze_external_call(self, op, seen=None): - try: - funcobj = op.args[0].value._obj - except DelayedPointer: - return self.bottom_result() + def analyze_external_call(self, funcobj, seen=None): result = self.bottom_result() if hasattr(funcobj, '_callbacks'): bk = self.translator.annotator.bookkeeper @@ -80,12 +75,24 @@ def analyze(self, op, seen=None, graphinfo=None): if op.opname == "direct_call": - graph = get_graph(op.args[0], self.translator) - if graph is None: - x = self.analyze_external_call(op, seen) + try: + funcobj = op.args[0].value._obj + except DelayedPointer: + return self.top_result() + if funcobj is None: + # We encountered a null pointer. Calling it will crash. + # However, the call could be on a dead path, so we return the + # bottom result here. + return self.bottom_result() + if getattr(funcobj, 'external', None) is not None: + x = self.analyze_external_call(funcobj, seen) if self.verbose and x: self.dump_info('analyze_external_call %s: %r' % (op, x)) return x + try: + graph = funcobj.graph + except AttributeError: + return self.top_result() x = self.analyze_direct_call(graph, seen) if self.verbose and x: self.dump_info('analyze_direct_call(%s): %r' % (graph, x)) diff --git a/rpython/translator/backendopt/test/test_canraise.py b/rpython/translator/backendopt/test/test_canraise.py --- a/rpython/translator/backendopt/test/test_canraise.py +++ b/rpython/translator/backendopt/test/test_canraise.py @@ -204,8 +204,7 @@ result = ra.can_raise(fgraph.startblock.operations[0]) assert not result - z = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed), - 'foobar') + z = llexternal('z', [lltype.Signed], lltype.Signed) def g(x): return z(x) t, ra = self.translate(g, [int]) diff --git a/rpython/translator/backendopt/test/test_graphanalyze.py b/rpython/translator/backendopt/test/test_graphanalyze.py --- a/rpython/translator/backendopt/test/test_graphanalyze.py +++ b/rpython/translator/backendopt/test/test_graphanalyze.py @@ -1,7 +1,7 @@ import random from rpython.tool.algo.unionfind import UnionFind -from rpython.translator.backendopt.graphanalyze import Dependency -from rpython.translator.backendopt.graphanalyze import DependencyTracker +from rpython.translator.backendopt.graphanalyze import (Dependency, + DependencyTracker, BoolGraphAnalyzer) class FakeGraphAnalyzer: @@ -49,3 +49,30 @@ method1 = rectrack(n, tracker) method2 = expected(n) assert method1 == method2 + + +def test_delayed_fnptr(): + from rpython.flowspace.model import SpaceOperation + from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator + from rpython.translator.translator import TranslationContext + t = TranslationContext() + t.buildannotator() + t.buildrtyper() + annhelper = MixLevelHelperAnnotator(t.rtyper) + def f(): + pass + c_f = annhelper.constfunc(f, [], None) + op = SpaceOperation('direct_call', [c_f], None) + analyzer = BoolGraphAnalyzer(t) + assert analyzer.analyze(op) + + +def test_null_fnptr(): + from rpython.flowspace.model import SpaceOperation, Constant + from rpython.rtyper.lltypesystem.lltype import Void, FuncType, nullptr + from rpython.translator.translator import TranslationContext + t = TranslationContext() + fnptr = nullptr(FuncType([], Void)) + op = SpaceOperation('direct_call', [Constant(fnptr)], None) + analyzer = BoolGraphAnalyzer(t) + assert not analyzer.analyze(op) diff --git a/rpython/translator/simplify.py b/rpython/translator/simplify.py --- a/rpython/translator/simplify.py +++ b/rpython/translator/simplify.py @@ -24,22 +24,13 @@ if not isinstance(f, lltype._ptr): return None try: - funcobj = f._getobj() + funcobj = f._obj except lltype.DelayedPointer: return None try: - callable = funcobj._callable - except (AttributeError, KeyError, AssertionError): - return None - try: return funcobj.graph except AttributeError: return None - try: - callable = funcobj._callable - return translator._graphof(callable) - except (AttributeError, KeyError, AssertionError): - return None def replace_exitswitch_by_constant(block, const): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit