[pypy-commit] pypy remove-getfield-pure: Merge with default
sbauman
pypy.commits at gmail.com
Tue Jan 12 23:42:19 EST 2016
Author: Spenser Andrew Bauman <sabauma at gmail.com>
Branch: remove-getfield-pure
Changeset: r81733:fd2fff063c7e
Date: 2016-01-12 14:47 -0500
http://bitbucket.org/pypy/pypy/changeset/fd2fff063c7e/
Log: Merge with 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,14 @@
return op.opname == 'jit_force_quasi_immutable'
class RandomEffectsAnalyzer(BoolGraphAnalyzer):
- def analyze_external_call(self, op, seen=None):
+ def analyze_external_call(self, funcobj, seen=None):
try:
- funcobj = op.args[0].value._obj
if funcobj.random_effects_on_gcobjs:
return True
- except (AttributeError, lltype.DelayedPointer):
+ except AttributeError:
return True # better safe than sorry
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:
@@ -39,19 +42,15 @@
self.cached_infos = []
self.cached_structs = []
self._lazy_setfield = None
- self._lazy_setfield_registered = False
- 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
@@ -72,7 +71,7 @@
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())
assert not self.possible_aliasing(optheap, structinfo)
@@ -87,11 +86,8 @@
# 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
+ # common case: store the 'op' as lazy_setfield
self._lazy_setfield = op
- #if not self._lazy_setfield_registered:
- # self._lazy_setfield_registered = True
else:
# this is the case where the pending setfield ends up
@@ -111,25 +107,13 @@
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))
+ 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
if op is not None:
@@ -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
@@ -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):
@@ -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_setfield(self, descr)
return pendingfields
def optimize_GETFIELD_GC_I(self, op):
@@ -507,7 +529,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
@@ -545,12 +567,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,7 +524,7 @@
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):
@@ -531,7 +532,7 @@
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 +627,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 +646,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 +692,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/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:
- return True
+ def analyze_external_call(self, funcobj, seen=None):
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/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
@@ -55,11 +55,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 +76,22 @@
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
+ graph = funcobj.graph
+ assert graph is not None
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)
More information about the pypy-commit
mailing list