Author: Philip Jenvey <pjen...@underboss.org> Branch: py3k Changeset: r67186:7cd5f50e628b Date: 2013-10-07 12:18 -0700 http://bitbucket.org/pypy/pypy/changeset/7cd5f50e628b/
Log: merge default diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -363,9 +363,11 @@ pass -def connect(database, **kwargs): - factory = kwargs.get("factory", Connection) - return factory(database, **kwargs) +def connect(database, timeout=5.0, detect_types=0, isolation_level="", + check_same_thread=True, factory=None, cached_statements=100): + factory = Connection if not factory else factory + return factory(database, timeout, detect_types, isolation_level, + check_same_thread, factory, cached_statements) def _unicode_text_factory(x): diff --git a/lib_pypy/_tkinter/tclobj.py b/lib_pypy/_tkinter/tclobj.py --- a/lib_pypy/_tkinter/tclobj.py +++ b/lib_pypy/_tkinter/tclobj.py @@ -22,9 +22,11 @@ return result elif value.typePtr == typeCache.BooleanType: - return result + return bool(value.internalRep.longValue) elif value.typePtr == typeCache.ByteArrayType: - return result + size = tkffi.new('int*') + data = tklib.Tcl_GetByteArrayFromObj(value, size) + return tkffi.buffer(data, size[0])[:] elif value.typePtr == typeCache.DoubleType: return value.internalRep.doubleValue elif value.typePtr == typeCache.IntType: @@ -44,7 +46,7 @@ result.append(FromObj(app, tcl_elem[0])) return tuple(result) elif value.typePtr == typeCache.ProcBodyType: - return result + pass # fall through and return tcl object. elif value.typePtr == typeCache.StringType: buf = tklib.Tcl_GetUnicode(value) length = tklib.Tcl_GetCharLength(value) diff --git a/lib_pypy/_tkinter/tklib.py b/lib_pypy/_tkinter/tklib.py --- a/lib_pypy/_tkinter/tklib.py +++ b/lib_pypy/_tkinter/tklib.py @@ -72,6 +72,7 @@ int Tcl_GetBoolean(Tcl_Interp* interp, const char* src, int* boolPtr); char *Tcl_GetString(Tcl_Obj* objPtr); char *Tcl_GetStringFromObj(Tcl_Obj* objPtr, int* lengthPtr); +unsigned char *Tcl_GetByteArrayFromObj(Tcl_Obj* objPtr, int* lengthPtr); Tcl_UniChar *Tcl_GetUnicode(Tcl_Obj* objPtr); int Tcl_GetCharLength(Tcl_Obj* objPtr); diff --git a/pypy/doc/arm.rst b/pypy/doc/arm.rst --- a/pypy/doc/arm.rst +++ b/pypy/doc/arm.rst @@ -35,6 +35,11 @@ * ``qemu-system`` * ``qemu-user-static`` +- The dependencies above are in addition to the ones needed for a regular + translation, `listed here`_. + +.. _`listed here`: getting-started-python.html#translating-the-pypy-python-interpreter + Creating a Qemu based ARM chroot -------------------------------- diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -107,9 +107,15 @@ for i in range(min(len(varnames), self.getfastscopelength())): name = varnames[i] w_value = fastscope_w[i] + w_name = self.space.wrap(name.decode('utf-8')) if w_value is not None: - w_name = self.space.wrap(name.decode('utf-8')) self.space.setitem(self.w_locals, w_name, w_value) + else: + try: + self.space.delitem(self.w_locals, w_name) + except OperationError as e: + if not e.match(self.space, self.space.w_KeyError): + raise def locals2fast(self): # Copy values from self.w_locals to the fastlocals diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py --- a/pypy/interpreter/test/test_app_main.py +++ b/pypy/interpreter/test/test_app_main.py @@ -1073,6 +1073,8 @@ sys.path.append(self.goal_dir) # make sure cwd does not contain a stdlib + if self.tmp_dir.startswith(self.trunkdir): + skip('TMPDIR is inside the PyPy source') os.chdir(self.tmp_dir) tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c') try: diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -129,10 +129,21 @@ def test_locals(self): def f(): return locals() + def g(c=0, b=0, a=0): return locals() + assert f() == {} - assert g() == {'a':0, 'b':0, 'c':0} + assert g() == {'a': 0, 'b': 0, 'c': 0} + + def test_locals_deleted_local(self): + def f(): + a = 3 + locals() + del a + return locals() + + assert f() == {} def test_dir(self): def f(): @@ -298,22 +309,6 @@ assert next(x) == 3 def test_range_args(self): -## # range() attributes are deprecated and were removed in Python 2.3. -## x = range(2) -## assert x.start == 0 -## assert x.stop == 2 -## assert x.step == 1 - -## x = range(2,10,2) -## assert x.start == 2 -## assert x.stop == 10 -## assert x.step == 2 - -## x = range(2.3, 10.5, 2.4) -## assert x.start == 2 -## assert x.stop == 10 -## assert x.step == 2 - raises(ValueError, range, 0, 1, 0) def test_range_repr(self): @@ -374,7 +369,7 @@ raises(TypeError, range, 1, 3+2j) raises(TypeError, range, 1, 2, '1') raises(TypeError, range, 1, 2, 3+2j) - + def test_sorted(self): l = [] sorted_l = sorted(l) @@ -393,7 +388,7 @@ assert sorted_l is not l assert sorted_l == ['C', 'b', 'a'] raises(TypeError, sorted, [], reverse=None) - + def test_reversed_simple_sequences(self): l = range(5) rev = reversed(l) @@ -409,7 +404,7 @@ return 42 obj = SomeClass() assert reversed(obj) == 42 - + def test_return_None(self): class X(object): pass x = X() @@ -465,7 +460,7 @@ assert eval("1+2") == 3 assert eval(" \t1+2\n") == 3 assert eval("len([])") == 0 - assert eval("len([])", {}) == 0 + assert eval("len([])", {}) == 0 # cpython 2.4 allows this (raises in 2.3) assert eval("3", None, None) == 3 i = 4 diff --git a/pypy/module/cpyext/ndarrayobject.py b/pypy/module/cpyext/ndarrayobject.py --- a/pypy/module/cpyext/ndarrayobject.py +++ b/pypy/module/cpyext/ndarrayobject.py @@ -149,14 +149,17 @@ only used if the array is constructed that way. Almost always this parameter is NULL. """ - if min_depth !=0 or max_depth != 0: - raise OperationError(space.w_NotImplementedError, space.wrap( - '_PyArray_FromAny called with not-implemented min_dpeth or max_depth argument')) if requirements not in (0, NPY_DEFAULT): raise OperationError(space.w_NotImplementedError, space.wrap( '_PyArray_FromAny called with not-implemented requirements argument')) w_array = array(space, w_obj, w_dtype=w_dtype, copy=False) - if w_array.is_scalar(): + if min_depth !=0 and len(w_array.get_shape()) < min_depth: + raise OperationError(space.w_ValueError, space.wrap( + 'object of too small depth for desired array')) + elif max_depth !=0 and len(w_array.get_shape()) > max_depth: + raise OperationError(space.w_ValueError, space.wrap( + 'object of too deep for desired array')) + elif w_array.is_scalar(): # since PyArray_DATA() fails on scalars, create a 1D array and set empty # shape. So the following combination works for *reading* scalars: # PyObject *arr = PyArray_FromAny(obj); diff --git a/pypy/module/cpyext/test/test_ndarrayobject.py b/pypy/module/cpyext/test/test_ndarrayobject.py --- a/pypy/module/cpyext/test/test_ndarrayobject.py +++ b/pypy/module/cpyext/test/test_ndarrayobject.py @@ -90,15 +90,16 @@ def test_FromAny(self, space, api): a = array(space, [10, 5, 3]) assert api._PyArray_FromAny(a, NULL, 0, 0, 0, NULL) is a - self.raises(space, api, NotImplementedError, api._PyArray_FromAny, - a, NULL, 0, 3, 0, NULL) + assert api._PyArray_FromAny(a, NULL, 1, 4, 0, NULL) is a + self.raises(space, api, ValueError, api._PyArray_FromAny, + a, NULL, 4, 5, 0, NULL) def test_FromObject(self, space, api): a = array(space, [10, 5, 3]) assert api._PyArray_FromObject(a, a.get_dtype().num, 0, 0) is a - exc = self.raises(space, api, NotImplementedError, api._PyArray_FromObject, - a, 11, 0, 3) - assert exc.errorstr(space).find('FromObject') >= 0 + exc = self.raises(space, api, ValueError, api._PyArray_FromObject, + a, 11, 4, 5) + assert exc.errorstr(space).find('desired') >= 0 def test_list_from_fixedptr(self, space, api): A = lltype.GcArray(lltype.Float) diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py --- a/pypy/module/math/interp_math.py +++ b/pypy/module/math/interp_math.py @@ -350,9 +350,8 @@ v = hi del partials[added:] if v != 0.0: - if rfloat.isinf(v) or rfloat.isnan(v): - if (not rfloat.isinf(original) and - not rfloat.isnan(original)): + if not rfloat.isfinite(v): + if rfloat.isfinite(original): raise OperationError(space.w_OverflowError, space.wrap("intermediate overflow")) if rfloat.isinf(original): 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 @@ -2966,6 +2966,12 @@ assert len(list(a[0])) == 2 + def test_issue_1589(self): + import numpypy as numpy + c = numpy.array([[(1, 2, 'a'), (3, 4, 'b')], [(5, 6, 'c'), (7, 8, 'd')]], + dtype=[('bg', 'i8'), ('fg', 'i8'), ('char', 'S1')]) + assert c[0][0]["char"] == 'a' + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): if option.runappdirect and '__pypy__' not in sys.builtin_module_names: diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1766,14 +1766,14 @@ def store(self, arr, i, offset, box): assert isinstance(box, interp_boxes.W_StringBox) - # XXX simplify to range(box.dtype.get_size()) ? return self._store(arr.storage, i, offset, box) @jit.unroll_safe def _store(self, storage, i, offset, box): assert isinstance(box, interp_boxes.W_StringBox) - for k in range(min(self.size, box.arr.size-offset)): - storage[k + i] = box.arr.storage[k + offset] + # XXX simplify to range(box.dtype.get_size()) ? + for k in range(min(self.size, box.arr.size-box.ofs)): + storage[k + offset + i] = box.arr.storage[k + box.ofs] def read(self, arr, i, offset, dtype=None): if dtype is None: diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -277,3 +277,28 @@ f1 = call_release_gil(..., descr=<Calli 4 ii EF=6 OS=62>) ... """) + + def test__cffi_bug1(self): + from rpython.rlib.test.test_clibffi import get_libm_name + def main(libm_name): + try: + import _cffi_backend + except ImportError: + sys.stderr.write('SKIP: cannot import _cffi_backend\n') + return 0 + + libm = _cffi_backend.load_library(libm_name) + BDouble = _cffi_backend.new_primitive_type("double") + BSin = _cffi_backend.new_function_type([BDouble], BDouble) + sin = libm.load_function(BSin, 'sin') + + def f(*args): + for i in range(300): + sin(*args) + + f(1.0) + f(1) + # + libm_name = get_libm_name(sys.platform) + log = self.run(main, [libm_name]) + # assert did not crash diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -113,7 +113,7 @@ i13 = strgetitem(p9, 0) i15 = int_eq(i13, 45) guard_false(i15, descr=...) - i17 = int_sub(0, i10) + i17 = int_neg(i10) i19 = int_gt(i10, 23) guard_false(i19, descr=...) p21 = newstr(23) diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py b/pypy/module/pypyjit/test_pypy_c/test_thread.py --- a/pypy/module/pypyjit/test_pypy_c/test_thread.py +++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py @@ -1,4 +1,3 @@ -import py from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC @@ -51,7 +50,6 @@ """) def test_lock_acquire_release(self): - py.test.skip("test too precise, please fix me") def main(n): import threading lock = threading.Lock() @@ -62,35 +60,30 @@ assert log.result == main(500) loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i58 = int_gt(i43, 0) - guard_true(i58, descr=<Guard0x10483adb8>) - p59 = getfield_gc(p15, descr=<FieldP pypy.module.thread.os_lock.Lock.inst_lock 8>) - i60 = getfield_gc(p59, descr=<FieldU rpython.rlib.rthread.Lock.inst__lock 8>) + i55 = int_gt(i43, 0) + guard_true(i55, descr=...) + p56 = force_token() + setfield_gc(p0, p56, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .*>) + i57 = call_release_gil(..., i36, 1, descr=<Calli 4 ii EF=6>) + guard_not_forced(descr=...) + guard_no_exception(descr=...) + i58 = int_is_true(i57) + guard_true(i58, descr=...) + i59 = int_sub(i43, 1) + guard_not_invalidated(descr=...) p61 = force_token() - setfield_gc(p0, p61, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token 24>) - i62 = call_release_gil(4312440032, i60, 1, descr=<Calli 4 ii EF=6>) - guard_not_forced(descr=<Guard0x103f3cca0>) - guard_no_exception(descr=<Guard0x10483ad40>) + setfield_gc(p0, p61, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .*>) + i62 = call_release_gil(..., i36, 0, descr=<Calli 4 ii EF=6>) + guard_not_forced(descr=...) + guard_no_exception(descr=...) i63 = int_is_true(i62) - guard_true(i63, descr=<Guard0x10483acc8>) - i64 = int_sub(i43, 1) - guard_not_invalidated(descr=<Guard0x10483ac50>) - p66 = getfield_gc(p15, descr=<FieldP pypy.module.thread.os_lock.Lock.inst_lock 8>) - i67 = getfield_gc(p66, descr=<FieldU rpython.rlib.rthread.Lock.inst__lock 8>) - p68 = force_token() - setfield_gc(p0, p68, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token 24>) - i69 = call_release_gil(4312440032, i67, 0, descr=<Calli 4 ii EF=6>) - guard_not_forced(descr=<Guard0x103f3cc20>) - guard_no_exception(descr=<Guard0x10483aae8>) - i70 = int_is_true(i69) - guard_false(i70, descr=<Guard0x10483aa70>) - i71 = getfield_gc(p66, descr=<FieldU rpython.rlib.rthread.Lock.inst__lock 8>) - p72 = force_token() - setfield_gc(p0, p72, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token 24>) - call_release_gil(4312441056, i71, descr=<Callv 0 i EF=6>) - guard_not_forced(descr=<Guard0x103f3cba0>) - guard_no_exception(descr=<Guard0x10483a9f8>) - guard_not_invalidated(descr=<Guard0x10483a980>) + guard_false(i63, descr=...) + p64 = force_token() + setfield_gc(p0, p64, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .*>) + call_release_gil(..., i36, descr=<Callv 0 i EF=6>) + guard_not_forced(descr=...) + guard_no_exception(descr=...) + guard_not_invalidated(descr=...) --TICK-- - jump(..., descr=TargetToken(4361239720)) + jump(..., descr=...) """) diff --git a/pypy/module/test_lib_pypy/test_sqlite3.py b/pypy/module/test_lib_pypy/test_sqlite3.py --- a/pypy/module/test_lib_pypy/test_sqlite3.py +++ b/pypy/module/test_lib_pypy/test_sqlite3.py @@ -31,6 +31,12 @@ result = list(cursor) assert result == [(42,)] +def test_connect_takes_same_positional_args_as_Connection(con): + from inspect import getargspec + clsargs = getargspec(_sqlite3.Connection.__init__).args[1:] # ignore self + conargs = getargspec(_sqlite3.connect).args + assert clsargs == conargs + def test_total_changes_after_close(con): con.close() pytest.raises(_sqlite3.ProgrammingError, "con.total_changes") diff --git a/pypy/module/thread/os_lock.py b/pypy/module/thread/os_lock.py --- a/pypy/module/thread/os_lock.py +++ b/pypy/module/thread/os_lock.py @@ -75,6 +75,8 @@ class Lock(W_Root): "A wrappable box around an interp-level lock object." + _immutable_fields_ = ["lock"] + def __init__(self, space): self.space = space try: diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -398,21 +398,24 @@ x = w_float1.floatval y = w_float2.floatval + return W_FloatObject(_pow(space, x, y)) + +def _pow(space, x, y): # Sort out special cases here instead of relying on pow() - if y == 2.0: # special case for performance: - return W_FloatObject(x * x) # x * x is always correct + if y == 2.0: # special case for performance: + return x * x # x * x is always correct if y == 0.0: # x**0 is 1, even 0**0 - return W_FloatObject(1.0) + return 1.0 if isnan(x): # nan**y = nan, unless y == 0 - return W_FloatObject(x) + return x if isnan(y): # x**nan = nan, unless x == 1; x**nan = x if x == 1.0: - return W_FloatObject(1.0) + return 1.0 else: - return W_FloatObject(y) + return y if isinf(y): # x**inf is: 0.0 if abs(x) < 1; 1.0 if abs(x) == 1; inf if # abs(x) > 1 (including case where x infinite) @@ -421,11 +424,11 @@ # abs(x) > 1 (including case where v infinite) x = abs(x) if x == 1.0: - return W_FloatObject(1.0) + return 1.0 elif (y > 0.0) == (x > 1.0): - return W_FloatObject(INFINITY) + return INFINITY else: - return W_FloatObject(0.0) + return 0.0 if isinf(x): # (+-inf)**w is: inf for w positive, 0 for w negative; in oth # cases, we need to add the appropriate sign if w is an odd @@ -433,14 +436,14 @@ y_is_odd = math.fmod(abs(y), 2.0) == 1.0 if y > 0.0: if y_is_odd: - return W_FloatObject(x) + return x else: - return W_FloatObject(abs(x)) + return abs(x) else: if y_is_odd: - return W_FloatObject(copysign(0.0, x)) + return copysign(0.0, x) else: - return W_FloatObject(0.0) + return 0.0 if x == 0.0: if y < 0.0: @@ -454,7 +457,7 @@ # - pipermail/python-bugs-list/2003-March/016795.html if x < 0.0: if isnan(y): - return W_FloatObject(NAN) + return NAN if math.floor(y) != y: # Negative numbers raised to fractional powers become # complex @@ -470,9 +473,9 @@ if x == 1.0: # (-1) ** large_integer also ends up here if negate_result: - return W_FloatObject(-1.0) + return -1.0 else: - return W_FloatObject(1.0) + return 1.0 try: # We delegate to our implementation of math.pow() the error detection. @@ -486,7 +489,7 @@ if negate_result: z = -z - return W_FloatObject(z) + return z def neg__Float(space, w_float1): diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -194,10 +194,10 @@ W_AbstractTupleObject.typedef = StdTypeDef( "tuple", - __doc__ = '''tuple() -> an empty tuple + __doc__ = """tuple() -> an empty tuple tuple(sequence) -> tuple initialized from sequence's items -If the argument is a tuple, the return value is the same object.''', +If the argument is a tuple, the return value is the same object.""", __new__ = interp2app(W_AbstractTupleObject.descr_new), __repr__ = interp2app(W_AbstractTupleObject.descr_repr), __hash__ = interpindirect2app(W_AbstractTupleObject.descr_hash), diff --git a/pypy/pytest-A.py b/pypy/pytest-A.py --- a/pypy/pytest-A.py +++ b/pypy/pytest-A.py @@ -5,7 +5,6 @@ 'arm': ['interpreter/astcompiler/test', 'interpreter/pyparser/test', 'interpreter/test', - 'interpreter/test2', 'module/test_lib_pypy', 'objspace/std/test', ], diff --git a/rpython/flowspace/test/test_objspace.py b/rpython/flowspace/test/test_objspace.py --- a/rpython/flowspace/test/test_objspace.py +++ b/rpython/flowspace/test/test_objspace.py @@ -1063,7 +1063,6 @@ assert len(graph.startblock.exits) == 1 assert graph.startblock.exits[0].target == graph.returnblock - def test_global_variable(self): def global_var_missing(): return a diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py --- a/rpython/jit/backend/llgraph/runner.py +++ b/rpython/jit/backend/llgraph/runner.py @@ -381,6 +381,8 @@ res = self.llinterp.eval_graph(ptr._obj.graph, args) else: res = ptr._obj._callable(*args) + if RESULT is lltype.Void: + return None return support.cast_result(RESULT, res) def _do_call(self, func, args_i, args_r, args_f, calldescr): diff --git a/rpython/jit/metainterp/heapcache.py b/rpython/jit/metainterp/heapcache.py --- a/rpython/jit/metainterp/heapcache.py +++ b/rpython/jit/metainterp/heapcache.py @@ -87,9 +87,11 @@ def _escape(self, box): if box in self.new_boxes: self.new_boxes[box] = False - if box in self.dependencies: - deps = self.dependencies[box] - del self.dependencies[box] + try: + deps = self.dependencies.pop(box) + except KeyError: + pass + else: for dep in deps: self._escape(dep) @@ -117,15 +119,18 @@ # effects are so well defined. elif effectinfo.oopspecindex == effectinfo.OS_ARRAYCOPY: # The destination box - if argboxes[2] in self.new_boxes: - # XXX: no descr here so we invalidate any of them, not just - # of the correct type - # XXX: in theory the indices of the copy could be looked at - # as well - for descr, cache in self.heap_array_cache.iteritems(): + if ( + argboxes[2] in self.new_boxes and + len(effectinfo.write_descrs_arrays) == 1 + ): + # Fish the descr out of the effectinfo + cache = self.heap_array_cache.get(effectinfo.write_descrs_arrays[0], None) + if cache is not None: + # XXX: in theory the indices of the copy could be + # looked at for idx, cache in cache.iteritems(): for frombox in cache.keys(): - if not self.new_boxes.get(frombox, False): + if not self.is_unescaped(frombox): del cache[frombox] return else: diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -107,6 +107,11 @@ v2 = self.getvalue(op.getarg(1)) if v2.is_constant() and v2.box.getint() == 0: self.make_equal_to(op.result, v1) + elif v1.is_constant() and v1.box.getint() == 0: + op = op.copy_and_change(rop.INT_NEG, args=[v2.box]) + self.emit_operation(op) + elif v1 is v2: + self.make_constant_int(op.result, 0) else: self.emit_operation(op) # Synthesize the reverse ops for optimize_default to reuse @@ -166,6 +171,8 @@ if v2.is_constant() and v2.box.getint() == 0: self.make_equal_to(op.result, v1) + elif v1.is_constant() and v1.box.getint() == 0: + self.make_constant_int(op.result, 0) else: self.emit_operation(op) @@ -175,6 +182,8 @@ if v2.is_constant() and v2.box.getint() == 0: self.make_equal_to(op.result, v1) + elif v1.is_constant() and v1.box.getint() == 0: + self.make_constant_int(op.result, 0) else: self.emit_operation(op) diff --git a/rpython/jit/metainterp/optimizeopt/simplify.py b/rpython/jit/metainterp/optimizeopt/simplify.py --- a/rpython/jit/metainterp/optimizeopt/simplify.py +++ b/rpython/jit/metainterp/optimizeopt/simplify.py @@ -45,7 +45,7 @@ return self.optimize_JUMP(op.copy_and_change(rop.JUMP)) self.last_label_descr = op.getdescr() self.emit_operation(op) - + def optimize_JUMP(self, op): if not self.unroll: descr = op.getdescr() 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 @@ -3735,6 +3735,33 @@ """ self.optimize_loop(ops, expected) + def test_sub_identity(self): + ops = """ + [i0] + i1 = int_sub(i0, i0) + i2 = int_sub(i1, i0) + jump(i1, i2) + """ + expected = """ + [i0] + i2 = int_neg(i0) + jump(0, i2) + """ + self.optimize_loop(ops, expected) + + def test_shift_zero(self): + ops = """ + [i0] + i1 = int_lshift(0, i0) + i2 = int_rshift(0, i0) + jump(i1, i2) + """ + expected = """ + [i0] + jump(0, 0) + """ + self.optimize_loop(ops, expected) + def test_bound_and(self): ops = """ [i0] diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -45,6 +45,15 @@ return value return OptValue(self.force_box(optforce)) + def get_args_for_fail(self, modifier): + # checks for recursion: it is False unless + # we have already seen the very same keybox + if self.box is None and not modifier.already_seen_virtual(self.keybox): + self._get_args_for_fail(modifier) + + def _get_args_for_fail(self, modifier): + raise NotImplementedError("abstract base") + def make_virtual_info(self, modifier, fieldnums): if fieldnums is None: return self._make_virtual(modifier) @@ -193,16 +202,13 @@ self._cached_sorted_fields = lst return lst - def get_args_for_fail(self, modifier): - if self.box is None and not modifier.already_seen_virtual(self.keybox): - # checks for recursion: it is False unless - # we have already seen the very same keybox - lst = self._get_field_descr_list() - fieldboxes = [self._fields[ofs].get_key_box() for ofs in lst] - modifier.register_virtual_fields(self.keybox, fieldboxes) - for ofs in lst: - fieldvalue = self._fields[ofs] - fieldvalue.get_args_for_fail(modifier) + def _get_args_for_fail(self, modifier): + lst = self._get_field_descr_list() + fieldboxes = [self._fields[ofs].get_key_box() for ofs in lst] + modifier.register_virtual_fields(self.keybox, fieldboxes) + for ofs in lst: + fieldvalue = self._fields[ofs] + fieldvalue.get_args_for_fail(modifier) class VirtualValue(AbstractVirtualStructValue): level = optimizer.LEVEL_KNOWNCLASS @@ -254,18 +260,15 @@ def set_item_value(self, i, newval): raise NotImplementedError - def get_args_for_fail(self, modifier): - if self.box is None and not modifier.already_seen_virtual(self.keybox): - # checks for recursion: it is False unless - # we have already seen the very same keybox - itemboxes = [] - for i in range(self.getlength()): - itemvalue = self.get_item_value(i) - itemboxes.append(itemvalue.get_key_box()) - modifier.register_virtual_fields(self.keybox, itemboxes) - for i in range(self.getlength()): - itemvalue = self.get_item_value(i) - itemvalue.get_args_for_fail(modifier) + def _get_args_for_fail(self, modifier): + itemboxes = [] + for i in range(self.getlength()): + itemvalue = self.get_item_value(i) + itemboxes.append(itemvalue.get_key_box()) + modifier.register_virtual_fields(self.keybox, itemboxes) + for i in range(self.getlength()): + itemvalue = self.get_item_value(i) + itemvalue.get_args_for_fail(modifier) class VArrayValue(AbstractVArrayValue): @@ -370,17 +373,16 @@ descrs.append(item_descrs) return descrs - def get_args_for_fail(self, modifier): - if self.box is None and not modifier.already_seen_virtual(self.keybox): - itemdescrs = self._get_list_of_descrs() - itemboxes = [] - for i in range(len(self._items)): - for descr in itemdescrs[i]: - itemboxes.append(self._items[i][descr].get_key_box()) - modifier.register_virtual_fields(self.keybox, itemboxes) - for i in range(len(self._items)): - for descr in itemdescrs[i]: - self._items[i][descr].get_args_for_fail(modifier) + def _get_args_for_fail(self, modifier): + itemdescrs = self._get_list_of_descrs() + itemboxes = [] + for i in range(len(self._items)): + for descr in itemdescrs[i]: + itemboxes.append(self._items[i][descr].get_key_box()) + modifier.register_virtual_fields(self.keybox, itemboxes) + for i in range(len(self._items)): + for descr in itemdescrs[i]: + self._items[i][descr].get_args_for_fail(modifier) def force_at_end_of_preamble(self, already_forced, optforce): if self in already_forced: @@ -481,6 +483,15 @@ def getitem_raw(self, offset, length, descr): return self.rawbuffer_value.getitem_raw(self.offset+offset, length, descr) + def _get_args_for_fail(self, modifier): + box = self.rawbuffer_value.get_key_box() + modifier.register_virtual_fields(self.keybox, [box]) + self.rawbuffer_value.get_args_for_fail(modifier) + + def _make_virtual(self, modifier): + return modifier.make_vrawslice(self.offset) + + class OptVirtualize(optimizer.Optimization): "Virtualize objects until they escape." diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -284,7 +284,10 @@ return VArrayStructInfo(arraydescr, fielddescrs) def make_vrawbuffer(self, size, offsets, descrs): - return VRawBufferStateInfo(size, offsets, descrs) + return VRawBufferInfo(size, offsets, descrs) + + def make_vrawslice(self, offset): + return VRawSliceInfo(offset) def make_vstrplain(self, is_unicode=False): if is_unicode: @@ -554,10 +557,13 @@ debug_print("\t\t", str(untag(i))) -class VRawBufferStateInfo(AbstractVirtualInfo): +class VAbstractRawInfo(AbstractVirtualInfo): kind = INT is_about_raw = True + +class VRawBufferInfo(VAbstractRawInfo): + def __init__(self, size, offsets, descrs): self.size = size self.offsets = offsets @@ -580,6 +586,25 @@ debug_print("\t\t", str(untag(i))) +class VRawSliceInfo(VAbstractRawInfo): + + def __init__(self, offset): + self.offset = offset + + @specialize.argtype(1) + def allocate_int(self, decoder, index): + assert len(self.fieldnums) == 1 + base_buffer = decoder.decode_int(self.fieldnums[0]) + buffer = decoder.int_add_const(base_buffer, self.offset) + decoder.virtuals_cache.set_int(index, buffer) + return buffer + + def debug_prints(self): + debug_print("\tvrawsliceinfo", " at ", compute_unique_id(self)) + for i in self.fieldnums: + debug_print("\t\t", str(untag(i))) + + class VArrayStructInfo(AbstractVirtualInfo): def __init__(self, arraydescr, fielddescrs): self.arraydescr = arraydescr @@ -783,7 +808,8 @@ v = self.virtuals_cache.get_int(index) if not v: v = self.rd_virtuals[index] - assert v.is_about_raw and isinstance(v, VRawBufferStateInfo) + ll_assert(bool(v), "resume.py: null rd_virtuals[index]") + assert v.is_about_raw and isinstance(v, VAbstractRawInfo) v = v.allocate_int(self, index) ll_assert(v == self.virtuals_cache.get_int(index), "resume.py: bad cache") return v @@ -1116,6 +1142,10 @@ def write_a_float(self, index, box): self.boxes_f[index] = box + def int_add_const(self, intbox, offset): + return self.metainterp.execute_and_record(rop.INT_ADD, None, intbox, + ConstInt(offset)) + # ---------- when resuming for blackholing, get direct values ---------- def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage, @@ -1407,6 +1437,9 @@ def write_a_float(self, index, float): self.blackholeinterp.setarg_f(index, float) + def int_add_const(self, base, offset): + return base + offset + # ____________________________________________________________ def dump_storage(storage, liveboxes): diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py --- a/rpython/jit/metainterp/test/test_fficall.py +++ b/rpython/jit/metainterp/test/test_fficall.py @@ -86,15 +86,17 @@ data = rffi.ptradd(exchange_buffer, ofs) rffi.cast(lltype.Ptr(TYPE), data)[0] = write_rvalue - def f(): + def f(i): exbuf = lltype.malloc(rffi.CCHARP.TO, (len(avalues)+2) * 16, - flavor='raw', zero=True) - ofs = 16 + flavor='raw') + + targetptr = rffi.ptradd(exbuf, 16) for avalue in unroll_avalues: TYPE = rffi.CArray(lltype.typeOf(avalue)) - data = rffi.ptradd(exbuf, ofs) - rffi.cast(lltype.Ptr(TYPE), data)[0] = avalue - ofs += 16 + if i >= 9: # a guard that can fail + pass + rffi.cast(lltype.Ptr(TYPE), targetptr)[0] = avalue + targetptr = rffi.ptradd(targetptr, 16) jit_ffi_call(cif_description, func_addr, exbuf) @@ -102,8 +104,7 @@ res = 654321 else: TYPE = rffi.CArray(lltype.typeOf(rvalue)) - data = rffi.ptradd(exbuf, ofs) - res = rffi.cast(lltype.Ptr(TYPE), data)[0] + res = rffi.cast(lltype.Ptr(TYPE), targetptr)[0] lltype.free(exbuf, flavor='raw') if lltype.typeOf(res) is lltype.SingleFloat: res = float(res) @@ -117,9 +118,9 @@ return res == rvalue with FakeFFI(fake_call_impl_any): - res = f() + res = f(-42) assert matching_result(res, rvalue) - res = self.interp_operations(f, [], + res = self.interp_operations(f, [-42], supports_floats = supports_floats, supports_longlong = supports_longlong, supports_singlefloats = supports_singlefloats) @@ -132,6 +133,19 @@ self.check_operations_history(call_may_force=0, call_release_gil=expected_call_release_gil) + ################################################## + driver = jit.JitDriver(reds=['i'], greens=[]) + def main(): + i = 0 + while 1: + driver.jit_merge_point(i=i) + res = f(i) + i += 1 + if i == 12: + return res + self.meta_interp(main, []) + + def test_simple_call_int(self): self._run([types.signed] * 2, types.signed, [456, 789], -42) diff --git a/rpython/jit/metainterp/test/test_heapcache.py b/rpython/jit/metainterp/test/test_heapcache.py --- a/rpython/jit/metainterp/test/test_heapcache.py +++ b/rpython/jit/metainterp/test/test_heapcache.py @@ -29,17 +29,24 @@ OS_ARRAYCOPY = 0 - def __init__(self, extraeffect, oopspecindex): + def __init__(self, extraeffect, oopspecindex, write_descrs_arrays): self.extraeffect = extraeffect self.oopspecindex = oopspecindex + self.write_descrs_arrays = write_descrs_arrays + class FakeCallDescr(object): - def __init__(self, extraeffect, oopspecindex=None): + def __init__(self, extraeffect, oopspecindex=None, write_descrs_arrays=[]): self.extraeffect = extraeffect self.oopspecindex = oopspecindex + self.write_descrs_arrays = write_descrs_arrays def get_extra_info(self): - return FakeEffectinfo(self.extraeffect, self.oopspecindex) + return FakeEffectinfo( + self.extraeffect, self.oopspecindex, + write_descrs_arrays=self.write_descrs_arrays + ) + class TestHeapCache(object): def test_known_class_box(self): @@ -364,13 +371,13 @@ # Just need the destination box for this call h.invalidate_caches( rop.CALL, - FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY), + FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, None, box2, None, None] ) assert h.getarrayitem(box1, index1, descr1) is box2 h.invalidate_caches( rop.CALL, - FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY), + FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, None, box3, None, None] ) assert h.getarrayitem(box1, index1, descr1) is None @@ -379,11 +386,24 @@ assert h.getarrayitem(box4, index1, descr1) is box2 h.invalidate_caches( rop.CALL, - FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY), + FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, None, box2, None, None] ) assert h.getarrayitem(box4, index1, descr1) is None + def test_ll_arraycopy_differing_descrs(self): + h = HeapCache() + h.setarrayitem(box1, index1, box2, descr1) + assert h.getarrayitem(box1, index1, descr1) is box2 + h.new_array(box2, lengthbox2) + h.invalidate_caches( + rop.CALL, + FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr2]), + [None, None, box2, None, None] + ) + assert h.getarrayitem(box1, index1, descr1) is box2 + + def test_unescaped(self): h = HeapCache() assert not h.is_unescaped(box1) diff --git a/rpython/memory/support.py b/rpython/memory/support.py --- a/rpython/memory/support.py +++ b/rpython/memory/support.py @@ -121,13 +121,15 @@ cur = next free_non_gc_object(self) - def _length_estimate(self): + def length(self): chunk = self.chunk + result = 0 count = self.used_in_last_chunk while chunk: + result += count chunk = chunk.next - count += chunk_size - return count + count = chunk_size + return result def foreach(self, callback, arg): """Invoke 'callback(address, arg)' for all addresses in the stack. @@ -144,7 +146,7 @@ foreach._annspecialcase_ = 'specialize:arg(1)' def stack2dict(self): - result = AddressDict(self._length_estimate()) + result = AddressDict(self.length()) self.foreach(_add_in_dict, result) return result diff --git a/rpython/memory/test/test_support.py b/rpython/memory/test/test_support.py --- a/rpython/memory/test/test_support.py +++ b/rpython/memory/test/test_support.py @@ -94,6 +94,18 @@ assert a == addrs[i] assert not ll.non_empty() + def test_length(self): + AddressStack = get_address_stack(10) + ll = AddressStack() + a = raw_malloc(llmemory.sizeof(lltype.Signed)) + for i in range(42): + assert ll.length() == i + ll.append(a) + for i in range(42-1, -1, -1): + b = ll.pop() + assert b == a + assert ll.length() == i + class TestAddressDeque: def test_big_access(self): diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -728,10 +728,16 @@ if c.numdigits() == 1 and c._digits[0] == ONEDIGIT: return NULLRBIGINT - # if base < 0: - # base = base % modulus - # Having the base positive just makes things easier. - if a.sign < 0: + # Reduce base by modulus in some cases: + # 1. If base < 0. Forcing the base non-neg makes things easier. + # 2. If base is obviously larger than the modulus. The "small + # exponent" case later can multiply directly by base repeatedly, + # while the "large exponent" case multiplies directly by base 31 + # times. It can be unboundedly faster to multiply by + # base % modulus instead. + # We could _always_ do this reduction, but mod() isn't cheap, + # so we only do it when it buys something. + if a.sign < 0 or a.numdigits() > c.numdigits(): a = a.mod(c) elif b.sign == 0: diff --git a/rpython/rlib/rpath.py b/rpython/rlib/rpath.py --- a/rpython/rlib/rpath.py +++ b/rpython/rlib/rpath.py @@ -23,3 +23,103 @@ return path else: raise ImportError('Unsupported os: %s' % os.name) + + +def dirname(p): + """Returns the directory component of a pathname""" + i = p.rfind('/') + 1 + assert i >= 0 + head = p[:i] + if head and head != '/' * len(head): + head = head.rstrip('/') + return head + + +def basename(p): + """Returns the final component of a pathname""" + i = p.rfind('/') + 1 + assert i >= 0 + return p[i:] + + +def split(p): + """Split a pathname. Returns tuple "(head, tail)" where "tail" is + everything after the final slash. Either part may be empty.""" + i = p.rfind('/') + 1 + assert i >= 0 + head, tail = p[:i], p[i:] + if head and head != '/' * len(head): + head = head.rstrip('/') + return head, tail + + +def exists(path): + """Test whether a path exists. Returns False for broken symbolic links""" + try: + assert path is not None + os.stat(path) + except os.error: + return False + return True + + +import os +from os.path import isabs, islink, abspath, normpath + +def join(a, p): + """Join two or more pathname components, inserting '/' as needed. + If any component is an absolute path, all previous path components + will be discarded. An empty last part will result in a path that + ends with a separator.""" + path = a + for b in p: + if b.startswith('/'): + path = b + elif path == '' or path.endswith('/'): + path += b + else: + path += '/' + b + return path + +def realpath(filename): + """Return the canonical path of the specified filename, eliminating any +symbolic links encountered in the path.""" + if isabs(filename): + bits = ['/'] + filename.split('/')[1:] + else: + bits = [''] + filename.split('/') + + for i in range(2, len(bits)+1): + component = join(bits[0], bits[1:i]) + # Resolve symbolic links. + if islink(component): + resolved = _resolve_link(component) + if resolved is None: + # Infinite loop -- return original component + rest of the path + return abspath(join(component, bits[i:])) + else: + newpath = join(resolved, bits[i:]) + return realpath(newpath) + + return abspath(filename) + + +def _resolve_link(path): + """Internal helper function. Takes a path and follows symlinks + until we either arrive at something that isn't a symlink, or + encounter a path we've seen before (meaning that there's a loop). + """ + paths_seen = {} + while islink(path): + if path in paths_seen: + # Already seen this path, so we must have a symlink loop + return None + paths_seen[path] = None + # Resolve where the link points to + resolved = os.readlink(path) + if not isabs(resolved): + dir = dirname(path) + path = normpath(join(dir, [resolved])) + else: + path = normpath(resolved) + return path diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py --- a/rpython/rlib/rthread.py +++ b/rpython/rlib/rthread.py @@ -117,6 +117,8 @@ """ Container for low-level implementation of a lock object """ + _immutable_fields_ = ["_lock"] + def __init__(self, ll_lock): self._lock = ll_lock 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 @@ -1,5 +1,6 @@ import gc, sys import py +import platform from rpython.rtyper.tool.rffi_platform import CompilationError try: from rpython.rlib import rstacklet @@ -332,6 +333,10 @@ gc = 'minimark' gcrootfinder = 'asmgcc' + @py.test.mark.skipif("sys.platform != 'linux2' or platform.machine().startswith('arm')") + def test_demo1(self): + BaseTestStacklet.test_demo1(self) + class TestStackletShadowStack(BaseTestStacklet): gc = 'minimark' gcrootfinder = 'shadowstack' diff --git a/rpython/translator/c/src/stacklet/switch_arm_gcc.h b/rpython/translator/c/src/stacklet/switch_arm_gcc.h --- a/rpython/translator/c/src/stacklet/switch_arm_gcc.h +++ b/rpython/translator/c/src/stacklet/switch_arm_gcc.h @@ -1,3 +1,10 @@ +#if __ARM_ARCH__ >= 5 +# define call_reg(x) "blx " #x "\n" +#elif defined (__ARM_ARCH_4T__) +# define call_reg(x) "mov lr, pc ; bx " #x "\n" +#else +# define call_reg(x) "mov lr, pc ; mov pc, " #x "\n" +#endif static void __attribute__((optimize("O3"))) *slp_switch(void *(*save_state)(void*, void*), void *(*restore_state)(void*, void*), @@ -11,7 +18,7 @@ "mov r5, %[extra]\n" "mov r0, sp\n" /* arg 1: current (old) stack pointer */ "mov r1, r5\n" /* arg 2: extra */ - "blx r3\n" /* call save_state() */ + call_reg(r3) /* call save_state() */ /* skip the rest if the return value is null */ "cmp r0, #0\n" @@ -23,7 +30,7 @@ stack is not restored yet. It contains only garbage here. */ "mov r1, r5\n" /* arg 2: extra */ /* arg 1: current (new) stack pointer is already in r0*/ - "blx r4\n" /* call restore_state() */ + call_reg(r4) /* call restore_state() */ /* The stack's content is now restored. */ "zero:\n" _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit