Author: Ronan Lamy <ronan.l...@gmail.com> Branch: py3k Changeset: r85869:bb148d9bb7e9 Date: 2016-07-26 20:40 +0100 http://bitbucket.org/pypy/pypy/changeset/bb148d9bb7e9/
Log: hg merge default diff --git a/dotviewer/graphparse.py b/dotviewer/graphparse.py --- a/dotviewer/graphparse.py +++ b/dotviewer/graphparse.py @@ -85,10 +85,11 @@ pass def splitline(line, re_word = re.compile(r'[^\s"]\S*|["]["]|["].*?[^\\]["]')): + import ast result = [] for word in re_word.findall(line): if word.startswith('"'): - word = eval(word) + word = ast.literal_eval(word) result.append(word) return result diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -198,10 +198,13 @@ return tp._alignmentofinstances() @builtinify -def byref(cdata): +def byref(cdata, offset=0): # "pointer" is imported at the end of this module to avoid circular # imports - return pointer(cdata) + ptr = pointer(cdata) + if offset != 0: + ptr._buffer[0] += offset + return ptr def cdata_from_address(self, address): # fix the address: turn it into as unsigned, in case it's a negative number diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -335,3 +335,58 @@ This will disable SELinux's protection and allow PyPy to configure correctly. Be sure to enable it again if you need it! + + +How should I report a bug? +-------------------------- + +Our bug tracker is here: https://bitbucket.org/pypy/pypy/issues/ + +Missing features or incompatibilities with CPython are considered +bugs, and they are welcome. (See also our list of `known +incompatibilities`__.) + +.. __: http://pypy.org/compat.html + +For bugs of the kind "I'm getting a PyPy crash or a strange +exception", please note that: **We can't do anything without +reproducing the bug ourselves**. We cannot do anything with +tracebacks from gdb, or core dumps. This is not only because the +standard PyPy is compiled without debug symbols. The real reason is +that a C-level traceback is usually of no help at all in PyPy. +Debugging PyPy can be annoying. + +In more details: + +* First, please give the exact PyPy version, and the OS. + +* It might help focus our search if we know if the bug can be + reproduced on a "``pypy --jit off``" or not. If "``pypy --jit + off``" always works, then the problem might be in the JIT. + Otherwise, we know we can ignore that part. + +* If you got the bug using only Open Source components, please give a + step-by-step guide that we can follow to reproduce the problem + ourselves. Don't assume we know anything about any program other + than PyPy. We would like a guide that we can follow point by point + (without guessing or having to figure things out) + on a machine similar to yours, starting from a bare PyPy, until we + see the same problem. (If you can, you can try to reduce the number + of steps and the time it needs to run, but that is not mandatory.) + +* If the bug involves Closed Source components, or just too many Open + Source components to install them all ourselves, then maybe you can + give us some temporary ssh access to a machine where the bug can be + reproduced. + +* If giving us access would require us to sign a NDA, then we can + consider a commerical support contract for a small sum of money. + +* If even that is not possible for you, then sorry, we can't help. + +Of course, you can try to debug the problem yourself, and we can help +you get started if you ask on the #pypy IRC channel, but be prepared: +debugging an annoying PyPy problem usually involves quite a lot of gdb +in auto-generated C code, and at least some knowledge about the +various components involved, from PyPy's own RPython source code to +the GC and possibly the JIT. diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py --- a/pypy/module/_cffi_backend/ctypestruct.py +++ b/pypy/module/_cffi_backend/ctypestruct.py @@ -90,7 +90,7 @@ self.force_lazy_struct() space = self.space try: - cfield = self._fields_dict[fieldname] + cfield = self._getcfield_const(fieldname) except KeyError: raise OperationError(space.w_KeyError, space.wrap(fieldname)) if cfield.bitshift >= 0: diff --git a/pypy/module/cpyext/test/array.c b/pypy/module/cpyext/test/array.c --- a/pypy/module/cpyext/test/array.c +++ b/pypy/module/cpyext/test/array.c @@ -2366,6 +2366,60 @@ (binaryfunc)NULL, /* nb_divide */ }; +static PyObject* +array_base_multiply(PyObject* obj1, PyObject* obj2) +{ + if (PyList_Check(obj1) && ((arrayobject*)obj2)->ob_descr->typecode == 'i' && Py_SIZE(obj2) == 1) + { + int nn; + int n = PyList_Size(obj1); + PyObject *v = getarrayitem(obj2, 0); + int i = ((PyIntObject*)v)->ob_ival; + PyObject * ret = PyList_New(n); + for (nn = 0; nn < n; nn++) + { + v = PyList_GetItem(obj1, nn); + if (PyInt_Check(v)) + PyList_SetItem(ret, nn, PyLong_FromLong(i * ((PyIntObject*)v)->ob_ival)); + else + PyList_SetItem(ret, nn, v); + } + return ret; + } + else if (PyList_Check(obj2) && ((arrayobject*)obj1)->ob_descr->typecode == 'i' && Py_SIZE(obj1) == 1) + { + int nn; + int n = PyList_Size(obj2); + PyObject *v = getarrayitem(obj1, 0); + int i = ((PyIntObject*)v)->ob_ival; + PyObject * ret = PyList_New(n); + for (nn = 0; nn < n; nn++) + { + v = PyList_GetItem(obj2, nn); + if (PyInt_Check(v)) + PyList_SetItem(ret, nn, PyLong_FromLong(i * ((PyIntObject*)v)->ob_ival)); + else + PyList_SetItem(ret, nn, v); + } + return ret; + } + else if(obj1->ob_type == &Arraytype) + fprintf(stderr, "\nCannot multiply array of type %c and %s\n", + ((arrayobject*)obj1)->ob_descr->typecode, obj2->ob_type->tp_name); + else if(obj2->ob_type == &Arraytype) + fprintf(stderr, "\nCannot multiply array of type %c and %s\n", + ((arrayobject*)obj2)->ob_descr->typecode, obj1->ob_type->tp_name); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyNumberMethods array_base_as_number = { + (binaryfunc)NULL, /* nb_add*/ + (binaryfunc)NULL, /* nb_subtract */ + (binaryfunc)array_base_multiply, /* nb_multiply */ + (binaryfunc)NULL, /* nb_divide */ +}; + static PyMappingMethods array_as_mapping = { (lenfunc)array_length, (binaryfunc)array_subscr, @@ -2624,6 +2678,49 @@ static PyObject *array_iter(arrayobject *ao); +static PyTypeObject ArrayBasetype = { + PyVarObject_HEAD_INIT(NULL, 0) + "array.basearray", + sizeof(arrayobject), + 0, + (destructor)array_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)array_repr, /* tp_repr */ + &array_base_as_number, /* tp_as_number*/ + &array_as_sequence, /* tp_as_sequence*/ + &array_as_mapping, /* tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + &array_as_buffer, /* tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_WEAKREFS | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + arraytype_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + array_richcompare, /* tp_richcompare */ + offsetof(arrayobject, weakreflist), /* tp_weaklistoffset */ + (getiterfunc)array_iter, /* tp_iter */ + 0, /* tp_iternext */ + array_methods, /* tp_methods */ + 0, /* tp_members */ + array_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + array_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + static PyTypeObject Arraytype = { PyVarObject_HEAD_INIT(NULL, 0) "array.array", @@ -2791,6 +2888,8 @@ register Py_UNICODE *p; struct arraydescr *descr; + ArrayBasetype.ob_type = &PyType_Type; + Arraytype.tp_base = &ArrayBasetype; if (PyType_Ready(&Arraytype) < 0) return NULL; Py_TYPE(&PyArrayIter_Type) = &PyType_Type; @@ -2798,10 +2897,11 @@ if (m == NULL) return NULL; - Py_INCREF((PyObject *)&Arraytype); + if (PyType_Ready(&ArrayBasetype) < 0) + return; PyModule_AddObject(m, "ArrayType", (PyObject *)&Arraytype); - Py_INCREF((PyObject *)&Arraytype); PyModule_AddObject(m, "array", (PyObject *)&Arraytype); + PyModule_AddObject(m, "arraybase", (PyObject *)&ArrayBasetype); for (descr=descriptors; descr->typecode != '\0'; descr++) { size++; diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c --- a/pypy/module/cpyext/test/foo.c +++ b/pypy/module/cpyext/test/foo.c @@ -747,6 +747,7 @@ if (PyType_Ready(&UnicodeSubtype3) < 0) INITERROR; + TupleLike.tp_flags = Py_TPFLAGS_DEFAULT; TupleLike.tp_base = &PyTuple_Type; if (PyType_Ready(&TupleLike) < 0) INITERROR; diff --git a/pypy/module/cpyext/test/test_bytesobject.py b/pypy/module/cpyext/test/test_bytesobject.py --- a/pypy/module/cpyext/test/test_bytesobject.py +++ b/pypy/module/cpyext/test/test_bytesobject.py @@ -113,9 +113,10 @@ module = self.import_extension('foo', [ ("getbytes", "METH_NOARGS", """ - PyObject* s1 = PyBytes_FromStringAndSize("test", 4); - char* c = PyBytes_AsString(s1); - PyObject* s2 = PyBytes_FromStringAndSize(c, 4); + char *c; + PyObject* s2, *s1 = PyBytes_FromStringAndSize("test", 4); + c = PyBytes_AsString(s1); + s2 = PyBytes_FromStringAndSize(c, 4); Py_DECREF(s1); return s2; """), diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -78,7 +78,7 @@ else: libraries = [] if sys.platform.startswith('linux'): - compile_extra = ["-Werror", "-g", "-O0", "-fPIC"] + compile_extra = ["-Werror", "-g", "-O0", "-Wp,-U_FORTIFY_SOURCE", "-fPIC"] link_extra = ["-g"] else: compile_extra = link_extra = None @@ -129,6 +129,7 @@ return str(soname) def freeze_refcnts(self): + rawrefcount._dont_free_any_more() return #ZZZ state = self.space.fromcache(RefcountState) self.frozen_refcounts = {} diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -803,7 +803,7 @@ data before the other iterator, it is faster to use list() instead of tee() - Equivalent to : + If iter(iterable) has no method __copy__(), this is equivalent to: def tee(iterable, n=2): def gen(next, data={}, cnt=[0]): @@ -816,17 +816,22 @@ yield item it = iter(iterable) return tuple([gen(it.next) for i in range(n)]) + + If iter(iterable) has a __copy__ method, though, we just return + a tuple t = (iterable, t[0].__copy__(), t[1].__copy__(), ...). """ if n < 0: raise oefmt(space.w_ValueError, "n must be >= 0") - if isinstance(w_iterable, W_TeeIterable): # optimization only - w_chained_list = w_iterable.w_chained_list - w_iterator = w_iterable.w_iterator + if space.findattr(w_iterable, space.wrap("__copy__")) is not None: + # In this case, we don't instantiate any W_TeeIterable. + # We just rely on doing repeated __copy__(). This case + # includes the situation where w_iterable is already + # a W_TeeIterable itself. iterators_w = [w_iterable] * n for i in range(1, n): - iterators_w[i] = space.wrap(W_TeeIterable(space, w_iterator, - w_chained_list)) + w_iterable = space.call_method(w_iterable, "__copy__") + iterators_w[i] = w_iterable else: w_iterator = space.iter(w_iterable) w_chained_list = W_TeeChainedListNode(space) @@ -905,6 +910,11 @@ self.w_chained_list = w_chained_list.w_next return w_obj + def copy_w(self): + space = self.space + tee_iter = W_TeeIterable(space, self.w_iterator, self.chained_list) + return space.wrap(tee_iter) + def reduce_w(self): return self.space.newtuple([self.space.gettypefor(W_TeeIterable), self.space.newtuple([self.space.newtuple([])]), @@ -943,6 +953,7 @@ __new__ = interp2app(W_TeeIterable___new__), __iter__ = interp2app(W_TeeIterable.iter_w), __next__ = interp2app(W_TeeIterable.next_w), + __copy__ = interp2app(W_TeeIterable.copy_w), __weakref__ = make_weakref_descr(W_TeeIterable), __reduce__ = interp2app(W_TeeIterable.reduce_w), __setstate__ = interp2app(W_TeeIterable.setstate_w) diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -577,6 +577,48 @@ x = next(d) assert x == 'b' + def test_tee_defines_copy(self): + import itertools + a, b = itertools.tee('abc') + c = b.__copy__() + assert list(a) == ['a', 'b', 'c'] + assert list(b) == ['a', 'b', 'c'] + assert list(c) == ['a', 'b', 'c'] + a, = itertools.tee('abc', 1) + x = a.next() + assert x == 'a' + b = a.__copy__() + x = a.next() + assert x == 'b' + x = b.next() + assert x == 'b' + + def test_tee_function_uses_copy(self): + import itertools + class MyIterator(object): + def __iter__(self): + return self + def next(self): + raise NotImplementedError + def __copy__(self): + return iter('def') + my = MyIterator() + a, = itertools.tee(my, 1) + assert a is my + a, b = itertools.tee(my) + assert a is my + assert b is not my + assert list(b) == ['d', 'e', 'f'] + # this gives AttributeError because it tries to call + # my.__copy__().__copy__() and there isn't one + raises(AttributeError, itertools.tee, my, 3) + + def test_tee_function_empty(self): + import itertools + assert itertools.tee('abc', 0) == () + a, = itertools.tee('abc', 1) + assert itertools.tee(a, 0) == () + class AppTestItertools26: spaceconfig = dict(usemodules=['itertools']) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py @@ -265,3 +265,10 @@ class A(object): _byref = byref A._byref(c_int(5)) + + def test_byref_with_offset(self): + c = c_int() + d = byref(c) + base = cast(d, c_void_p).value + for i in [0, 1, 4, 1444, -10293]: + assert cast(byref(c, i), c_void_p).value == base + i diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -205,6 +205,9 @@ def newbytes(self, x): return w_some_obj() + def newunicode(self, x): + return w_some_obj() + def wrap(self, x): if not we_are_translated(): if isinstance(x, gateway.interp2app): diff --git a/rpython/jit/backend/arm/test/test_assembler.py b/rpython/jit/backend/arm/test/test_assembler.py --- a/rpython/jit/backend/arm/test/test_assembler.py +++ b/rpython/jit/backend/arm/test/test_assembler.py @@ -1,6 +1,5 @@ from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import registers as r -from rpython.jit.backend.arm.support import arm_int_div from rpython.jit.backend.arm.assembler import AssemblerARM from rpython.jit.backend.arm.locations import imm from rpython.jit.backend.arm.test.support import run_asm @@ -180,19 +179,6 @@ self.a.gen_func_epilog() assert run_asm(self.a) == 133 - def test_division(self): - self.a.gen_func_prolog() - self.a.mc.MOV_ri(r.r0.value, 123) - self.a.mc.MOV_ri(r.r1.value, 2) - - # call to div - self.a.mc.PUSH(range(2, 12)) - div_addr = rffi.cast(lltype.Signed, arm_int_div) - self.a.mc.BL(div_addr) - self.a.mc.POP(range(2, 12)) - self.a.gen_func_epilog() - assert run_asm(self.a) == 61 - def test_bl_with_conditional_exec(self): functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) call_addr = rffi.cast(lltype.Signed, llhelper(functype, callme)) diff --git a/rpython/jit/backend/arm/test/test_regalloc.py b/rpython/jit/backend/arm/test/test_regalloc.py --- a/rpython/jit/backend/arm/test/test_regalloc.py +++ b/rpython/jit/backend/arm/test/test_regalloc.py @@ -545,23 +545,6 @@ self.interpret(ops, [s, 1234567890]) assert s[1] == 1234567890 - def test_division_optimized(self): - ops = ''' - [i7, i6] - label(i7, i6, descr=targettoken) - i18 = int_floordiv(i7, i6) - i19 = int_xor(i7, i6) - i21 = int_lt(i19, 0) - i22 = int_mod(i7, i6) - i23 = int_is_true(i22) - i24 = int_eq(i6, 4) - guard_false(i24) [i18] - jump(i18, i6, descr=targettoken) - ''' - self.interpret(ops, [10, 4]) - assert self.getint(0) == 2 - # FIXME: Verify that i19 - i23 are removed - class TestRegallocFloats(CustomBaseTestRegalloc): def test_float_add(self): diff --git a/rpython/jit/backend/llsupport/test/test_gc_integration.py b/rpython/jit/backend/llsupport/test/test_gc_integration.py --- a/rpython/jit/backend/llsupport/test/test_gc_integration.py +++ b/rpython/jit/backend/llsupport/test/test_gc_integration.py @@ -330,6 +330,13 @@ expected_size = 2 idx = 1 fixed_size -= 32 + if self.cpu.backend_name.startswith('zarch') or \ + self.cpu.backend_name.startswith('ppc'): + # the allocation always allocates the register + # into the return register. (e.g. r3 on ppc) + # the next malloc_nursery will move r3 to the + # frame manager, thus the two bits will be on the frame + fixed_size += 4 assert len(frame.jf_gcmap) == expected_size # check that we have two bits set, and that they are in two # registers (p0 and p1 are moved away when doing p2, but not diff --git a/rpython/jit/backend/zarch/arch.py b/rpython/jit/backend/zarch/arch.py --- a/rpython/jit/backend/zarch/arch.py +++ b/rpython/jit/backend/zarch/arch.py @@ -45,10 +45,7 @@ # +------------------------------+ <- assembler begin # | SAVE CONTEXT | # +------------------------------+ -# +--+| BRANCH (saves addr of pool | -# | | in r13) | -# | +------------------------------+ -# | | ... | +#start| ... | # | | LITERAL POOL | <---+ # | | ... | <-+ | # +-->+------------------------------+ | | diff --git a/rpython/jit/backend/zarch/assembler.py b/rpython/jit/backend/zarch/assembler.py --- a/rpython/jit/backend/zarch/assembler.py +++ b/rpython/jit/backend/zarch/assembler.py @@ -309,17 +309,15 @@ # signature of this _frame_realloc_slowpath function: # * on entry, r0 is the new size - # * on entry, r1 is the gcmap # * no managed register must be modified - ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap') - mc.STG(r.SCRATCH, l.addr(ofs2, r.SPP)) + # caller already did push_gcmap(store=True) self._push_core_regs_to_jitframe(mc, r.MANAGED_REGS) self._push_fp_regs_to_jitframe(mc) - # First argument is SPP (= r31), which is the jitframe + # First argument is SPP, which is the jitframe mc.LGR(r.r2, r.SPP) # no need to move second argument (frame_depth), @@ -347,6 +345,7 @@ mc.load(r.r5, r.r5, 0) mc.store(r.r2, r.r5, -WORD) + self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_core_regs_from_jitframe(mc, r.MANAGED_REGS) self._pop_fp_regs_from_jitframe(mc) @@ -386,14 +385,12 @@ # signature of these cond_call_slowpath functions: # * on entry, r11 contains the function to call # * r2, r3, r4, r5 contain arguments for the call - # * r0 is the gcmap + # * gcmap is pushed # * the old value of these regs must already be stored in the jitframe # * on exit, all registers are restored from the jitframe mc = InstrBuilder() self.mc = mc - ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap') - mc.STG(r.SCRATCH2, l.addr(ofs2,r.SPP)) mc.store_link() mc.push_std_frame() @@ -411,6 +408,7 @@ reg is not r.r4 and reg is not r.r5 and reg is not r.r11] + # the caller already did push_gcmap(store=True) self._push_core_regs_to_jitframe(mc, regs) if supports_floats: self._push_fp_regs_to_jitframe(mc) @@ -420,6 +418,7 @@ # Finish self._reload_frame_if_necessary(mc) + self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_core_regs_from_jitframe(mc, saved_regs) if supports_floats: self._pop_fp_regs_from_jitframe(mc) @@ -449,12 +448,11 @@ mc.store_link() mc.push_std_frame() # - ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap') - mc.STG(r.r1, l.addr(ofs2, r.SPP)) saved_regs = [reg for reg in r.MANAGED_REGS if reg is not r.RES and reg is not r.RSZ] self._push_core_regs_to_jitframe(mc, saved_regs) self._push_fp_regs_to_jitframe(mc) + # the caller already did push_gcmap(store=True) # if kind == 'fixed': addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() @@ -588,7 +586,7 @@ # sum -> (14 bytes) mc.write('\x00'*14) mc.load_imm(r.RETURN, self._frame_realloc_slowpath) - self.load_gcmap(mc, r.r1, gcmap) + self.push_gcmap(mc, gcmap, store=True) mc.raw_call() self.frame_depth_to_patch.append((patch_pos, mc.currpos())) @@ -685,6 +683,8 @@ # name = "Loop # %s: %s" % (looptoken.number, loopname) # self.cpu.profile_agent.native_code_written(name, # rawstart, full_size) + #print(hex(rawstart+looppos)) + #import pdb; pdb.set_trace() return AsmInfo(ops_offset, rawstart + looppos, size_excluding_failure_stuff - looppos, rawstart) @@ -867,6 +867,10 @@ ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') mc.STG(r.SCRATCH, l.addr(ofs, r.SPP)) + def pop_gcmap(self, mc): + ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') + mc.LG(r.SCRATCH, l.addr(ofs, r.SPP)) + def break_long_loop(self): # If the loop is too long, the guards in it will jump forward # more than 32 KB. We use an approximate hack to know if we @@ -1339,7 +1343,7 @@ # new value of nursery_free_adr in RSZ and the adr of the new object # in RES. - self.load_gcmap(mc, r.r1, gcmap) + self.push_gcmap(mc, gcmap, store=True) mc.branch_absolute(self.malloc_slowpath) # here r1 holds nursery_free_addr @@ -1375,7 +1379,7 @@ # new value of nursery_free_adr in RSZ and the adr of the new object # in RES. - self.load_gcmap(mc, r.r1, gcmap) + self.push_gcmap(mc, gcmap, store=True) mc.branch_absolute(self.malloc_slowpath) offset = mc.currpos() - fast_jmp_pos @@ -1468,7 +1472,7 @@ pmc.overwrite() # # save the gcmap - self.load_gcmap(mc, r.r1, gcmap) + self.push_gcmap(mc, gcmap, store=True) # # load the function into r14 and jump if kind == rewrite.FLAG_ARRAY: diff --git a/rpython/jit/backend/zarch/opassembler.py b/rpython/jit/backend/zarch/opassembler.py --- a/rpython/jit/backend/zarch/opassembler.py +++ b/rpython/jit/backend/zarch/opassembler.py @@ -387,8 +387,7 @@ if reg in self._COND_CALL_SAVE_REGS] self._push_core_regs_to_jitframe(self.mc, should_be_saved) - # load gc map into unusual location: r0 - self.load_gcmap(self.mc, r.SCRATCH2, regalloc.get_gcmap()) + self.push_gcmap(self.mc, regalloc.get_gcmap()) # # load the 0-to-4 arguments into these registers, with the address of # the function to call into r11 diff --git a/rpython/jit/backend/zarch/test/test_runner.py b/rpython/jit/backend/zarch/test/test_runner.py --- a/rpython/jit/backend/zarch/test/test_runner.py +++ b/rpython/jit/backend/zarch/test/test_runner.py @@ -26,4 +26,4 @@ add_loop_instructions = "lg; lgr; larl; agr; cgfi; jge; j;$" bridge_loop_instructions = "lg; cgfi; jnl; lghi; " \ - "(lgfi|iilf);( iihf;)? (lgfi|iilf);( iihf;)? basr; larl; (lgfi|iilf);( iihf;)? br;$" + "(lgfi|iilf);( iihf;)? (lgfi|iilf);( iihf;)? stg; basr; larl; (lgfi|iilf);( iihf;)? br;$" diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py --- a/rpython/jit/metainterp/blackhole.py +++ b/rpython/jit/metainterp/blackhole.py @@ -1143,45 +1143,35 @@ @arguments("cpu", "i", "R", "d", returns="i") def bhimpl_residual_call_r_i(cpu, func, args_r, calldescr): - workaround2200.active = True return cpu.bh_call_i(func, None, args_r, None, calldescr) @arguments("cpu", "i", "R", "d", returns="r") def bhimpl_residual_call_r_r(cpu, func, args_r, calldescr): - workaround2200.active = True return cpu.bh_call_r(func, None, args_r, None, calldescr) @arguments("cpu", "i", "R", "d") def bhimpl_residual_call_r_v(cpu, func, args_r, calldescr): - workaround2200.active = True return cpu.bh_call_v(func, None, args_r, None, calldescr) @arguments("cpu", "i", "I", "R", "d", returns="i") def bhimpl_residual_call_ir_i(cpu, func, args_i, args_r, calldescr): - workaround2200.active = True return cpu.bh_call_i(func, args_i, args_r, None, calldescr) @arguments("cpu", "i", "I", "R", "d", returns="r") def bhimpl_residual_call_ir_r(cpu, func, args_i, args_r, calldescr): - workaround2200.active = True return cpu.bh_call_r(func, args_i, args_r, None, calldescr) @arguments("cpu", "i", "I", "R", "d") def bhimpl_residual_call_ir_v(cpu, func, args_i, args_r, calldescr): - workaround2200.active = True return cpu.bh_call_v(func, args_i, args_r, None, calldescr) @arguments("cpu", "i", "I", "R", "F", "d", returns="i") def bhimpl_residual_call_irf_i(cpu, func, args_i,args_r,args_f,calldescr): - workaround2200.active = True return cpu.bh_call_i(func, args_i, args_r, args_f, calldescr) @arguments("cpu", "i", "I", "R", "F", "d", returns="r") def bhimpl_residual_call_irf_r(cpu, func, args_i,args_r,args_f,calldescr): - workaround2200.active = True return cpu.bh_call_r(func, args_i, args_r, args_f, calldescr) @arguments("cpu", "i", "I", "R", "F", "d", returns="f") def bhimpl_residual_call_irf_f(cpu, func, args_i,args_r,args_f,calldescr): - workaround2200.active = True return cpu.bh_call_f(func, args_i, args_r, args_f, calldescr) @arguments("cpu", "i", "I", "R", "F", "d") def bhimpl_residual_call_irf_v(cpu, func, args_i,args_r,args_f,calldescr): - workaround2200.active = True return cpu.bh_call_v(func, args_i, args_r, args_f, calldescr) # conditional calls - note that they cannot return stuff @@ -1209,54 +1199,44 @@ @arguments("cpu", "j", "R", returns="i") def bhimpl_inline_call_r_i(cpu, jitcode, args_r): - workaround2200.active = True return cpu.bh_call_i(jitcode.get_fnaddr_as_int(), None, args_r, None, jitcode.calldescr) @arguments("cpu", "j", "R", returns="r") def bhimpl_inline_call_r_r(cpu, jitcode, args_r): - workaround2200.active = True return cpu.bh_call_r(jitcode.get_fnaddr_as_int(), None, args_r, None, jitcode.calldescr) @arguments("cpu", "j", "R") def bhimpl_inline_call_r_v(cpu, jitcode, args_r): - workaround2200.active = True return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), None, args_r, None, jitcode.calldescr) @arguments("cpu", "j", "I", "R", returns="i") def bhimpl_inline_call_ir_i(cpu, jitcode, args_i, args_r): - workaround2200.active = True return cpu.bh_call_i(jitcode.get_fnaddr_as_int(), args_i, args_r, None, jitcode.calldescr) @arguments("cpu", "j", "I", "R", returns="r") def bhimpl_inline_call_ir_r(cpu, jitcode, args_i, args_r): - workaround2200.active = True return cpu.bh_call_r(jitcode.get_fnaddr_as_int(), args_i, args_r, None, jitcode.calldescr) @arguments("cpu", "j", "I", "R") def bhimpl_inline_call_ir_v(cpu, jitcode, args_i, args_r): - workaround2200.active = True return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), args_i, args_r, None, jitcode.calldescr) @arguments("cpu", "j", "I", "R", "F", returns="i") def bhimpl_inline_call_irf_i(cpu, jitcode, args_i, args_r, args_f): - workaround2200.active = True return cpu.bh_call_i(jitcode.get_fnaddr_as_int(), args_i, args_r, args_f, jitcode.calldescr) @arguments("cpu", "j", "I", "R", "F", returns="r") def bhimpl_inline_call_irf_r(cpu, jitcode, args_i, args_r, args_f): - workaround2200.active = True return cpu.bh_call_r(jitcode.get_fnaddr_as_int(), args_i, args_r, args_f, jitcode.calldescr) @arguments("cpu", "j", "I", "R", "F", returns="f") def bhimpl_inline_call_irf_f(cpu, jitcode, args_i, args_r, args_f): - workaround2200.active = True return cpu.bh_call_f(jitcode.get_fnaddr_as_int(), args_i, args_r, args_f, jitcode.calldescr) @arguments("cpu", "j", "I", "R", "F") def bhimpl_inline_call_irf_v(cpu, jitcode, args_i, args_r, args_f): - workaround2200.active = True return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), args_i, args_r, args_f, jitcode.calldescr) @@ -1543,8 +1523,6 @@ if not self.nextblackholeinterp: self._exit_frame_with_exception(current_exc) return current_exc - finally: - workaround2200.active = False # # pass the frame's return value to the caller caller = self.nextblackholeinterp @@ -1717,10 +1695,3 @@ # _run_forever(firstbh, current_exc) convert_and_run_from_pyjitpl._dont_inline_ = True - -# ____________________________________________________________ - -class WorkaroundIssue2200(object): - pass -workaround2200 = WorkaroundIssue2200() -workaround2200.active = False diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -620,23 +620,28 @@ raise jitexc.DoneWithThisFrameVoid() class DoneWithThisFrameDescrInt(_DoneWithThisFrameDescr): + def get_result(self, cpu, deadframe): + return cpu.get_int_value(deadframe, 0) def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.INT - result = metainterp_sd.cpu.get_int_value(deadframe, 0) - raise jitexc.DoneWithThisFrameInt(result) + cpu = metainterp_sd.cpu + raise jitexc.DoneWithThisFrameInt(self.get_result(cpu, deadframe)) class DoneWithThisFrameDescrRef(_DoneWithThisFrameDescr): + def get_result(self, cpu, deadframe): + return cpu.get_ref_value(deadframe, 0) def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.REF cpu = metainterp_sd.cpu - result = cpu.get_ref_value(deadframe, 0) - raise jitexc.DoneWithThisFrameRef(cpu, result) + raise jitexc.DoneWithThisFrameRef(cpu, self.get_result(cpu, deadframe)) class DoneWithThisFrameDescrFloat(_DoneWithThisFrameDescr): + def get_result(self, cpu, deadframe): + return cpu.get_float_value(deadframe, 0) def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.FLOAT - result = metainterp_sd.cpu.get_float_value(deadframe, 0) - raise jitexc.DoneWithThisFrameFloat(result) + cpu = metainterp_sd.cpu + raise jitexc.DoneWithThisFrameFloat(self.get_result(cpu, deadframe)) class ExitFrameWithExceptionDescrRef(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): 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 @@ -57,10 +57,16 @@ self.cache_anything = {} self.cache_seen_allocation = {} + # set of boxes that we've seen a quasi-immut for the field on. cleared + # on writes to the field. + self.quasiimmut_seen = None + def _clear_cache_on_write(self, seen_allocation_of_target): if not seen_allocation_of_target: self.cache_seen_allocation.clear() self.cache_anything.clear() + if self.quasiimmut_seen is not None: + self.quasiimmut_seen.clear() def _seen_alloc(self, ref_box): if not isinstance(ref_box, RefFrontendOp): @@ -92,6 +98,8 @@ def invalidate_unescaped(self): self._invalidate_unescaped(self.cache_anything) self._invalidate_unescaped(self.cache_seen_allocation) + if self.quasiimmut_seen is not None: + self.quasiimmut_seen.clear() def _invalidate_unescaped(self, d): for ref_box in d.keys(): @@ -484,3 +492,18 @@ if isinstance(oldbox, FrontendOp) and isinstance(newbox, Const): assert newbox.same_constant(constant_from_op(oldbox)) oldbox.set_replaced_with_const() + + def is_quasi_immut_known(self, fielddescr, box): + cache = self.heap_cache.get(fielddescr, None) + if cache is not None and cache.quasiimmut_seen is not None: + return box in cache.quasiimmut_seen + return False + + def quasi_immut_now_known(self, fielddescr, box): + cache = self.heap_cache.get(fielddescr, None) + if cache is None: + cache = self.heap_cache[fielddescr] = CacheEntry(self) + if cache.quasiimmut_seen is not None: + cache.quasiimmut_seen[box] = None + else: + cache.quasiimmut_seen = {box: None} diff --git a/rpython/jit/metainterp/optimizeopt/intdiv.py b/rpython/jit/metainterp/optimizeopt/intdiv.py --- a/rpython/jit/metainterp/optimizeopt/intdiv.py +++ b/rpython/jit/metainterp/optimizeopt/intdiv.py @@ -1,5 +1,5 @@ from rpython.rlib.rarithmetic import LONG_BIT, intmask, r_uint -from rpython.rlib.rbigint import rbigint, ONERBIGINT + from rpython.jit.metainterp.history import ConstInt from rpython.jit.metainterp.resoperation import ResOperation, rop @@ -17,10 +17,19 @@ while (r_uint(1) << (i+1)) < r_uint(m): i += 1 - # k = 2**(64+i) // m + 1, computed manually using rbigint - # because that's the easiest - k1 = ONERBIGINT.lshift(LONG_BIT + i).floordiv(rbigint.fromint(m)) - k = k1.touint() + r_uint(1) + # quotient = 2**(64+i) // m + high_word_dividend = r_uint(1) << i + quotient = r_uint(0) + for bit in range(LONG_BIT-1, -1, -1): + t = quotient + (r_uint(1) << bit) + # check: is 't * m' small enough to be < 2**(64+i), or not? + # note that we're really computing (2**(64+i)-1) // m, but the result + # is the same, because powers of two are not multiples of m. + if unsigned_mul_high(t, r_uint(m)) < high_word_dividend: + quotient = t # yes, small enough + + # k = 2**(64+i) // m + 1 + k = quotient + r_uint(1) assert k != r_uint(0) # Proof that k < 2**64 holds in all cases, even with the "+1": diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -829,8 +829,11 @@ mutatefielddescr, orgpc): from rpython.jit.metainterp.quasiimmut import QuasiImmutDescr cpu = self.metainterp.cpu + if self.metainterp.heapcache.is_quasi_immut_known(fielddescr, box): + return descr = QuasiImmutDescr(cpu, box.getref_base(), fielddescr, mutatefielddescr) + self.metainterp.heapcache.quasi_immut_now_known(fielddescr, box) self.metainterp.history.record(rop.QUASIIMMUT_FIELD, [box], None, descr=descr) self.metainterp.generate_guard(rop.GUARD_NOT_INVALIDATED, @@ -2540,7 +2543,13 @@ elif box.type == history.REF: args.append(box.getref_base()) elif box.type == history.FLOAT: args.append(box.getfloatstorage()) else: assert 0 - self.jitdriver_sd.warmstate.execute_assembler(loop_token, *args) + res = self.jitdriver_sd.warmstate.execute_assembler(loop_token, *args) + kind = history.getkind(lltype.typeOf(res)) + if kind == 'void': raise jitexc.DoneWithThisFrameVoid() + if kind == 'int': raise jitexc.DoneWithThisFrameInt(res) + if kind == 'ref': raise jitexc.DoneWithThisFrameRef(self.cpu, res) + if kind == 'float': raise jitexc.DoneWithThisFrameFloat(res) + raise AssertionError(kind) def prepare_resume_from_failure(self, deadframe, inputargs, resumedescr): exception = self.cpu.grab_exc_value(deadframe) diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py --- a/rpython/jit/metainterp/test/test_ajit.py +++ b/rpython/jit/metainterp/test/test_ajit.py @@ -4470,6 +4470,28 @@ self.meta_interp(f, []) + def test_issue2335_recursion(self): + # Reproduces issue #2335: same as issue #2200, but the workaround + # in c4c54cb69aba was not enough. + driver = JitDriver(greens=["level"], reds=["i"]) + def enter(level, i): + if level == 0: + f(1) # recursive call + driver.can_enter_jit(level=level, i=i) + def f(level): + i = 0 if level == 0 else 298 + while True: + driver.jit_merge_point(level=level, i=i) + i += 1 + if i >= 300: + return i + promote(i + 1) # a failing guard + enter(level, i) + def main(): + set_param(None, 'trace_eagerness', 999999) + f(0) + self.meta_interp(main, []) + def test_pending_setarrayitem_with_indirect_constant_index(self): driver = JitDriver(greens=[], reds='auto') class X: 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 @@ -797,3 +797,46 @@ h.class_now_known(box1) # interaction of the two families of flags assert not h.is_unescaped(box1) assert h.is_likely_virtual(box1) + + def test_quasiimmut_seen(self): + h = HeapCache() + box1 = RefFrontendOp(1) + box2 = RefFrontendOp(2) + box3 = RefFrontendOp(3) + box4 = RefFrontendOp(4) + assert not h.is_quasi_immut_known(descr1, box1) + assert not h.is_quasi_immut_known(descr1, box2) + assert not h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) + h.quasi_immut_now_known(descr1, box1) + assert h.is_quasi_immut_known(descr1, box1) + assert not h.is_quasi_immut_known(descr1, box2) + assert not h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) + h.quasi_immut_now_known(descr1, box2) + assert h.is_quasi_immut_known(descr1, box1) + assert h.is_quasi_immut_known(descr1, box2) + assert not h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) + h.quasi_immut_now_known(descr2, box3) + assert h.is_quasi_immut_known(descr1, box1) + assert h.is_quasi_immut_known(descr1, box2) + assert h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) + h.quasi_immut_now_known(descr2, box4) + assert h.is_quasi_immut_known(descr1, box1) + assert h.is_quasi_immut_known(descr1, box2) + assert h.is_quasi_immut_known(descr2, box3) + assert h.is_quasi_immut_known(descr2, box4) + + # invalidate the descr1 cache + + h.setfield(box1, box3, descr1) + assert not h.is_quasi_immut_known(descr1, box1) + assert not h.is_quasi_immut_known(descr1, box2) + + # a call invalidates everything + h.invalidate_caches( + rop.CALL_N, FakeCallDescr(FakeEffectinfo.EF_CAN_RAISE), []) + assert not h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -512,6 +512,32 @@ assert res == 4 * 7 self.check_operations_history(getfield_gc_i=2, getfield_gc_r=2) + def test_heap_caching_quasi_immutable(self): + class A: + _immutable_fields_ = ['x?'] + a1 = A() + a1.x = 5 + a2 = A() + a2.x = 7 + + @jit.elidable + def get(n): + if n > 0: + return a1 + return a2 + + def g(a): + return a.x + + def fn(n): + jit.promote(n) + a = get(n) + return g(a) + a.x + res = self.interp_operations(fn, [7]) + assert res == 10 + self.check_operations_history(quasiimmut_field=1) + + def test_heap_caching_multiple_tuples(self): class Gbl(object): pass diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -529,7 +529,7 @@ def make_enter_function(self, jd): from rpython.jit.metainterp.warmstate import WarmEnterState state = WarmEnterState(self, jd) - maybe_compile_and_run = state.make_entry_point() + maybe_compile_and_run, EnterJitAssembler = state.make_entry_point() jd.warmstate = state def crash_in_jit(e): @@ -560,6 +560,7 @@ maybe_enter_jit._always_inline_ = True jd._maybe_enter_jit_fn = maybe_enter_jit jd._maybe_compile_and_run_fn = maybe_compile_and_run + jd._EnterJitAssembler = EnterJitAssembler def make_driverhook_graphs(self): s_Str = annmodel.SomeString() @@ -842,12 +843,8 @@ # while 1: # try: # return portal(*args) - # except ContinueRunningNormally, e: - # *args = *e.new_args - # except DoneWithThisFrame, e: - # return e.return - # except ExitFrameWithException, e: - # raise Exception, e.value + # except JitException, e: + # return handle_jitexception(e) # # def portal(*args): # while 1: @@ -884,90 +881,79 @@ rtyper = self.translator.rtyper RESULT = PORTALFUNC.RESULT result_kind = history.getkind(RESULT) + assert result_kind.startswith(jd.result_type) ts = self.cpu.ts state = jd.warmstate maybe_compile_and_run = jd._maybe_compile_and_run_fn + EnterJitAssembler = jd._EnterJitAssembler def ll_portal_runner(*args): - start = True - while 1: - try: - # maybe enter from the function's start. Note that the - # 'start' variable is constant-folded away because it's - # the first statement in the loop. - if start: - maybe_compile_and_run( - state.increment_function_threshold, *args) - # - # then run the normal portal function, i.e. the - # interpreter's main loop. It might enter the jit - # via maybe_enter_jit(), which typically ends with - # handle_fail() being called, which raises on the - # following exceptions --- catched here, because we - # want to interrupt the whole interpreter loop. - return support.maybe_on_top_of_llinterp(rtyper, - portal_ptr)(*args) - except jitexc.ContinueRunningNormally as e: + try: + # maybe enter from the function's start. + maybe_compile_and_run( + state.increment_function_threshold, *args) + # + # then run the normal portal function, i.e. the + # interpreter's main loop. It might enter the jit + # via maybe_enter_jit(), which typically ends with + # handle_fail() being called, which raises on the + # following exceptions --- catched here, because we + # want to interrupt the whole interpreter loop. + return support.maybe_on_top_of_llinterp(rtyper, + portal_ptr)(*args) + except jitexc.JitException as e: + result = handle_jitexception(e) + if result_kind != 'void': + result = specialize_value(RESULT, result) + return result + + def handle_jitexception(e): + # XXX there are too many exceptions all around... + while True: + if isinstance(e, EnterJitAssembler): + try: + return e.execute() + except jitexc.JitException as e: + continue + # + if isinstance(e, jitexc.ContinueRunningNormally): args = () for ARGTYPE, attrname, count in portalfunc_ARGS: x = getattr(e, attrname)[count] x = specialize_value(ARGTYPE, x) args = args + (x,) - start = False - continue - except jitexc.DoneWithThisFrameVoid: - assert result_kind == 'void' - return - except jitexc.DoneWithThisFrameInt as e: - assert result_kind == 'int' - return specialize_value(RESULT, e.result) - except jitexc.DoneWithThisFrameRef as e: - assert result_kind == 'ref' - return specialize_value(RESULT, e.result) - except jitexc.DoneWithThisFrameFloat as e: - assert result_kind == 'float' - return specialize_value(RESULT, e.result) - except jitexc.ExitFrameWithExceptionRef as e: + try: + result = support.maybe_on_top_of_llinterp(rtyper, + portal_ptr)(*args) + except jitexc.JitException as e: + continue + if result_kind != 'void': + result = unspecialize_value(result) + return result + # + if result_kind == 'void': + if isinstance(e, jitexc.DoneWithThisFrameVoid): + return None + if result_kind == 'int': + if isinstance(e, jitexc.DoneWithThisFrameInt): + return e.result + if result_kind == 'ref': + if isinstance(e, jitexc.DoneWithThisFrameRef): + return e.result + if result_kind == 'float': + if isinstance(e, jitexc.DoneWithThisFrameFloat): + return e.result + # + if isinstance(e, jitexc.ExitFrameWithExceptionRef): value = ts.cast_to_baseclass(e.value) if not we_are_translated(): raise LLException(ts.get_typeptr(value), value) else: value = cast_base_ptr_to_instance(Exception, value) + assert value is not None raise value - - def handle_jitexception(e): - # XXX the bulk of this function is mostly a copy-paste from above - try: - raise e - except jitexc.ContinueRunningNormally as e: - args = () - for ARGTYPE, attrname, count in portalfunc_ARGS: - x = getattr(e, attrname)[count] - x = specialize_value(ARGTYPE, x) - args = args + (x,) - result = ll_portal_runner(*args) - if result_kind != 'void': - result = unspecialize_value(result) - return result - except jitexc.DoneWithThisFrameVoid: - assert result_kind == 'void' - return - except jitexc.DoneWithThisFrameInt as e: - assert result_kind == 'int' - return e.result - except jitexc.DoneWithThisFrameRef as e: - assert result_kind == 'ref' - return e.result - except jitexc.DoneWithThisFrameFloat as e: - assert result_kind == 'float' - return e.result - except jitexc.ExitFrameWithExceptionRef as e: - value = ts.cast_to_baseclass(e.value) - if not we_are_translated(): - raise LLException(ts.get_typeptr(value), value) - else: - value = cast_base_ptr_to_instance(Exception, value) - raise value + # + raise AssertionError("all cases should have been handled") jd._ll_portal_runner = ll_portal_runner # for debugging jd.portal_runner_ptr = self.helper_func(jd._PTR_PORTAL_FUNCTYPE, diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -2,7 +2,7 @@ import weakref from rpython.jit.codewriter import support, heaptracker, longlong -from rpython.jit.metainterp import resoperation, history +from rpython.jit.metainterp import resoperation, history, jitexc from rpython.rlib.debug import debug_start, debug_stop, debug_print from rpython.rlib.debug import have_debug_prints_for from rpython.rlib.jit import PARAMETERS @@ -348,8 +348,9 @@ def make_entry_point(self): "NOT_RPYTHON" - if hasattr(self, 'maybe_compile_and_run'): - return self.maybe_compile_and_run + from rpython.jit.metainterp import compile + if hasattr(self, 'entry_point_fns'): + return self.entry_point_fns warmrunnerdesc = self.warmrunnerdesc metainterp_sd = warmrunnerdesc.metainterp_sd @@ -362,6 +363,8 @@ confirm_enter_jit = self.confirm_enter_jit range_red_args = unrolling_iterable( range(num_green_args, num_green_args + jitdriver_sd.num_red_args)) + name_red_args = unrolling_iterable( + [(i, 'arg%d' % i) for i in range(jitdriver_sd.num_red_args)]) # get a new specialized copy of the method ARGS = [] for kind in jitdriver_sd.red_args_types: @@ -376,6 +379,7 @@ func_execute_token = self.cpu.make_execute_token(*ARGS) cpu = self.cpu jitcounter = self.warmrunnerdesc.jitcounter + result_type = jitdriver_sd.result_type def execute_assembler(loop_token, *args): # Call the backend to run the 'looptoken' with the given @@ -396,8 +400,23 @@ # # Handle the failure fail_descr = cpu.get_latest_descr(deadframe) + # First, a fast path to avoid raising and immediately catching + # a DoneWithThisFrame exception + if result_type == history.VOID: + if isinstance(fail_descr, compile.DoneWithThisFrameDescrVoid): + return None + if result_type == history.INT: + if isinstance(fail_descr, compile.DoneWithThisFrameDescrInt): + return fail_descr.get_result(cpu, deadframe) + if result_type == history.REF: + if isinstance(fail_descr, compile.DoneWithThisFrameDescrRef): + return fail_descr.get_result(cpu, deadframe) + if result_type == history.FLOAT: + if isinstance(fail_descr, compile.DoneWithThisFrameDescrFloat): + return fail_descr.get_result(cpu, deadframe) + # + # General case fail_descr.handle_fail(deadframe, metainterp_sd, jitdriver_sd) - # assert 0, "should have raised" def bound_reached(hash, cell, *args): @@ -419,7 +438,8 @@ def maybe_compile_and_run(increment_threshold, *args): """Entry point to the JIT. Called at the point with the - can_enter_jit() hint. + can_enter_jit() hint, and at the start of a function + with a different threshold. """ # Look for the cell corresponding to the current greenargs. # Search for the JitCell that is of the correct subclass of @@ -439,14 +459,6 @@ bound_reached(hash, None, *args) return - # Workaround for issue #2200, maybe temporary. This is not - # a proper fix, but only a hack that should work well enough - # for PyPy's main jitdriver... See test_issue2200_recursion - from rpython.jit.metainterp.blackhole import workaround2200 - if workaround2200.active: - workaround2200.active = False - return - # Here, we have found 'cell'. # if cell.flags & (JC_TRACING | JC_TEMPORARY): @@ -484,14 +496,27 @@ execute_args = () for i in range_red_args: execute_args += (unspecialize_value(args[i]), ) - # run it! this executes until interrupted by an exception - execute_assembler(procedure_token, *execute_args) - assert 0, "should not reach this point" + # run it, but from outside in ll_portal_runner, not from here + # (this avoids RPython-level recursion with no corresponding + # app-level recursion, as shown by issues 2200 and 2335) + raise EnterJitAssembler(procedure_token, *execute_args) + + class EnterJitAssembler(jitexc.JitException): + def __init__(self, procedure_token, *args): + self.procedure_token = procedure_token + for i, argname in name_red_args: + setattr(self, argname, args[i]) + def execute(self): + args = () + for i, argname in name_red_args: + args += (getattr(self, argname), ) + return execute_assembler(self.procedure_token, *args) maybe_compile_and_run._dont_inline_ = True - self.maybe_compile_and_run = maybe_compile_and_run self.execute_assembler = execute_assembler - return maybe_compile_and_run + self.entry_point_fns = (maybe_compile_and_run, + EnterJitAssembler) + return self.entry_point_fns # ---------- diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -593,11 +593,6 @@ HASH_MALLOC_SIZE = EVP_MD_SIZE + EVP_MD_CTX_SIZE \ + rffi.sizeof(EVP_MD) * 2 + 208 -OBJ_NAME_CALLBACK = lltype.Ptr(lltype.FuncType( - [OBJ_NAME, rffi.VOIDP], lltype.Void)) -OBJ_NAME_do_all = external( - 'OBJ_NAME_do_all', [rffi.INT, OBJ_NAME_CALLBACK, rffi.VOIDP], lltype.Void) - def init_ssl(): libssl_SSL_load_error_strings() libssl_SSL_library_init() diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -220,7 +220,7 @@ pass if _WIN32: - includes = ['io.h', 'sys/utime.h', 'sys/types.h'] + includes = ['io.h', 'sys/utime.h', 'sys/types.h', 'process.h'] libraries = [] else: if sys.platform.startswith(('darwin', 'netbsd', 'openbsd')): @@ -704,10 +704,10 @@ c_execve = external('execve', [rffi.CCHARP, rffi.CCHARPP, rffi.CCHARPP], rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO) -c_spawnv = external('spawnv', +c_spawnv = external(UNDERSCORE_ON_WIN32 + 'spawnv', [rffi.INT, rffi.CCHARP, rffi.CCHARPP], rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO) -c_spawnve = external('spawnve', +c_spawnve = external(UNDERSCORE_ON_WIN32 + 'spawnve', [rffi.INT, rffi.CCHARP, rffi.CCHARPP, rffi.CCHARPP], rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO) diff --git a/rpython/rlib/test/test_rsocket.py b/rpython/rlib/test/test_rsocket.py --- a/rpython/rlib/test/test_rsocket.py +++ b/rpython/rlib/test/test_rsocket.py @@ -313,8 +313,10 @@ assert isinstance(lst, list) found = False for family, socktype, protocol, canonname, addr in lst: - if addr.get_host() == '104.130.43.121': + if addr.get_host() in ('104.130.43.121', '23.253.135.79'): found = True + elif family == AF_INET: + print 'pydotorg changed to', addr.get_host() result[i] += found def test_getaddrinfo_pydotorg(): diff --git a/rpython/rtyper/lltypesystem/ll2ctypes.py b/rpython/rtyper/lltypesystem/ll2ctypes.py --- a/rpython/rtyper/lltypesystem/ll2ctypes.py +++ b/rpython/rtyper/lltypesystem/ll2ctypes.py @@ -171,10 +171,7 @@ _length_ = 2 @property def value(self): - if sys.byteorder == 'little': - res = self[0] | (self[1] << 64) - else: - res = self[1] | (self[0] << 64) + res = self[0] | (self[1] << 64) if res >= (1 << 127): res -= 1 << 128 return res _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit