[pypy-commit] pypy arm-backend-2: merge default up to e4a0b9e4d23b
bivab
noreply at buildbot.pypy.org
Thu Dec 29 09:57:24 CET 2011
Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r50941:c615cc3558ce
Date: 2011-12-26 13:48 +0100
http://bitbucket.org/pypy/pypy/changeset/c615cc3558ce/
Log: merge default up to e4a0b9e4d23b
diff --git a/pypy/annotation/specialize.py b/pypy/annotation/specialize.py
--- a/pypy/annotation/specialize.py
+++ b/pypy/annotation/specialize.py
@@ -36,9 +36,7 @@
newtup = SpaceOperation('newtuple', starargs, argscopy[-1])
newstartblock.operations.append(newtup)
newstartblock.closeblock(Link(argscopy, graph.startblock))
- graph.startblock.isstartblock = False
graph.startblock = newstartblock
- newstartblock.isstartblock = True
argnames = argnames + ['.star%d' % i for i in range(nb_extra_args)]
graph.signature = Signature(argnames)
# note that we can mostly ignore defaults: if nb_extra_args > 0,
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -304,5 +304,14 @@
never a dictionary as it sometimes is in CPython. Assigning to
``__builtins__`` has no effect.
+* directly calling the internal magic methods of a few built-in types
+ with invalid arguments may have a slightly different result. For
+ example, ``[].__add__(None)`` and ``(2).__add__(None)`` both return
+ ``NotImplemented`` on PyPy; on CPython, only the later does, and the
+ former raises ``TypeError``. (Of course, ``[]+None`` and ``2+None``
+ both raise ``TypeError`` everywhere.) This difference is an
+ implementation detail that shows up because of internal C-level slots
+ that PyPy does not have.
+
.. include:: _ref.txt
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -241,12 +241,15 @@
return op.opname == 'jit_force_quasi_immutable'
class RandomEffectsAnalyzer(BoolGraphAnalyzer):
- def analyze_direct_call(self, graph, seen=None):
- if hasattr(graph, "func") and hasattr(graph.func, "_ptr"):
- if graph.func._ptr._obj.random_effects_on_gcobjs:
+ def analyze_external_call(self, op, seen=None):
+ try:
+ funcobj = op.args[0].value._obj
+ if funcobj.random_effects_on_gcobjs:
return True
- return super(RandomEffectsAnalyzer, self).analyze_direct_call(graph,
- seen)
+ except (AttributeError, lltype.DelayedPointer):
+ pass
+ return super(RandomEffectsAnalyzer, self).analyze_external_call(
+ op, seen)
def analyze_simple_operation(self, op, graphinfo):
return False
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -15,6 +15,8 @@
from pypy.translator.simplify import get_funcobj
from pypy.translator.unsimplify import varoftype
+class UnsupportedMallocFlags(Exception):
+ pass
def transform_graph(graph, cpu=None, callcontrol=None, portal_jd=None):
"""Transform a control flow graph to make it suitable for
@@ -205,7 +207,19 @@
if op.args[0] in self.vable_array_vars:
self.vable_array_vars[op.result]= self.vable_array_vars[op.args[0]]
- rewrite_op_cast_pointer = rewrite_op_same_as
+ def rewrite_op_cast_pointer(self, op):
+ newop = self.rewrite_op_same_as(op)
+ assert newop is None
+ if (self._is_rclass_instance(op.args[0]) and
+ self._is_rclass_instance(op.result)):
+ FROM = op.args[0].concretetype.TO
+ TO = op.result.concretetype.TO
+ if lltype._castdepth(TO, FROM) > 0:
+ vtable = heaptracker.get_vtable_for_gcstruct(self.cpu, TO)
+ const_vtable = Constant(vtable, lltype.typeOf(vtable))
+ return [None, # hack, do the right renaming from op.args[0] to op.result
+ SpaceOperation("record_known_class", [op.args[0], const_vtable], None)]
+
def rewrite_op_cast_bool_to_int(self, op): pass
def rewrite_op_cast_bool_to_uint(self, op): pass
def rewrite_op_cast_char_to_int(self, op): pass
@@ -481,8 +495,22 @@
def rewrite_op_malloc_varsize(self, op):
if op.args[1].value['flavor'] == 'raw':
+ d = op.args[1].value.copy()
+ d.pop('flavor')
+ add_memory_pressure = d.pop('add_memory_pressure', False)
+ zero = d.pop('zero', False)
+ track_allocation = d.pop('track_allocation', True)
+ if d:
+ raise UnsupportedMallocFlags(d)
ARRAY = op.args[0].value
- return self._do_builtin_call(op, 'raw_malloc',
+ name = 'raw_malloc'
+ if zero:
+ name += '_zero'
+ if add_memory_pressure:
+ name += '_add_memory_pressure'
+ if not track_allocation:
+ name += '_no_track_allocation'
+ return self._do_builtin_call(op, name,
[op.args[2]],
extra = (ARRAY,),
extrakey = ARRAY)
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -599,10 +599,21 @@
return p
return _ll_0_alloc_with_del
- def build_ll_1_raw_malloc(ARRAY):
- def _ll_1_raw_malloc(n):
- return lltype.malloc(ARRAY, n, flavor='raw')
- return _ll_1_raw_malloc
+ def build_raw_malloc_builder(zero=False, add_memory_pressure=False, track_allocation=True):
+ def build_ll_1_raw_malloc(ARRAY):
+ def _ll_1_raw_malloc(n):
+ return lltype.malloc(ARRAY, n, flavor='raw', zero=zero, add_memory_pressure=add_memory_pressure)
+ return _ll_1_raw_malloc
+ return build_ll_1_raw_malloc
+
+ build_ll_1_raw_malloc = build_raw_malloc_builder()
+ build_ll_1_raw_malloc_zero = build_raw_malloc_builder(zero=True)
+ build_ll_1_raw_malloc_zero_add_memory_pressure = build_raw_malloc_builder(zero=True, add_memory_pressure=True)
+ build_ll_1_raw_malloc_add_memory_pressure = build_raw_malloc_builder(add_memory_pressure=True)
+ build_ll_1_raw_malloc_no_track_allocation = build_raw_malloc_builder(track_allocation=False)
+ build_ll_1_raw_malloc_zero_no_track_allocation = build_raw_malloc_builder(zero=True, track_allocation=False)
+ build_ll_1_raw_malloc_zero_add_memory_pressure_no_track_allocation = build_raw_malloc_builder(zero=True, add_memory_pressure=True, track_allocation=False)
+ build_ll_1_raw_malloc_add_memory_pressure_no_track_allocation = build_raw_malloc_builder(add_memory_pressure=True, track_allocation=False)
def build_ll_1_raw_free(ARRAY):
def _ll_1_raw_free(p):
diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py
--- a/pypy/jit/codewriter/test/test_call.py
+++ b/pypy/jit/codewriter/test/test_call.py
@@ -192,3 +192,21 @@
[op] = block.operations
call_descr = cc.getcalldescr(op)
assert call_descr.extrainfo.has_random_effects()
+
+def test_random_effects_on_stacklet_switch():
+ from pypy.jit.backend.llgraph.runner import LLtypeCPU
+ from pypy.rlib._rffi_stacklet import switch, thread_handle, handle
+ @jit.dont_look_inside
+ def f():
+ switch(rffi.cast(thread_handle, 0), rffi.cast(handle, 0))
+
+ rtyper = support.annotate(f, [])
+ jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
+ cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd])
+ res = cc.find_all_graphs(FakePolicy())
+
+ [f_graph] = [x for x in res if x.func is f]
+ [block, _] = list(f_graph.iterblocks())
+ op = block.operations[-1]
+ call_descr = cc.getcalldescr(op)
+ assert call_descr.extrainfo.has_random_effects()
diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -1,3 +1,5 @@
+
+import py
import random
try:
from itertools import product
@@ -15,12 +17,12 @@
from pypy.objspace.flow.model import FunctionGraph, Block, Link
from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
-from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr
+from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr, rffi
from pypy.rpython.lltypesystem.module import ll_math
from pypy.translator.unsimplify import varoftype
from pypy.jit.codewriter import heaptracker, effectinfo
from pypy.jit.codewriter.flatten import ListOfKind
-from pypy.jit.codewriter.jtransform import Transformer
+from pypy.jit.codewriter.jtransform import Transformer, UnsupportedMallocFlags
from pypy.jit.metainterp.history import getkind
def const(x):
@@ -538,6 +540,44 @@
assert op1.opname == '-live-'
assert op1.args == []
+def test_raw_malloc():
+ S = rffi.CArray(lltype.Signed)
+ v1 = varoftype(lltype.Signed)
+ v = varoftype(lltype.Ptr(S))
+ flags = Constant({'flavor': 'raw'}, lltype.Void)
+ op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
+ v1], v)
+ tr = Transformer(FakeCPU(), FakeResidualCallControl())
+ op0, op1 = tr.rewrite_operation(op)
+ assert op0.opname == 'residual_call_ir_i'
+ assert op0.args[0].value == 'raw_malloc' # pseudo-function as a str
+ assert op1.opname == '-live-'
+ assert op1.args == []
+
+def test_raw_malloc_zero():
+ S = rffi.CArray(lltype.Signed)
+ v1 = varoftype(lltype.Signed)
+ v = varoftype(lltype.Ptr(S))
+ flags = Constant({'flavor': 'raw', 'zero': True}, lltype.Void)
+ op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
+ v1], v)
+ tr = Transformer(FakeCPU(), FakeResidualCallControl())
+ op0, op1 = tr.rewrite_operation(op)
+ assert op0.opname == 'residual_call_ir_i'
+ assert op0.args[0].value == 'raw_malloc_zero' # pseudo-function as a str
+ assert op1.opname == '-live-'
+ assert op1.args == []
+
+def test_raw_malloc_unsupported_flag():
+ S = rffi.CArray(lltype.Signed)
+ v1 = varoftype(lltype.Signed)
+ v = varoftype(lltype.Ptr(S))
+ flags = Constant({'flavor': 'raw', 'unsupported_flag': True}, lltype.Void)
+ op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
+ v1], v)
+ tr = Transformer(FakeCPU(), FakeResidualCallControl())
+ py.test.raises(UnsupportedMallocFlags, tr.rewrite_operation, op)
+
def test_rename_on_links():
v1 = Variable()
v2 = Variable(); v2.concretetype = llmemory.Address
@@ -1140,4 +1180,4 @@
assert op1.opname == 'mark_opaque_ptr'
assert op1.args == [v1]
assert op1.result is None
- assert op2 is None
\ No newline at end of file
+ assert op2 is None
diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py
--- a/pypy/jit/codewriter/test/test_longlong.py
+++ b/pypy/jit/codewriter/test/test_longlong.py
@@ -78,7 +78,7 @@
oplist = tr.rewrite_operation(op)
assert len(oplist) == 2
assert oplist[0].opname == 'residual_call_irf_f'
- assert oplist[0].args[0].value == 'llong_from_int'
+ assert oplist[0].args[0].value == opname.split('_')[0]+'_from_int'
assert oplist[0].args[1] == 'calldescr-84'
assert list(oplist[0].args[2]) == [const(0)]
assert list(oplist[0].args[3]) == []
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -518,6 +518,9 @@
@arguments("r")
def bhimpl_mark_opaque_ptr(a):
pass
+ @arguments("r", "i")
+ def bhimpl_record_known_class(a, b):
+ pass
@arguments("i", returns="i")
def bhimpl_int_copy(a):
diff --git a/pypy/jit/metainterp/gc.py b/pypy/jit/metainterp/gc.py
--- a/pypy/jit/metainterp/gc.py
+++ b/pypy/jit/metainterp/gc.py
@@ -7,6 +7,9 @@
self.config = config
+class GC_none(GcDescription):
+ malloc_zero_filled = True
+
class GC_boehm(GcDescription):
malloc_zero_filled = True
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -260,6 +260,16 @@
def optimize_GUARD_FALSE(self, op):
self.optimize_guard(op, CONST_0)
+ def optimize_RECORD_KNOWN_CLASS(self, op):
+ value = self.getvalue(op.getarg(0))
+ expectedclassbox = op.getarg(1)
+ assert isinstance(expectedclassbox, Const)
+ realclassbox = value.get_constant_class(self.optimizer.cpu)
+ if realclassbox is not None:
+ assert realclassbox.same_constant(expectedclassbox)
+ return
+ value.make_constant_class(expectedclassbox, None)
+
def optimize_GUARD_CLASS(self, op):
value = self.getvalue(op.getarg(0))
expectedclassbox = op.getarg(1)
@@ -481,6 +491,9 @@
self.pure(rop.CAST_PTR_TO_INT, [op.result], op.getarg(0))
self.emit_operation(op)
+ def optimize_SAME_AS(self, op):
+ self.make_equal_to(op.result, self.getvalue(op.getarg(0)))
+
dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
default=OptRewrite.emit_operation)
optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -28,6 +28,9 @@
def optimize_MARK_OPAQUE_PTR(self, op):
pass
+ def optimize_RECORD_KNOWN_CLASS(self, op):
+ pass
+
dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_',
default=OptSimplify.emit_operation)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -6482,6 +6482,21 @@
# not obvious, because of the exception UnicodeDecodeError that
# can be raised by ll_str2unicode()
+ def test_record_known_class(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ record_known_class(p1, ConstClass(node_vtable))
+ guard_class(p1, ConstClass(node_vtable)) []
+ jump(p1)
+ """
+ expected = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected)
+
def test_quasi_immut(self):
ops = """
[p0, p1, i0]
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -243,6 +243,18 @@
def opimpl_mark_opaque_ptr(self, box):
return self.execute(rop.MARK_OPAQUE_PTR, box)
+ @arguments("box", "box")
+ def opimpl_record_known_class(self, box, clsbox):
+ from pypy.rpython.lltypesystem import llmemory
+ if self.metainterp.heapcache.is_class_known(box):
+ return
+ adr = clsbox.getaddr()
+ bounding_class = llmemory.cast_adr_to_ptr(adr, rclass.CLASSTYPE)
+ if bounding_class.subclassrange_max - bounding_class.subclassrange_min == 1:
+ # precise class knowledge, this can be used
+ self.execute(rop.RECORD_KNOWN_CLASS, box, clsbox)
+ self.metainterp.heapcache.class_now_known(box)
+
@arguments("box")
def _opimpl_any_return(self, box):
self.metainterp.finishframe(box)
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -494,6 +494,7 @@
'COPYSTRCONTENT/5', # src, dst, srcstart, dststart, length
'COPYUNICODECONTENT/5',
'QUASIIMMUT_FIELD/1d', # [objptr], descr=SlowMutateDescr
+ 'RECORD_KNOWN_CLASS/2', # [objptr, clsptr]
'_CANRAISE_FIRST', # ----- start of can_raise operations -----
'_CALL_FIRST',
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3585,6 +3585,67 @@
self.interp_operations(f, [5], translationoptions=translationoptions)
+ def test_annotation_gives_knowledge_to_tracer(self):
+ class Base(object):
+ pass
+ class A(Base):
+ def f(self):
+ return self.a
+ def g(self):
+ return self.a + 1
+ class B(Base):
+ def f(self):
+ return self.b
+ def g(self):
+ return self.b + 1
+ class C(B):
+ def f(self):
+ self.c += 1
+ return self.c
+ def g(self):
+ return self.c + 1
+ @dont_look_inside
+ def make(x):
+ if x > 0:
+ a = A()
+ a.a = x + 1
+ elif x < 0:
+ a = B()
+ a.b = -x
+ else:
+ a = C()
+ a.c = 10
+ return a
+ def f(x):
+ a = make(x)
+ if x > 0:
+ assert isinstance(a, A)
+ z = a.f()
+ elif x < 0:
+ assert isinstance(a, B)
+ z = a.f()
+ else:
+ assert isinstance(a, C)
+ z = a.f()
+ return z + a.g()
+ res1 = f(6)
+ res2 = self.interp_operations(f, [6])
+ assert res1 == res2
+ self.check_operations_history(guard_class=0, record_known_class=1)
+
+ res1 = f(-6)
+ res2 = self.interp_operations(f, [-6])
+ assert res1 == res2
+ # cannot use record_known_class here, because B has a subclass
+ self.check_operations_history(guard_class=1)
+
+ res1 = f(0)
+ res2 = self.interp_operations(f, [0])
+ assert res1 == res2
+ # here it works again
+ self.check_operations_history(guard_class=0, record_known_class=1)
+
+
class TestLLtype(BaseLLtypeTests, LLJitMixin):
def test_tagged(self):
from pypy.rlib.objectmodel import UnboxedValue
diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py
--- a/pypy/jit/metainterp/test/test_virtual.py
+++ b/pypy/jit/metainterp/test/test_virtual.py
@@ -612,7 +612,7 @@
return node.value
res = self.meta_interp(f, [48, 3], policy=StopAtXPolicy(externfn))
assert res == f(48, 3)
- self.check_loop_count(3)
+ self.check_loop_count(5)
res = self.meta_interp(f, [40, 3], policy=StopAtXPolicy(externfn))
assert res == f(40, 3)
self.check_loop_count(3)
@@ -761,6 +761,27 @@
res = self.meta_interp(f, [0x1F, 0x11])
assert res == f(0x1F, 0x11)
+ def test_duplicated_virtual(self):
+ myjitdriver = JitDriver(greens = [], reds = ['n', 'node1', 'node2'])
+ def f(n):
+ node1 = self._new()
+ node1.value = 0
+ node2 = self._new()
+ node2.value = 1
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n, node1=node1, node2=node2)
+ next = self._new()
+ next.value = node1.value + node2.value + n
+ node1 = next
+ node2 = next
+ n -= 1
+ return node1.value
+ res = self.meta_interp(f, [10])
+ assert res == f(10)
+ self.check_resops(new_with_vtable=0, new=0)
+
+
+
class VirtualMiscTests:
def test_multiple_equal_virtuals(self):
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -255,10 +255,8 @@
s_binding = self.translator.annotator.binding
jd._portal_args_s = [s_binding(v) for v in args]
graph = copygraph(graph)
- graph.startblock.isstartblock = False
[jmpp] = find_jit_merge_points([graph])
graph.startblock = support.split_before_jit_merge_point(*jmpp)
- graph.startblock.isstartblock = True
# a crash in the following checkgraph() means that you forgot
# to list some variable in greens=[] or reds=[] in JitDriver,
# or that a jit_merge_point() takes a constant as an argument.
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -27,6 +27,7 @@
'builtinify' : 'interp_magic.builtinify',
'lookup_special' : 'interp_magic.lookup_special',
'do_what_I_mean' : 'interp_magic.do_what_I_mean',
+ 'list_strategy' : 'interp_magic.list_strategy',
}
submodules = {
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -5,7 +5,6 @@
from pypy.objspace.std.typeobject import MethodCache
from pypy.objspace.std.mapdict import IndexCache
-
def internal_repr(space, w_object):
return space.wrap('%r' % (w_object,))
@@ -73,3 +72,11 @@
def do_what_I_mean(space):
return space.wrap(42)
+
+def list_strategy(space, w_list):
+ from pypy.objspace.std.listobject import W_ListObject
+ if isinstance(w_list, W_ListObject):
+ return space.wrap(w_list.strategy._applevel_repr)
+ else:
+ w_msg = space.wrap("Can only get the list strategy of a list")
+ raise OperationError(space.w_TypeError, w_msg)
diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py
--- a/pypy/module/__pypy__/test/test_special.py
+++ b/pypy/module/__pypy__/test/test_special.py
@@ -5,7 +5,7 @@
def setup_class(cls):
if option.runappdirect:
py.test.skip("does not make sense on pypy-c")
- cls.space = gettestobjspace(**{"objspace.usemodules.select": False})
+ cls.space = gettestobjspace(**{"objspace.usemodules.select": False, "objspace.std.withrangelist": True})
def test__isfake(self):
from __pypy__ import isfake
@@ -54,3 +54,21 @@
from __pypy__ import do_what_I_mean
x = do_what_I_mean()
assert x == 42
+
+ def test_list_strategy(self):
+ from __pypy__ import list_strategy
+
+ l = [1, 2, 3]
+ assert list_strategy(l) == "int"
+ l = ["a", "b", "c"]
+ assert list_strategy(l) == "str"
+ l = [1.1, 2.2, 3.3]
+ assert list_strategy(l) == "float"
+ l = range(3)
+ assert list_strategy(l) == "range"
+ l = [1, "b", 3]
+ assert list_strategy(l) == "object"
+ l = []
+ assert list_strategy(l) == "empty"
+ o = 5
+ raises(TypeError, list_strategy, 5)
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -131,7 +131,7 @@
def binop(func):
- func._annspecialcase_ = "specialize:call_location"
+ specialize.argtype(1, 2)(func)
@functools.wraps(func)
def impl(self, v1, v2):
return self.adapt_val(func(self,
@@ -141,6 +141,7 @@
return impl
def raw_binop(func):
+ specialize.argtype(1, 2)(func)
# Returns the result unwrapped.
@functools.wraps(func)
def impl(self, v1, v2):
@@ -151,6 +152,7 @@
return impl
def unaryop(func):
+ specialize.argtype(1)(func)
@functools.wraps(func)
def impl(self, v):
return self.adapt_val(func(self, self.for_computation(self.unbox(v))))
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -1110,6 +1110,14 @@
def debug_repr(self):
return 'Slice(%s)' % self.parent.debug_repr()
+ def copy(self):
+ array = NDimArray(self.size, self.shape[:], self.find_dtype())
+ iter = self.start_iter()
+ while not iter.done():
+ array.setitem(iter.offset, self.getitem(iter.offset))
+ iter = iter.next(len(self.shape))
+ return array
+
class NDimArray(BaseArray):
""" A class representing contiguous array. We know that each iteration
by say ufunc will increase the data index by one
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -760,6 +760,19 @@
a[::-1] = a + a
assert (a == [8, 6, 4, 2, 0]).all()
+ def test_debug_repr(self):
+ from numpypy import zeros, sin
+ a = zeros(1)
+ assert a.__debug_repr__() == 'Array'
+ assert (a + a).__debug_repr__() == 'Call2(add, Array, Array)'
+ assert (a[::2]).__debug_repr__() == 'Slice(Array)'
+ assert (a + 2).__debug_repr__() == 'Call2(add, Array, Scalar)'
+ assert (a + a.flat).__debug_repr__() == 'Call2(add, Array, FlatIter(Array))'
+ assert sin(a).__debug_repr__() == 'Call1(sin, Array)'
+ b = a + a
+ b[0] = 3
+ assert b.__debug_repr__() == 'Call2(add, forced=Array)'
+
class AppTestMultiDim(BaseNumpyAppTest):
def test_init(self):
import numpypy
@@ -989,18 +1002,11 @@
a = array([1, 2, 3])
assert dot(a.flat, a.flat) == 14
- def test_debug_repr(self):
- from numpypy import zeros, sin
- a = zeros(1)
- assert a.__debug_repr__() == 'Array'
- assert (a + a).__debug_repr__() == 'Call2(add, Array, Array)'
- assert (a[::2]).__debug_repr__() == 'Slice(Array)'
- assert (a + 2).__debug_repr__() == 'Call2(add, Array, Scalar)'
- assert (a + a.flat).__debug_repr__() == 'Call2(add, Array, FlatIter(Array))'
- assert sin(a).__debug_repr__() == 'Call1(sin, Array)'
- b = a + a
- b[0] = 3
- assert b.__debug_repr__() == 'Call2(add, forced=Array)'
+ def test_slice_copy(self):
+ from numpypy import zeros
+ a = zeros((10, 10))
+ b = a[0].copy()
+ assert (b == zeros(10)).all()
class AppTestSupport(object):
def setup_class(cls):
diff --git a/pypy/objspace/flow/model.py b/pypy/objspace/flow/model.py
--- a/pypy/objspace/flow/model.py
+++ b/pypy/objspace/flow/model.py
@@ -38,7 +38,6 @@
def __init__(self, name, startblock, return_var=None):
self.name = name # function name (possibly mangled already)
self.startblock = startblock
- self.startblock.isstartblock = True
# build default returnblock
self.returnblock = Block([return_var or Variable()])
self.returnblock.operations = ()
@@ -171,11 +170,10 @@
class Block(object):
- __slots__ = """isstartblock inputargs operations exitswitch
+ __slots__ = """inputargs operations exitswitch
exits blockcolor""".split()
def __init__(self, inputargs):
- self.isstartblock = False
self.inputargs = list(inputargs) # mixed list of variable/const XXX
self.operations = [] # list of SpaceOperation(s)
self.exitswitch = None # a variable or
@@ -452,7 +450,6 @@
newblock.closeblock(*newlinks)
newstartblock = blockmap[graph.startblock]
- newstartblock.isstartblock = True
newgraph = FunctionGraph(graph.name, newstartblock)
newgraph.returnblock = blockmap[graph.returnblock]
newgraph.exceptblock = blockmap[graph.exceptblock]
@@ -490,7 +487,6 @@
for block in graph.iterblocks():
- assert bool(block.isstartblock) == (block is graph.startblock)
assert type(block.exits) is tuple, (
"block.exits is a %s (closeblock() or recloseblock() missing?)"
% (type(block.exits).__name__,))
diff --git a/pypy/objspace/flow/test/test_checkgraph.py b/pypy/objspace/flow/test/test_checkgraph.py
--- a/pypy/objspace/flow/test/test_checkgraph.py
+++ b/pypy/objspace/flow/test/test_checkgraph.py
@@ -13,20 +13,6 @@
py.test.raises(AssertionError, checkgraph, g)
-def test_nostartblock():
- g = FunctionGraph("g", Block([]))
- g.startblock.closeblock(Link([Constant(1)], g.returnblock))
- g.startblock.isstartblock = False
- py.test.raises(AssertionError, checkgraph, g)
-
-def test_twostartblocks():
- g = FunctionGraph("g", Block([]))
- b = Block([])
- b.isstartblock = True
- g.startblock.closeblock(Link([], b))
- b.closeblock(Link([Constant(1)], g.returnblock))
- py.test.raises(AssertionError, checkgraph, g)
-
def test_exitlessblocknotexitblock():
g = FunctionGraph("g", Block([]))
py.test.raises(AssertionError, checkgraph, g)
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -50,6 +50,13 @@
else:
return space.fromcache(StringListStrategy)
+ # check for floats
+ for w_obj in list_w:
+ if not is_W_FloatObject(w_obj):
+ break
+ else:
+ return space.fromcache(FloatListStrategy)
+
return space.fromcache(ObjectListStrategy)
def is_W_IntObject(w_object):
@@ -60,7 +67,9 @@
from pypy.objspace.std.stringobject import W_StringObject
return type(w_object) is W_StringObject
-
+def is_W_FloatObject(w_object):
+ from pypy.objspace.std.floatobject import W_FloatObject
+ return type(w_object) is W_FloatObject
class W_ListObject(W_AbstractListObject):
from pypy.objspace.std.listtype import list_typedef as typedef
@@ -317,6 +326,8 @@
to the added item.
W_Lists do not switch back to EmptyListStrategy when becoming empty again."""
+ _applevel_repr = "empty"
+
def __init__(self, space):
ListStrategy.__init__(self, space)
# cache an empty list that is used whenever getitems is called (i.e. sorting)
@@ -364,6 +375,8 @@
strategy = self.space.fromcache(IntegerListStrategy)
elif is_W_StringObject(w_item):
strategy = self.space.fromcache(StringListStrategy)
+ elif is_W_FloatObject(w_item):
+ strategy = self.space.fromcache(FloatListStrategy)
else:
strategy = self.space.fromcache(ObjectListStrategy)
@@ -415,6 +428,8 @@
On any operation destroying the range (inserting, appending non-ints)
the strategy is switched to IntegerListStrategy."""
+ _applevel_repr = "range"
+
def switch_to_integer_strategy(self, w_list):
items = self._getitems_range(w_list, False)
strategy = w_list.strategy = self.space.fromcache(IntegerListStrategy)
@@ -853,6 +868,7 @@
class ObjectListStrategy(AbstractUnwrappedStrategy, ListStrategy):
_none_value = None
+ _applevel_repr = "object"
def unwrap(self, w_obj):
return w_obj
@@ -881,6 +897,7 @@
class IntegerListStrategy(AbstractUnwrappedStrategy, ListStrategy):
_none_value = 0
+ _applevel_repr = "int"
def wrap(self, intval):
return self.space.wrap(intval)
@@ -905,8 +922,36 @@
if reverse:
l.reverse()
+class FloatListStrategy(AbstractUnwrappedStrategy, ListStrategy):
+ _none_value = 0.0
+ _applevel_repr = "float"
+
+ def wrap(self, floatval):
+ return self.space.wrap(floatval)
+
+ def unwrap(self, w_float):
+ return self.space.float_w(w_float)
+
+ erase, unerase = rerased.new_erasing_pair("float")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def is_correct_type(self, w_obj):
+ return is_W_FloatObject(w_obj)
+
+ def list_is_correct_type(self, w_list):
+ return w_list.strategy is self.space.fromcache(FloatListStrategy)
+
+ def sort(self, w_list, reverse):
+ l = self.unerase(w_list.lstorage)
+ sorter = FloatSort(l, len(l))
+ sorter.sort()
+ if reverse:
+ l.reverse()
+
class StringListStrategy(AbstractUnwrappedStrategy, ListStrategy):
_none_value = None
+ _applevel_repr = "str"
def wrap(self, stringval):
return self.space.wrap(stringval)
@@ -934,6 +979,7 @@
def getitems_str(self, w_list):
return self.unerase(w_list.lstorage)
+
# _______________________________________________________
init_signature = Signature(['sequence'], None, None)
@@ -1282,6 +1328,7 @@
TimSort = make_timsort_class()
IntBaseTimSort = make_timsort_class()
+FloatBaseTimSort = make_timsort_class()
StringBaseTimSort = make_timsort_class()
class KeyContainer(baseobjspace.W_Root):
@@ -1302,6 +1349,10 @@
def lt(self, a, b):
return a < b
+class FloatSort(FloatBaseTimSort):
+ def lt(self, a, b):
+ return a < b
+
class StringSort(StringBaseTimSort):
def lt(self, a, b):
return a < b
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -470,11 +470,17 @@
l.extend(iter([1, 2, 3, 4]))
assert l is l0
assert l == [1, 1, 2, 3, 4]
+
l = l0 = ['a']
l.extend(iter(['b', 'c', 'd']))
assert l == ['a', 'b', 'c', 'd']
assert l is l0
+ l = l0 = [1.2]
+ l.extend(iter([2.3, 3.4, 4.5]))
+ assert l == [1.2, 2.3, 3.4, 4.5]
+ assert l is l0
+
def test_sort(self):
l = l0 = [1, 5, 3, 0]
l.sort()
@@ -493,6 +499,10 @@
l.sort(reverse=True)
assert l == ["d", "c", "b", "a"]
+ l = [3.3, 2.2, 4.4, 1.1, 3.1, 5.5]
+ l.sort()
+ assert l == [1.1, 2.2, 3.1, 3.3, 4.4, 5.5]
+
def test_sort_cmp(self):
def lencmp(a,b): return cmp(len(a), len(b))
l = [ 'a', 'fiver', 'tre', '' ]
@@ -546,11 +556,19 @@
assert l[-2] == 6
raises(IndexError, "l[len(l)]")
raises(IndexError, "l[-len(l)-1]")
+
l = ['a', 'b', 'c']
assert l[0] == 'a'
assert l[-1] == 'c'
assert l[-2] == 'b'
raises(IndexError, "l[len(l)]")
+
+ l = [1.1, 2.2, 3.3]
+ assert l[0] == 1.1
+ assert l[-1] == 3.3
+ assert l[-2] == 2.2
+ raises(IndexError, "l[len(l)]")
+
l = []
raises(IndexError, "l[1]")
@@ -588,6 +606,16 @@
assert l is l0
raises(IndexError, "del l[0]")
+ l = l0 = [1.1, 2.2, 3.3]
+ del l[0]
+ assert l == [2.2, 3.3]
+ del l[-1]
+ assert l == [2.2]
+ del l[-1]
+ assert l == []
+ assert l is l0
+ raises(IndexError, "del l[0]")
+
l = range(10)
del l[5]
assert l == [0, 1, 2, 3, 4, 6, 7, 8, 9]
@@ -627,9 +655,15 @@
del l[:]
assert l is l0
assert l == []
+
l = ['a', 'b']
del l[:]
assert l == []
+
+ l = [1.1, 2.2]
+ del l[:]
+ assert l == []
+
l = range(5)
del l[:]
assert l == []
@@ -640,6 +674,11 @@
assert l is l0
assert l == [1,2,3,4,5]
+ l = l0 = [1.1,2.2,3.3]
+ l += [4.4,5.5]
+ assert l is l0
+ assert l == [1.1,2.2,3.3,4.4,5.5]
+
l = l0 = ['a', 'b', 'c']
l1 = l[:]
l += ['d']
@@ -697,6 +736,11 @@
l *= -5
assert l == []
+ l = l0 = [1.1, 2.2]
+ l *= 2
+ assert l is l0
+ assert l == [1.1, 2.2, 1.1, 2.2]
+
l = range(2)
l *= 2
assert l == [0, 1, 0, 1]
@@ -731,6 +775,10 @@
assert c.index(0) == 0
raises(ValueError, c.index, 3)
+ c = [0.0, 2.2, 4.4]
+ assert c.index(0) == 0.0
+ raises(ValueError, c.index, 3)
+
def test_index_cpython_bug(self):
if self.on_cpython:
skip("cpython has a bug here")
@@ -779,6 +827,10 @@
l[::3] = ('a', 'b')
assert l == ['a', 1, 2, 'b', 4, 5]
+ l = [0.0, 1.1, 2.2, 3.3, 4.4, 5.5]
+ l[::3] = ('a', 'b')
+ assert l == ['a', 1.1, 2.2, 'b', 4.4, 5.5]
+
def test_setslice_with_self(self):
l = [1,2,3,4]
l[:] = l
@@ -835,6 +887,10 @@
l.append("a")
assert l == [1,2,3,"a"]
+ l = [1.1, 2.2, 3.3]
+ l.append(4.4)
+ assert l == [1.1, 2.2, 3.3, 4.4]
+
def test_count(self):
c = list('hello')
assert c.count('l') == 2
@@ -875,6 +931,10 @@
l.pop()
assert l == range(9)
+ l = [1.1, 2.2, 3.3]
+ l.pop()
+ assert l == [1.1, 2.2]
+
l = []
raises(IndexError, l.pop, 0)
@@ -897,16 +957,19 @@
l2 = ["1", "2", "3", "4"]
l3 = range(5)
l4 = [1, 2, 3, "4"]
+ l5 = [1.1, 2.2, 3.3, 4.4]
raises(IndexError, l1.pop, -5)
raises(IndexError, l2.pop, -5)
raises(IndexError, l3.pop, -6)
raises(IndexError, l4.pop, -5)
+ raises(IndexError, l5.pop, -5)
assert l1.pop(-2) == 3
assert l2.pop(-2) == "3"
assert l3.pop(-2) == 3
assert l4.pop(-2) == 3
+ assert l5.pop(-2) == 3.3
def test_remove(self):
c = list('hello world')
@@ -925,6 +988,13 @@
l = [0, 3, 5]
raises(ValueError, c.remove, 2)
+ l = [0.0, 1.1, 2.2, 3.3, 4.4]
+ l.remove(2.2)
+ assert l == [0.0, 1.1, 3.3, 4.4]
+ l = [0.0, 3.3, 5.5]
+ raises(ValueError, c.remove, 2)
+ raises(ValueError, c.remove, 2.2)
+
def test_reverse(self):
c = list('hello world')
c.reverse()
diff --git a/pypy/objspace/std/test/test_liststrategies.py b/pypy/objspace/std/test/test_liststrategies.py
--- a/pypy/objspace/std/test/test_liststrategies.py
+++ b/pypy/objspace/std/test/test_liststrategies.py
@@ -1,4 +1,4 @@
-from pypy.objspace.std.listobject import W_ListObject, EmptyListStrategy, ObjectListStrategy, IntegerListStrategy, StringListStrategy, RangeListStrategy, make_range_list
+from pypy.objspace.std.listobject import W_ListObject, EmptyListStrategy, ObjectListStrategy, IntegerListStrategy, FloatListStrategy, StringListStrategy, RangeListStrategy, make_range_list
from pypy.objspace.std import listobject
from pypy.objspace.std.test.test_listobject import TestW_ListObject
@@ -15,7 +15,7 @@
def test_empty_to_any(self):
l = W_ListObject(self.space, [])
assert isinstance(l.strategy, EmptyListStrategy)
- l.append(self.space.wrap(1.))
+ l.append(self.space.wrap((1,3)))
assert isinstance(l.strategy, ObjectListStrategy)
l = W_ListObject(self.space, [])
@@ -28,6 +28,11 @@
l.append(self.space.wrap('a'))
assert isinstance(l.strategy, StringListStrategy)
+ l = W_ListObject(self.space, [])
+ assert isinstance(l.strategy, EmptyListStrategy)
+ l.append(self.space.wrap(1.2))
+ assert isinstance(l.strategy, FloatListStrategy)
+
def test_int_to_any(self):
l = W_ListObject(self.space, [self.space.wrap(1),self.space.wrap(2),self.space.wrap(3)])
assert isinstance(l.strategy, IntegerListStrategy)
@@ -44,6 +49,14 @@
l.append(self.space.wrap(3))
assert isinstance(l.strategy, ObjectListStrategy)
+ def test_float_to_any(self):
+ l = W_ListObject(self.space, [self.space.wrap(1.1),self.space.wrap(2.2),self.space.wrap(3.3)])
+ assert isinstance(l.strategy, FloatListStrategy)
+ l.append(self.space.wrap(4.4))
+ assert isinstance(l.strategy, FloatListStrategy)
+ l.append(self.space.wrap("a"))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
def test_setitem(self):
# This should work if test_listobject.py passes
l = W_ListObject(self.space, [self.space.wrap('a'),self.space.wrap('b'),self.space.wrap('c')])
@@ -65,6 +78,12 @@
l.setitem(0, self.space.wrap(2))
assert isinstance(l.strategy, ObjectListStrategy)
+ # FloatStrategy to ObjectStrategy
+ l = W_ListObject(self.space, [self.space.wrap(1.2),self.space.wrap(2.3),self.space.wrap(3.4)])
+ assert isinstance(l.strategy, FloatListStrategy)
+ l.setitem(0, self.space.wrap("a"))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
def test_insert(self):
# no change
l = W_ListObject(self.space, [self.space.wrap(1),self.space.wrap(2),self.space.wrap(3)])
@@ -84,6 +103,12 @@
l.insert(3, self.space.wrap('d'))
assert isinstance(l.strategy, ObjectListStrategy)
+ # FloatStrategy
+ l = W_ListObject(self.space, [self.space.wrap(1.1),self.space.wrap(2.2),self.space.wrap(3.3)])
+ assert isinstance(l.strategy, FloatListStrategy)
+ l.insert(3, self.space.wrap('d'))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
# EmptyStrategy
l = W_ListObject(self.space, [])
assert isinstance(l.strategy, EmptyListStrategy)
@@ -95,7 +120,9 @@
l.insert(0, self.space.wrap(2))
assert isinstance(l.strategy, IntegerListStrategy)
- def notest_list_empty_after_delete(self):
+ def test_list_empty_after_delete(self):
+ import py
+ py.test.skip("return to emptyliststrategy is not supported anymore")
l = W_ListObject(self.space, [self.space.wrap(3)])
assert isinstance(l.strategy, IntegerListStrategy)
l.deleteitem(0)
@@ -117,21 +144,36 @@
l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
assert isinstance(l.strategy, IntegerListStrategy)
+ # IntegerStrategy to IntegerStrategy
l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
assert isinstance(l.strategy, IntegerListStrategy)
l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5), self.space.wrap(6)]))
assert isinstance(l.strategy, IntegerListStrategy)
+ # ObjectStrategy to ObjectStrategy
l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap('b'), self.space.wrap(3)])
assert isinstance(l.strategy, ObjectListStrategy)
l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
assert isinstance(l.strategy, ObjectListStrategy)
+ # IntegerStrategy to ObjectStrategy
l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
assert isinstance(l.strategy, IntegerListStrategy)
l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap('a'), self.space.wrap('b'), self.space.wrap('c')]))
assert isinstance(l.strategy, ObjectListStrategy)
+ # StringStrategy to ObjectStrategy
+ l = W_ListObject(self.space, [self.space.wrap('a'), self.space.wrap('b'), self.space.wrap('c')])
+ assert isinstance(l.strategy, StringListStrategy)
+ l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ # FloatStrategy to ObjectStrategy
+ l = W_ListObject(self.space, [self.space.wrap(1.1), self.space.wrap(2.2), self.space.wrap(3.3)])
+ assert isinstance(l.strategy, FloatListStrategy)
+ l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap('a'), self.space.wrap(2), self.space.wrap(3)]))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
def test_setslice_List(self):
def wrapitems(items):
@@ -160,6 +202,11 @@
keep_other_strategy(l, 0, 2, other.length(), other)
assert l.strategy is self.space.fromcache(StringListStrategy)
+ l = W_ListObject(self.space, wrapitems([1.1, 2.2, 3.3, 4.4, 5.5]))
+ other = W_ListObject(self.space, [])
+ keep_other_strategy(l, 0, 1, l.length(), other)
+ assert l.strategy is self.space.fromcache(FloatListStrategy)
+
l = W_ListObject(self.space, wrapitems(["a",3,"c",4,"e"]))
other = W_ListObject(self.space, wrapitems(["a", "b", "c"]))
keep_other_strategy(l, 0, 2, other.length(), other)
@@ -194,6 +241,11 @@
l.extend(W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5), self.space.wrap(6)]))
assert isinstance(l.strategy, IntegerListStrategy)
+ l = W_ListObject(self.space, [self.space.wrap(1.1), self.space.wrap(2.2), self.space.wrap(3.3)])
+ assert isinstance(l.strategy, FloatListStrategy)
+ l.extend(W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5), self.space.wrap(6)]))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
def test_empty_extend_with_any(self):
empty = W_ListObject(self.space, [])
assert isinstance(empty.strategy, EmptyListStrategy)
@@ -220,6 +272,11 @@
empty = W_ListObject(self.space, [])
assert isinstance(empty.strategy, EmptyListStrategy)
+ empty.extend(W_ListObject(self.space, [self.space.wrap(1.1), self.space.wrap(2.2), self.space.wrap(3.3)]))
+ assert isinstance(empty.strategy, FloatListStrategy)
+
+ empty = W_ListObject(self.space, [])
+ assert isinstance(empty.strategy, EmptyListStrategy)
empty.extend(W_ListObject(self.space, []))
assert isinstance(empty.strategy, EmptyListStrategy)
@@ -293,12 +350,13 @@
l.setslice(0, 1, 3, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
assert isinstance(l.strategy, IntegerListStrategy)
- def test_get_items_copy(self):
+ def test_copy_list(self):
l1 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
- l2 = l1.getitems()
+ l2 = l1.clone()
l2.append(self.space.wrap(4))
assert not l2 == l1.getitems()
+ def test_getitems_does_not_copy_object_list(self):
l1 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap("two"), self.space.wrap(3)])
l2 = l1.getitems()
l2.append(self.space.wrap("four"))
@@ -345,7 +403,6 @@
# should not raise
assert getslice__List_ANY_ANY(self.space, l, self.space.wrap(15), self.space.wrap(2222)).strategy == self.space.fromcache(EmptyListStrategy)
-
def test_add_to_rangelist(self):
l1 = make_range_list(self.space, 1, 1, 3)
l2 = W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5)])
diff --git a/pypy/rlib/_stacklet_n_a.py b/pypy/rlib/_stacklet_n_a.py
--- a/pypy/rlib/_stacklet_n_a.py
+++ b/pypy/rlib/_stacklet_n_a.py
@@ -1,4 +1,5 @@
from pypy.rlib import _rffi_stacklet as _c
+from pypy.rlib import objectmodel, debug
from pypy.rpython.annlowlevel import llhelper
from pypy.tool.staticmethods import StaticMethods
@@ -21,6 +22,9 @@
def destroy(thrd, h):
_c.destroy(thrd._thrd, h)
+ if objectmodel.we_are_translated():
+ debug.debug_print("not using a framework GC: "
+ "stacklet_destroy() may leak")
is_empty_handle = _c.is_empty_handle
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -176,7 +176,6 @@
return decorator
@oopspec("jit.isconstant(value)")
- at specialize.ll()
def isconstant(value):
"""
While tracing, returns whether or not the value is currently known to be
@@ -186,9 +185,9 @@
This is for advanced usage only.
"""
return NonConstant(False)
+isconstant._annspecialcase_ = "specialize:call_location"
@oopspec("jit.isvirtual(value)")
- at specialize.ll()
def isvirtual(value):
"""
Returns if this value is virtual, while tracing, it's relatively
@@ -197,6 +196,7 @@
This is for advanced usage only.
"""
return NonConstant(False)
+isvirtual._annspecialcase_ = "specialize:call_location"
class Entry(ExtRegistryEntry):
_about_ = hint
diff --git a/pypy/rlib/test/test_rstacklet.py b/pypy/rlib/test/test_rstacklet.py
--- a/pypy/rlib/test/test_rstacklet.py
+++ b/pypy/rlib/test/test_rstacklet.py
@@ -65,6 +65,15 @@
self.tasks[0].withdepth(self.random.genrand32() % 50)
assert len(self.tasks[0].lst) == 0
+ @here_is_a_test
+ def test_destroy(self):
+ # this used to give MemoryError in shadowstack tests
+ for i in range(100000):
+ self.status = 0
+ h = self.sthread.new(switchbackonce_callback,
+ rffi.cast(llmemory.Address, 321))
+ self.sthread.destroy(h)
+
def any_alive(self):
for task in self.tasks:
if task.h:
diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py b/pypy/rpython/memory/gctransform/asmgcroot.py
--- a/pypy/rpython/memory/gctransform/asmgcroot.py
+++ b/pypy/rpython/memory/gctransform/asmgcroot.py
@@ -92,7 +92,6 @@
# make a copy of the graph that will reload the values
graph2 = copygraph(fnptr._obj.graph)
block2 = graph2.startblock
- block2.isstartblock = False
block1 = Block([])
reloadedvars = []
for v, c_p in zip(block2.inputargs, sra):
@@ -109,7 +108,6 @@
[w], v))
reloadedvars.append(v)
block1.closeblock(Link(reloadedvars, block2))
- block1.isstartblock = True
graph2.startblock = block1
FUNC2 = lltype.FuncType([], FUNC1.RESULT)
fnptr2 = lltype.functionptr(FUNC2,
diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py
--- a/pypy/rpython/memory/gctransform/shadowstack.py
+++ b/pypy/rpython/memory/gctransform/shadowstack.py
@@ -307,7 +307,7 @@
"restore_state_from: broken shadowstack")
self.gcdata.root_stack_base = shadowstackref.base
self.gcdata.root_stack_top = shadowstackref.top
- self.destroy(shadowstackref)
+ self._cleanup(shadowstackref)
def start_fresh_new_state(self):
self.gcdata.root_stack_base = self.unused_full_stack
@@ -315,6 +315,10 @@
self.unused_full_stack = llmemory.NULL
def destroy(self, shadowstackref):
+ llmemory.raw_free(shadowstackref.base)
+ self._cleanup(shadowstackref)
+
+ def _cleanup(self, shadowstackref):
shadowstackref.base = llmemory.NULL
shadowstackref.top = llmemory.NULL
shadowstackref.context = llmemory.NULL
diff --git a/pypy/rpython/memory/gctransform/test/test_transform.py b/pypy/rpython/memory/gctransform/test/test_transform.py
--- a/pypy/rpython/memory/gctransform/test/test_transform.py
+++ b/pypy/rpython/memory/gctransform/test/test_transform.py
@@ -102,12 +102,12 @@
llops.genop("gc_pop_alive", [var])
-def checkblock(block, is_borrowed):
+def checkblock(block, is_borrowed, is_start_block):
if block.operations == ():
# a return/exception block -- don't want to think about them
# (even though the test passes for somewhat accidental reasons)
return
- if block.isstartblock:
+ if is_start_block:
refs_in = 0
else:
refs_in = len([v for v in block.inputargs if isinstance(v, Variable)
@@ -167,7 +167,7 @@
if check:
for graph, is_borrowed in graphs_borrowed.iteritems():
for block in graph.iterblocks():
- checkblock(block, is_borrowed)
+ checkblock(block, is_borrowed, block is graph.startblock)
return t, transformer
def getops(graph):
diff --git a/pypy/rpython/memory/gctransform/transform.py b/pypy/rpython/memory/gctransform/transform.py
--- a/pypy/rpython/memory/gctransform/transform.py
+++ b/pypy/rpython/memory/gctransform/transform.py
@@ -263,9 +263,7 @@
# still be empty (but let's check)
if starts_with_empty_block(graph) and inserted_empty_startblock:
old_startblock = graph.startblock
- graph.startblock.isstartblock = False
graph.startblock = graph.startblock.exits[0].target
- graph.startblock.isstartblock = True
checkgraph(graph)
diff --git a/pypy/rpython/normalizecalls.py b/pypy/rpython/normalizecalls.py
--- a/pypy/rpython/normalizecalls.py
+++ b/pypy/rpython/normalizecalls.py
@@ -116,8 +116,6 @@
v = Constant(default)
outlist.append(v)
newblock.closeblock(Link(outlist, oldblock))
- oldblock.isstartblock = False
- newblock.isstartblock = True
graph.startblock = newblock
for i in range(len(newdefaults)-1,-1,-1):
if newdefaults[i] is NODEFAULT:
@@ -171,8 +169,6 @@
# prepare the output args of newblock and link
outlist = inlist[:]
newblock.closeblock(Link(outlist, oldblock))
- oldblock.isstartblock = False
- newblock.isstartblock = True
graph.startblock = newblock
# finished
checkgraph(graph)
diff --git a/pypy/tool/nullpath.py b/pypy/tool/nullpath.py
--- a/pypy/tool/nullpath.py
+++ b/pypy/tool/nullpath.py
@@ -1,4 +1,4 @@
-import py
+import py, os
class NullPyPathLocal(py.path.local):
@@ -6,7 +6,7 @@
return self.__class__(py.path.local.join(self, *args))
def open(self, mode):
- return open('/dev/null', mode)
+ return open(os.devnull, mode)
def __repr__(self):
return py.path.local.__repr__(self) + ' [fake]'
diff --git a/pypy/tool/test/test_nullpath.py b/pypy/tool/test/test_nullpath.py
--- a/pypy/tool/test/test_nullpath.py
+++ b/pypy/tool/test/test_nullpath.py
@@ -1,11 +1,7 @@
-import sys
+import sys, os
import py
from pypy.tool.nullpath import NullPyPathLocal
-def setup_module():
- if 'posix' not in sys.builtin_module_names:
- py.test.skip('posix only')
-
def test_nullpath(tmpdir):
path = NullPyPathLocal(tmpdir)
assert repr(path).endswith('[fake]')
@@ -13,4 +9,4 @@
assert isinstance(foo_txt, NullPyPathLocal)
#
f = foo_txt.open('w')
- assert f.name == '/dev/null'
+ assert f.name == os.devnull
diff --git a/pypy/translator/backendopt/constfold.py b/pypy/translator/backendopt/constfold.py
--- a/pypy/translator/backendopt/constfold.py
+++ b/pypy/translator/backendopt/constfold.py
@@ -37,8 +37,9 @@
except (KeyboardInterrupt, SystemExit):
raise
except Exception, e:
- log.WARNING('constant-folding %r:' % (spaceop,))
- log.WARNING(' %s: %s' % (e.__class__.__name__, e))
+ pass # turn off reporting these as warnings: useless
+ #log.WARNING('constant-folding %r:' % (spaceop,))
+ #log.WARNING(' %s: %s' % (e.__class__.__name__, e))
else:
# success in folding this space operation
if spaceop.opname in fixup_op_result:
diff --git a/pypy/translator/backendopt/inline.py b/pypy/translator/backendopt/inline.py
--- a/pypy/translator/backendopt/inline.py
+++ b/pypy/translator/backendopt/inline.py
@@ -453,7 +453,6 @@
#vars that need to be passed through the blocks of the inlined function
linktoinlined = splitlink
copiedstartblock = self.copy_block(self.graph_to_inline.startblock)
- copiedstartblock.isstartblock = False
#find args passed to startblock of inlined function
passon_args = []
for arg in self.op.args[1:]:
diff --git a/pypy/translator/backendopt/mallocv.py b/pypy/translator/backendopt/mallocv.py
--- a/pypy/translator/backendopt/mallocv.py
+++ b/pypy/translator/backendopt/mallocv.py
@@ -391,7 +391,6 @@
virtualframe = VirtualFrame(graph2.startblock, 0, nodelist)
graphbuilder = GraphBuilder(self, graph2)
specblock = graphbuilder.start_from_virtualframe(virtualframe)
- specblock.isstartblock = True
specgraph = graph2
specgraph.name += '_mallocv'
specgraph.startblock = specblock
diff --git a/pypy/translator/backendopt/test/test_malloc.py b/pypy/translator/backendopt/test/test_malloc.py
--- a/pypy/translator/backendopt/test/test_malloc.py
+++ b/pypy/translator/backendopt/test/test_malloc.py
@@ -50,7 +50,8 @@
# we do the loop ourselves instead of calling remove_simple_mallocs()
while True:
progress = remover.remove_mallocs_once(graph)
- simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks()))
+ simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks()),
+ [graph])
if progress and option.view:
t.view()
if expected_result is not Ellipsis:
diff --git a/pypy/translator/c/test/test_refcount.py b/pypy/translator/c/test/test_refcount.py
--- a/pypy/translator/c/test/test_refcount.py
+++ b/pypy/translator/c/test/test_refcount.py
@@ -229,7 +229,6 @@
graph = t.buildflowgraph(g)
assert graph.startblock.operations == []
graph.startblock = graph.startblock.exits[0].target
- graph.startblock.isstartblock = True
from pypy.objspace.flow.model import checkgraph
checkgraph(graph)
t._prebuilt_graphs[g] = graph
diff --git a/pypy/translator/simplify.py b/pypy/translator/simplify.py
--- a/pypy/translator/simplify.py
+++ b/pypy/translator/simplify.py
@@ -397,7 +397,8 @@
def transform_dead_op_vars(graph, translator=None):
"""Remove dead operations and variables that are passed over a link
but not used in the target block. Input is a graph."""
- return transform_dead_op_vars_in_blocks(list(graph.iterblocks()), translator)
+ return transform_dead_op_vars_in_blocks(list(graph.iterblocks()),
+ [graph], translator)
# the set of operations that can safely be removed
# (they have no side effects, at least in R-Python)
@@ -419,11 +420,19 @@
hasattr: True,
}
-def transform_dead_op_vars_in_blocks(blocks, translator=None):
+def find_start_blocks(graphs):
+ start_blocks = set()
+ for graph in graphs:
+ start_blocks.add(graph.startblock)
+ return start_blocks
+
+def transform_dead_op_vars_in_blocks(blocks, graphs, translator=None):
"""Remove dead operations and variables that are passed over a link
but not used in the target block. Input is a set of blocks"""
read_vars = {} # set of variables really used
variable_flow = {} # map {Var: list-of-Vars-it-depends-on}
+ set_of_blocks = set(blocks)
+ start_blocks = find_start_blocks(graphs)
def canremove(op, block):
if op.opname not in CanRemove:
@@ -451,7 +460,7 @@
if block.exits:
for link in block.exits:
- if link.target not in blocks:
+ if link.target not in set_of_blocks:
for arg, targetarg in zip(link.args, link.target.inputargs):
read_vars[arg] = True
read_vars[targetarg] = True
@@ -465,7 +474,7 @@
read_vars[arg] = True
# an input block's inputargs should not be modified, even if some
# of the function's input arguments are not actually used
- if block.isstartblock:
+ if block in start_blocks:
for arg in block.inputargs:
read_vars[arg] = True
diff --git a/pypy/translator/transform.py b/pypy/translator/transform.py
--- a/pypy/translator/transform.py
+++ b/pypy/translator/transform.py
@@ -115,7 +115,7 @@
# to kill dead (never-followed) links,
# which can possibly remove more variables.
from pypy.translator.simplify import transform_dead_op_vars_in_blocks
- transform_dead_op_vars_in_blocks(block_subset)
+ transform_dead_op_vars_in_blocks(block_subset, self.translator.graphs)
def transform_dead_code(self, block_subset):
"""Remove dead code: these are the blocks that are not annotated at all
diff --git a/pypy/translator/unsimplify.py b/pypy/translator/unsimplify.py
--- a/pypy/translator/unsimplify.py
+++ b/pypy/translator/unsimplify.py
@@ -42,9 +42,7 @@
vars = [copyvar(annotator, v) for v in graph.startblock.inputargs]
newblock = Block(vars)
newblock.closeblock(Link(vars, graph.startblock))
- graph.startblock.isstartblock = False
graph.startblock = newblock
- graph.startblock.isstartblock = True
def starts_with_empty_block(graph):
return (not graph.startblock.operations
@@ -151,9 +149,7 @@
newop = SpaceOperation('direct_call', [c_initial_func], v_none)
extrablock.operations = [newop]
extrablock.closeblock(Link(args, entry_point.startblock))
- entry_point.startblock.isstartblock = False
entry_point.startblock = extrablock
- entry_point.startblock.isstartblock = True
checkgraph(entry_point)
def call_final_function(translator, final_func, annhelper=None):
More information about the pypy-commit
mailing list