Author: Richard Plangger <planri...@gmail.com> Branch: new-jit-log Changeset: r83262:3ad35c51e7c7 Date: 2016-03-22 17:10 +0100 http://bitbucket.org/pypy/pypy/changeset/3ad35c51e7c7/
Log: catchup with default diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -19,3 +19,4 @@ 850edf14b2c75573720f59e95767335fb1affe55 release-4.0.0 5f8302b8bf9f53056e40426f10c72151564e5b19 release-4.0.1 246c9cf22037b11dc0e8c29ce3f291d3b8c5935a release-5.0 +bbd45126bc691f669c4ebdfbd74456cd274c6b92 release-5.0.1 diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt --- a/pypy/doc/config/translation.gc.txt +++ b/pypy/doc/config/translation.gc.txt @@ -1,24 +1,26 @@ Choose the Garbage Collector used by the translated program. -The good performing collectors are "hybrid" and "minimark". -The default is "minimark". +The recommended default is "incminimark". - "ref": reference counting. Takes very long to translate and the result is - slow. + slow. Used only for tests. Don't use it for real RPython programs. - - "marksweep": naive mark & sweep. + - "none": no GC. Leaks everything. Don't use it for real RPython + programs: the rate of leaking is immense. - "semispace": a copying semi-space GC. - "generation": a generational GC using the semi-space GC for the older generation. - - "boehm": use the Boehm conservative GC. - - "hybrid": a hybrid collector of "generation" together with a mark-n-sweep old space - - "markcompact": a slow, but memory-efficient collector, - influenced e.g. by Smalltalk systems. + - "boehm": use the Boehm conservative GC. - "minimark": a generational mark-n-sweep collector with good performance. Includes page marking for large arrays. + + - "incminimark": like minimark, but adds incremental major + collections. Seems to come with no performance drawback over + "minimark", so it is the default. A few recent features of PyPy + (like cpyext) are only working with this GC. diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-5.0.1.rst release-5.0.0.rst release-4.0.1.rst release-4.0.0.rst diff --git a/pypy/doc/release-5.0.1.rst b/pypy/doc/release-5.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-5.0.1.rst @@ -0,0 +1,40 @@ +========== +PyPy 5.0.1 +========== + +We have released a bugfix for PyPy 5.0, after reports that the newly released +`lxml 3.6.0`_, which now supports PyPy 5.0 +, can `crash on large files`_. +Thanks to those who reported the crash. Please update, downloads are available +at pypy.org/download.html + +.. _`lxml 3.6.0`: https://pypi.python.org/pypi/lxml/3.6.0 +.. _`crash on large files`: https://bitbucket.org/pypy/pypy/issues/2260 + +The changes between PyPy 5.0 and 5.0.1 are only two bug fixes: one in +cpyext, which fixes notably (but not only) lxml; and another for a +corner case of the JIT. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`PyPy and CPython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD, FreeBSD), +newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux, and the +big- and little-endian variants of **PPC64** running Linux. + +.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org +.. _`dynamic languages`: http://pypyjs.org + +Please update, and continue to help us make PyPy better. + +Cheers + +The PyPy Team + diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -327,7 +327,7 @@ # XXX possibly adapt options using modules failures = create_cffi_import_libraries(exename, options, basedir) # if failures, they were already printed - print >> sys.stderr, str(exename),'successfully built, but errors while building the above modules will be ignored' + print >> sys.stderr, str(exename),'successfully built (errors, if any, while building the above modules are ignored)' driver.task_build_cffi_imports = types.MethodType(task_build_cffi_imports, driver) driver.tasks['build_cffi_imports'] = driver.task_build_cffi_imports, [compile_goal] driver.default_goal = 'build_cffi_imports' diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -417,7 +417,10 @@ self.wait_for_thread_shutdown() w_exitfunc = self.sys.getdictvalue(self, 'exitfunc') if w_exitfunc is not None: - self.call_function(w_exitfunc) + try: + self.call_function(w_exitfunc) + except OperationError as e: + e.write_unraisable(self, 'sys.exitfunc == ', w_exitfunc) from pypy.interpreter.module import Module for w_mod in self.builtin_modules.values(): if isinstance(w_mod, Module) and w_mod.startup_called: diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py --- a/pypy/interpreter/test/test_objspace.py +++ b/pypy/interpreter/test/test_objspace.py @@ -416,3 +416,14 @@ i -= 1 assert i >= 0 gc.collect() + + def test_exitfunc_catches_exceptions(self): + from pypy.tool.pytest.objspace import maketestobjspace + space = maketestobjspace() + space.appexec([], """(): + import sys + sys.exitfunc = lambda: this_is_an_unknown_name + """) + space.finish() + # assert that we reach this point without getting interrupted + # by the OperationError(NameError) diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -124,7 +124,7 @@ s = rffi.charp2str(ptr) else: s = rffi.charp2strn(ptr, length) - return space.wrap(s) + return space.wrapbytes(s) # # pointer to a wchar_t: builds and returns a unicode if self.is_unichar_ptr_or_array(): @@ -372,15 +372,15 @@ rffi_fclose(self.llf) -def prepare_file_argument(space, fileobj): - fileobj.direct_flush() - if fileobj.cffi_fileobj is None: - fd = fileobj.direct_fileno() +def prepare_file_argument(space, w_fileobj): + w_fileobj.direct_flush() + if w_fileobj.cffi_fileobj is None: + fd = w_fileobj.direct_fileno() if fd < 0: raise OperationError(space.w_ValueError, space.wrap("file has no OS file descriptor")) try: - fileobj.cffi_fileobj = CffiFileObj(fd, fileobj.mode) + w_fileobj.cffi_fileobj = CffiFileObj(fd, w_fileobj.mode) except OSError, e: raise wrap_oserror(space, e) - return rffi.cast(rffi.CCHARP, fileobj.cffi_fileobj.llf) + return rffi.cast(rffi.CCHARP, w_fileobj.cffi_fileobj.llf) diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -833,14 +833,14 @@ modulename = py.path.local(eci.libraries[-1]) def dealloc_trigger(): - from pypy.module.cpyext.pyobject import _Py_Dealloc + from pypy.module.cpyext.pyobject import decref print 'dealloc_trigger...' while True: ob = rawrefcount.next_dead(PyObject) if not ob: break print ob - _Py_Dealloc(space, ob) + decref(space, ob) print 'dealloc_trigger DONE' return "RETRY" rawrefcount.init(dealloc_trigger) diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py --- a/pypy/module/cpyext/bytesobject.py +++ b/pypy/module/cpyext/bytesobject.py @@ -1,4 +1,4 @@ -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, oefmt from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( cpython_api, cpython_struct, bootstrap_function, build_type_checkers, @@ -80,7 +80,8 @@ buflen = length + 1 py_str.c_size = length py_str.c_buffer = lltype.malloc(rffi.CCHARP.TO, buflen, - flavor='raw', zero=True) + flavor='raw', zero=True, + add_memory_pressure=True) return py_str def string_attach(space, py_obj, w_obj): @@ -133,8 +134,14 @@ if from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.w_str: pass # typecheck returned "ok" without forcing 'ref' at all elif not PyString_Check(space, ref): # otherwise, use the alternate way - raise OperationError(space.w_TypeError, space.wrap( - "PyString_AsString only support strings")) + from pypy.module.cpyext.unicodeobject import ( + PyUnicode_Check, _PyUnicode_AsDefaultEncodedString) + if PyUnicode_Check(space, ref): + ref = _PyUnicode_AsDefaultEncodedString(space, ref, lltype.nullptr(rffi.CCHARP.TO)) + else: + raise oefmt(space.w_TypeError, + "expected string or Unicode object, %T found", + from_ref(space, ref)) ref_str = rffi.cast(PyStringObject, ref) if not ref_str.c_buffer: # copy string buffer @@ -146,8 +153,14 @@ @cpython_api([PyObject, rffi.CCHARPP, rffi.CArrayPtr(Py_ssize_t)], rffi.INT_real, error=-1) def PyString_AsStringAndSize(space, ref, buffer, length): if not PyString_Check(space, ref): - raise OperationError(space.w_TypeError, space.wrap( - "PyString_AsStringAndSize only support strings")) + from pypy.module.cpyext.unicodeobject import ( + PyUnicode_Check, _PyUnicode_AsDefaultEncodedString) + if PyUnicode_Check(space, ref): + ref = _PyUnicode_AsDefaultEncodedString(space, ref, lltype.nullptr(rffi.CCHARP.TO)) + else: + raise oefmt(space.w_TypeError, + "expected string or Unicode object, %T found", + from_ref(space, ref)) ref_str = rffi.cast(PyStringObject, ref) if not ref_str.c_buffer: # copy string buffer diff --git a/pypy/module/cpyext/include/unicodeobject.h b/pypy/module/cpyext/include/unicodeobject.h --- a/pypy/module/cpyext/include/unicodeobject.h +++ b/pypy/module/cpyext/include/unicodeobject.h @@ -20,8 +20,12 @@ typedef struct { PyObject_HEAD - Py_UNICODE *buffer; + Py_UNICODE *str; Py_ssize_t size; + long hash; /* Hash value; -1 if not set */ + PyObject *defenc; /* (Default) Encoded version as Python + string, or NULL; this is used for + implementing the buffer protocol */ } PyUnicodeObject; diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py --- a/pypy/module/cpyext/object.py +++ b/pypy/module/cpyext/object.py @@ -17,7 +17,8 @@ @cpython_api([Py_ssize_t], rffi.VOIDP) def PyObject_MALLOC(space, size): return lltype.malloc(rffi.VOIDP.TO, size, - flavor='raw', zero=True) + flavor='raw', zero=True, + add_memory_pressure=True) @cpython_api([rffi.VOIDP], lltype.Void) def PyObject_FREE(space, ptr): diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py --- a/pypy/module/cpyext/pyobject.py +++ b/pypy/module/cpyext/pyobject.py @@ -50,7 +50,8 @@ size += itemcount * pytype.c_tp_itemsize assert size >= rffi.sizeof(PyObject.TO) buf = lltype.malloc(rffi.VOIDP.TO, size, - flavor='raw', zero=True) + flavor='raw', zero=True, + add_memory_pressure=True) pyobj = rffi.cast(PyObject, buf) pyobj.c_ob_refcnt = 1 pyobj.c_ob_type = pytype diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py --- a/pypy/module/cpyext/state.py +++ b/pypy/module/cpyext/state.py @@ -147,10 +147,10 @@ """ def perform(self, executioncontext, frame): - from pypy.module.cpyext.pyobject import PyObject, _Py_Dealloc + from pypy.module.cpyext.pyobject import PyObject, decref while True: py_obj = rawrefcount.next_dead(PyObject) if not py_obj: break - _Py_Dealloc(self.space, py_obj) + decref(self.space, py_obj) 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 @@ -139,6 +139,44 @@ ]) module.getstring() + def test_py_string_as_string_Unicode(self): + module = self.import_extension('foo', [ + ("getstring_unicode", "METH_NOARGS", + """ + Py_UNICODE chars[] = {'t', 'e', 's', 't'}; + PyObject* u1 = PyUnicode_FromUnicode(chars, 4); + char *buf; + buf = PyString_AsString(u1); + if (buf == NULL) + return NULL; + if (buf[3] != 't') { + PyErr_SetString(PyExc_AssertionError, "Bad conversion"); + return NULL; + } + Py_DECREF(u1); + Py_INCREF(Py_None); + return Py_None; + """), + ("getstringandsize_unicode", "METH_NOARGS", + """ + Py_UNICODE chars[] = {'t', 'e', 's', 't'}; + PyObject* u1 = PyUnicode_FromUnicode(chars, 4); + char *buf; + Py_ssize_t len; + if (PyString_AsStringAndSize(u1, &buf, &len) < 0) + return NULL; + if (len != 4) { + PyErr_SetString(PyExc_AssertionError, "Bad Length"); + return NULL; + } + Py_DECREF(u1); + Py_INCREF(Py_None); + return Py_None; + """), + ]) + module.getstring_unicode() + module.getstringandsize_unicode() + def test_format_v(self): module = self.import_extension('foo', [ ("test_string_format_v", "METH_VARARGS", diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -24,7 +24,7 @@ if(PyUnicode_GetSize(s) == 11) { result = 1; } - if(s->ob_type->tp_basicsize != sizeof(void*)*5) + if(s->ob_type->tp_basicsize != sizeof(void*)*7) result = 0; Py_DECREF(s); return PyBool_FromLong(result); @@ -66,6 +66,7 @@ c = PyUnicode_AsUnicode(s); c[0] = 'a'; c[1] = 0xe9; + c[2] = 0x00; c[3] = 'c'; return s; """), @@ -74,7 +75,35 @@ assert len(s) == 4 assert s == u'a�\x00c' + def test_hash(self): + module = self.import_extension('foo', [ + ("test_hash", "METH_VARARGS", + ''' + PyObject* obj = (PyTuple_GetItem(args, 0)); + long hash = ((PyUnicodeObject*)obj)->hash; + return PyLong_FromLong(hash); + ''' + ), + ]) + res = module.test_hash(u"xyz") + assert res == hash(u'xyz') + def test_default_encoded_string(self): + module = self.import_extension('foo', [ + ("test_default_encoded_string", "METH_O", + ''' + PyObject* result = _PyUnicode_AsDefaultEncodedString(args, "replace"); + Py_INCREF(result); + return result; + ''' + ), + ]) + res = module.test_default_encoded_string(u"xyz") + assert isinstance(res, str) + assert res == 'xyz' + res = module.test_default_encoded_string(u"caf\xe9") + assert isinstance(res, str) + assert res == 'caf?' class TestUnicode(BaseApiTest): def test_unicodeobject(self, space, api): @@ -155,22 +184,22 @@ def test_unicode_resize(self, space, api): py_uni = new_empty_unicode(space, 10) ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw') - py_uni.c_buffer[0] = u'a' - py_uni.c_buffer[1] = u'b' - py_uni.c_buffer[2] = u'c' + py_uni.c_str[0] = u'a' + py_uni.c_str[1] = u'b' + py_uni.c_str[2] = u'c' ar[0] = rffi.cast(PyObject, py_uni) api.PyUnicode_Resize(ar, 3) py_uni = rffi.cast(PyUnicodeObject, ar[0]) assert py_uni.c_size == 3 - assert py_uni.c_buffer[1] == u'b' - assert py_uni.c_buffer[3] == u'\x00' + assert py_uni.c_str[1] == u'b' + assert py_uni.c_str[3] == u'\x00' # the same for growing ar[0] = rffi.cast(PyObject, py_uni) api.PyUnicode_Resize(ar, 10) py_uni = rffi.cast(PyUnicodeObject, ar[0]) assert py_uni.c_size == 10 - assert py_uni.c_buffer[1] == 'b' - assert py_uni.c_buffer[10] == '\x00' + assert py_uni.c_str[1] == 'b' + assert py_uni.c_str[10] == '\x00' Py_DecRef(space, ar[0]) lltype.free(ar, flavor='raw') diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py --- a/pypy/module/cpyext/tupleobject.py +++ b/pypy/module/cpyext/tupleobject.py @@ -59,7 +59,8 @@ py_tup = rffi.cast(PyTupleObject, py_obj) py_tup.c_ob_item = lltype.malloc(ObjectItems, length, - flavor='raw', zero=True) + flavor='raw', zero=True, + add_memory_pressure=True) py_tup.c_ob_size = length return py_tup @@ -70,7 +71,8 @@ """ items_w = space.fixedview(w_obj) l = len(items_w) - p = lltype.malloc(ObjectItems, l, flavor='raw') + p = lltype.malloc(ObjectItems, l, flavor='raw', + add_memory_pressure=True) i = 0 try: while i < l: @@ -177,7 +179,8 @@ ref = rffi.cast(PyTupleObject, ref) oldsize = ref.c_ob_size oldp = ref.c_ob_item - newp = lltype.malloc(ObjectItems, newsize, zero=True, flavor='raw') + newp = lltype.malloc(ObjectItems, newsize, zero=True, flavor='raw', + add_memory_pressure=True) try: if oldsize < newsize: to_cp = oldsize diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -421,7 +421,8 @@ Py_DecRef(space, w_metatype) heaptype = lltype.malloc(PyHeapTypeObject.TO, - flavor='raw', zero=True) + flavor='raw', zero=True, + add_memory_pressure=True) pto = heaptype.c_ht_type pto.c_ob_refcnt = 1 pto.c_ob_type = metatype diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -22,7 +22,8 @@ PyUnicodeObjectStruct = lltype.ForwardReference() PyUnicodeObject = lltype.Ptr(PyUnicodeObjectStruct) PyUnicodeObjectFields = (PyObjectFields + - (("buffer", rffi.CWCHARP), ("size", Py_ssize_t))) + (("str", rffi.CWCHARP), ("size", Py_ssize_t), + ("hash", rffi.LONG), ("defenc", PyObject))) cpython_struct("PyUnicodeObject", PyUnicodeObjectFields, PyUnicodeObjectStruct) @bootstrap_function @@ -54,15 +55,20 @@ buflen = length + 1 py_uni.c_size = length - py_uni.c_buffer = lltype.malloc(rffi.CWCHARP.TO, buflen, - flavor='raw', zero=True) + py_uni.c_str = lltype.malloc(rffi.CWCHARP.TO, buflen, + flavor='raw', zero=True, + add_memory_pressure=True) + py_uni.c_hash = -1 + py_uni.c_defenc = lltype.nullptr(PyObject.TO) return py_uni def unicode_attach(space, py_obj, w_obj): "Fills a newly allocated PyUnicodeObject with a unicode string" py_unicode = rffi.cast(PyUnicodeObject, py_obj) py_unicode.c_size = len(space.unicode_w(w_obj)) - py_unicode.c_buffer = lltype.nullptr(rffi.CWCHARP.TO) + py_unicode.c_str = lltype.nullptr(rffi.CWCHARP.TO) + py_unicode.c_hash = space.hash_w(w_obj) + py_unicode.c_defenc = lltype.nullptr(PyObject.TO) def unicode_realize(space, py_obj): """ @@ -70,17 +76,20 @@ be modified after this call. """ py_uni = rffi.cast(PyUnicodeObject, py_obj) - s = rffi.wcharpsize2unicode(py_uni.c_buffer, py_uni.c_size) + s = rffi.wcharpsize2unicode(py_uni.c_str, py_uni.c_size) w_obj = space.wrap(s) + py_uni.c_hash = space.hash_w(w_obj) track_reference(space, py_obj, w_obj) return w_obj @cpython_api([PyObject], lltype.Void, header=None) def unicode_dealloc(space, py_obj): py_unicode = rffi.cast(PyUnicodeObject, py_obj) - if py_unicode.c_buffer: - lltype.free(py_unicode.c_buffer, flavor="raw") + if py_unicode.c_str: + lltype.free(py_unicode.c_str, flavor="raw") from pypy.module.cpyext.object import PyObject_dealloc + if py_unicode.c_defenc: + PyObject_dealloc(space, py_unicode.c_defenc) PyObject_dealloc(space, py_obj) @cpython_api([Py_UNICODE], rffi.INT_real, error=CANNOT_FAIL) @@ -204,12 +213,12 @@ """Return a pointer to the internal Py_UNICODE buffer of the object. ref has to be a PyUnicodeObject (not checked).""" ref_unicode = rffi.cast(PyUnicodeObject, ref) - if not ref_unicode.c_buffer: + if not ref_unicode.c_str: # Copy unicode buffer w_unicode = from_ref(space, ref) u = space.unicode_w(w_unicode) - ref_unicode.c_buffer = rffi.unicode2wcharp(u) - return ref_unicode.c_buffer + ref_unicode.c_str = rffi.unicode2wcharp(u) + return ref_unicode.c_str @cpython_api([PyObject], rffi.CWCHARP) def PyUnicode_AsUnicode(space, ref): @@ -240,7 +249,7 @@ string may or may not be 0-terminated. It is the responsibility of the caller to make sure that the wchar_t string is 0-terminated in case this is required by the application.""" - c_buffer = PyUnicode_AS_UNICODE(space, rffi.cast(PyObject, ref)) + c_str = PyUnicode_AS_UNICODE(space, rffi.cast(PyObject, ref)) c_size = ref.c_size # If possible, try to copy the 0-termination as well @@ -250,7 +259,7 @@ i = 0 while i < size: - buf[i] = c_buffer[i] + buf[i] = c_str[i] i += 1 if size > c_size: @@ -342,8 +351,15 @@ return PyUnicode_FromUnicode(space, wchar_p, length) @cpython_api([PyObject, CONST_STRING], PyObject) -def _PyUnicode_AsDefaultEncodedString(space, w_unicode, errors): - return PyUnicode_AsEncodedString(space, w_unicode, lltype.nullptr(rffi.CCHARP.TO), errors) +def _PyUnicode_AsDefaultEncodedString(space, ref, errors): + # Returns a borrowed reference. + py_uni = rffi.cast(PyUnicodeObject, ref) + if not py_uni.c_defenc: + py_uni.c_defenc = make_ref( + space, PyUnicode_AsEncodedString( + space, ref, + lltype.nullptr(rffi.CCHARP.TO), errors)) + return py_uni.c_defenc @cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING, CONST_STRING], PyObject) def PyUnicode_Decode(space, s, size, encoding, errors): @@ -443,7 +459,7 @@ def PyUnicode_Resize(space, ref, newsize): # XXX always create a new string so far py_uni = rffi.cast(PyUnicodeObject, ref[0]) - if not py_uni.c_buffer: + if not py_uni.c_str: raise OperationError(space.w_SystemError, space.wrap( "PyUnicode_Resize called on already created string")) try: @@ -457,7 +473,7 @@ if oldsize < newsize: to_cp = oldsize for i in range(to_cp): - py_newuni.c_buffer[i] = py_uni.c_buffer[i] + py_newuni.c_str[i] = py_uni.c_str[i] Py_DecRef(space, ref[0]) ref[0] = rffi.cast(PyObject, py_newuni) return 0 diff --git a/pypy/module/select/test/test_select.py b/pypy/module/select/test/test_select.py --- a/pypy/module/select/test/test_select.py +++ b/pypy/module/select/test/test_select.py @@ -287,8 +287,7 @@ t = thread.start_new_thread(pollster.poll, ()) try: time.sleep(0.3) - # TODO restore print '', if this is not the reason - for i in range(5): print 'release gil select' # to release GIL untranslated + for i in range(5): print '', # to release GIL untranslated # trigger ufds array reallocation for fd in rfds: pollster.unregister(fd) diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh --- a/pypy/tool/release/repackage.sh +++ b/pypy/tool/release/repackage.sh @@ -1,9 +1,9 @@ # Edit these appropriately before running this script maj=5 min=0 -rev=0 +rev=1 branchname=release-$maj.x # ==OR== release-$maj.$min.x -tagname=release-$maj.$min # ==OR== release-$maj.$min.$rev +tagname=release-$maj.$min.$rev # This script will download latest builds from the buildmaster, rename the top # level directory, and repackage ready to be uploaded to bitbucket. It will also # download source, assuming a tag for the release already exists, and repackage them. diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -66,6 +66,7 @@ 'x86_64': MODEL_X86, 'amd64': MODEL_X86, # freebsd 'AMD64': MODEL_X86, # win64 + 'armv8l': MODEL_ARM, # 32-bit ARMv8 'armv7l': MODEL_ARM, 'armv6l': MODEL_ARM, 'arm': MODEL_ARM, # freebsd diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -784,11 +784,13 @@ return [] # check for _immutable_fields_ hints immut = v_inst.concretetype.TO._immutable_field(c_fieldname.value) + need_live = False if immut: if (self.callcontrol is not None and self.callcontrol.could_be_green_field(v_inst.concretetype.TO, c_fieldname.value)): pure = '_greenfield' + need_live = True else: pure = '_pure' else: @@ -815,10 +817,12 @@ descr1 = self.cpu.fielddescrof( v_inst.concretetype.TO, quasiimmut.get_mutate_field_name(c_fieldname.value)) - op1 = [SpaceOperation('-live-', [], None), + return [SpaceOperation('-live-', [], None), SpaceOperation('record_quasiimmut_field', [v_inst, descr, descr1], None), op1] + if need_live: + return [SpaceOperation('-live-', [], None), op1] return op1 def rewrite_op_setfield(self, op, override_type=None): diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py --- a/rpython/jit/codewriter/test/test_jtransform.py +++ b/rpython/jit/codewriter/test/test_jtransform.py @@ -1012,7 +1012,8 @@ v1 = varoftype(lltype.Ptr(S)) v2 = varoftype(lltype.Char) op = SpaceOperation('getfield', [v1, Constant('x', lltype.Void)], v2) - op1 = Transformer(FakeCPU(), FakeCC()).rewrite_operation(op) + op0, op1 = Transformer(FakeCPU(), FakeCC()).rewrite_operation(op) + assert op0.opname == '-live-' assert op1.opname == 'getfield_gc_i_greenfield' assert op1.args == [v1, ('fielddescr', S, 'x')] assert op1.result == v2 diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py --- a/rpython/memory/gc/incminimark.py +++ b/rpython/memory/gc/incminimark.py @@ -2929,10 +2929,19 @@ ll_assert(rc < int(REFCNT_FROM_PYPY_LIGHT * 0.99), "refcount underflow from REFCNT_FROM_PYPY_LIGHT?") rc -= REFCNT_FROM_PYPY - self._pyobj(pyobject).ob_refcnt = rc self._pyobj(pyobject).ob_pypy_link = 0 if rc == 0: self.rrc_dealloc_pending.append(pyobject) + # an object with refcnt == 0 cannot stay around waiting + # for its deallocator to be called. Some code (lxml) + # expects that tp_dealloc is called immediately when + # the refcnt drops to 0. If it isn't, we get some + # uncleared raw pointer that can still be used to access + # the object; but (PyObject *)raw_pointer is then bogus + # because after a Py_INCREF()/Py_DECREF() on it, its + # tp_dealloc is also called! + rc = 1 + self._pyobj(pyobject).ob_refcnt = rc _rrc_free._always_inline_ = True def rrc_major_collection_trace(self): diff --git a/rpython/memory/gc/test/test_rawrefcount.py b/rpython/memory/gc/test/test_rawrefcount.py --- a/rpython/memory/gc/test/test_rawrefcount.py +++ b/rpython/memory/gc/test/test_rawrefcount.py @@ -174,7 +174,7 @@ p1 = check_alive(0) self._collect(major=True, expected_trigger=1) py.test.raises(RuntimeError, "p1.x") # dead - assert r1.ob_refcnt == 0 + assert r1.ob_refcnt == 1 # in the pending list assert r1.ob_pypy_link == 0 assert self.gc.rawrefcount_next_dead() == r1addr assert self.gc.rawrefcount_next_dead() == llmemory.NULL @@ -197,7 +197,7 @@ assert p1.x == 42 self._collect(major=True, expected_trigger=1) py.test.raises(RuntimeError, "p1.x") # dead - assert r1.ob_refcnt == 0 + assert r1.ob_refcnt == 1 assert r1.ob_pypy_link == 0 assert self.gc.rawrefcount_next_dead() == r1addr self.gc.check_no_more_rawrefcount_state() @@ -214,7 +214,7 @@ else: self._collect(major=False, expected_trigger=1) py.test.raises(RuntimeError, "p1.x") # dead - assert r1.ob_refcnt == 0 + assert r1.ob_refcnt == 1 assert r1.ob_pypy_link == 0 assert self.gc.rawrefcount_next_dead() == r1addr self.gc.check_no_more_rawrefcount_state() @@ -252,7 +252,7 @@ self._collect(major=True, expected_trigger=1) else: self._collect(major=False, expected_trigger=1) - assert r1.ob_refcnt == 0 # refcnt dropped to 0 + assert r1.ob_refcnt == 1 # refcnt 1, in the pending list assert r1.ob_pypy_link == 0 # detached assert self.gc.rawrefcount_next_dead() == r1addr self.gc.check_no_more_rawrefcount_state() @@ -277,7 +277,7 @@ assert self.trigger == [] self._collect(major=True, expected_trigger=1) py.test.raises(RuntimeError, "p1.x") # dead - assert r1.ob_refcnt == 0 + assert r1.ob_refcnt == 1 assert r1.ob_pypy_link == 0 assert self.gc.rawrefcount_next_dead() == r1addr self.gc.check_no_more_rawrefcount_state() diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py --- a/rpython/rlib/rawrefcount.py +++ b/rpython/rlib/rawrefcount.py @@ -72,6 +72,12 @@ return p def next_dead(OB_PTR_TYPE): + """NOT_RPYTHON. When the GC runs, it finds some pyobjs to be dead + but cannot immediately dispose of them (it doesn't know how to call + e.g. tp_dealloc(), and anyway calling it immediately would cause all + sorts of bugs). So instead, it stores them in an internal list, + initially with refcnt == 1. This pops the next item off this list. + """ if len(_d_list) == 0: return lltype.nullptr(OB_PTR_TYPE.TO) ob = _d_list.pop() @@ -136,6 +142,7 @@ ob.c_ob_refcnt -= REFCNT_FROM_PYPY ob.c_ob_pypy_link = 0 if ob.c_ob_refcnt == 0: + ob.c_ob_refcnt = 1 _d_list.append(ob) return None diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -22,6 +22,22 @@ from rpython.rlib import rwin32 from rpython.rlib.rwin32file import make_win32_traits +class CConfig: + _compilation_info_ = ExternalCompilationInfo( + includes=['sys/stat.h', + 'unistd.h', + 'fcntl.h'], + ) + for _name in """fchdir fchmod fchmodat fchown fchownat fexecve fdopendir + fpathconf fstat fstatat fstatvfs ftruncate futimens futimes + futimesat linkat lchflags lchmod lchown lstat lutimes + mkdirat mkfifoat mknodat openat readlinkat renameat + symlinkat unlinkat utimensat""".split(): + locals()['HAVE_%s' % _name.upper()] = rffi_platform.Has(_name) +cConfig = rffi_platform.configure(CConfig) +globals().update(cConfig) + + class CConstantErrno(CConstant): # these accessors are used when calling get_errno() or set_errno() # on top of CPython @@ -1024,6 +1040,13 @@ if not win32traits.MoveFile(path1, path2): raise rwin32.lastSavedWindowsError() +@specialize.argtype(0, 1) +def replace(path1, path2): + if os.name == 'nt': + raise NotImplementedError( + 'On windows, os.replace() should overwrite the destination') + return rename(path1, path2) + #___________________________________________________________________ c_mkfifo = external('mkfifo', [rffi.CCHARP, rffi.MODE_T], rffi.INT, diff --git a/rpython/rlib/rtime.py b/rpython/rlib/rtime.py --- a/rpython/rlib/rtime.py +++ b/rpython/rlib/rtime.py @@ -9,7 +9,6 @@ from rpython.rtyper.tool import rffi_platform from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.objectmodel import register_replacement_for -from rpython.rlib import jit from rpython.rlib.rarithmetic import intmask, UINT_MAX from rpython.rlib import rposix @@ -170,28 +169,30 @@ [lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT, releasegil=False, compilation_info=eci_with_lrt) -else: +if need_rusage: RUSAGE = RUSAGE RUSAGE_SELF = RUSAGE_SELF or 0 c_getrusage = external('getrusage', [rffi.INT, lltype.Ptr(RUSAGE)], - lltype.Void, + rffi.INT, releasegil=False) +def win_perf_counter(): + a = lltype.malloc(A, flavor='raw') + if state.divisor == 0.0: + QueryPerformanceCounter(a) + state.counter_start = a[0] + QueryPerformanceFrequency(a) + state.divisor = float(a[0]) + QueryPerformanceCounter(a) + diff = a[0] - state.counter_start + lltype.free(a, flavor='raw') + return float(diff) / state.divisor + @replace_time_function('clock') -@jit.dont_look_inside # the JIT doesn't like FixedSizeArray def clock(): if _WIN32: - a = lltype.malloc(A, flavor='raw') - if state.divisor == 0.0: - QueryPerformanceCounter(a) - state.counter_start = a[0] - QueryPerformanceFrequency(a) - state.divisor = float(a[0]) - QueryPerformanceCounter(a) - diff = a[0] - state.counter_start - lltype.free(a, flavor='raw') - return float(diff) / state.divisor + return win_perf_counter() elif CLOCK_PROCESS_CPUTIME_ID is not None: with lltype.scoped_alloc(TIMESPEC) as a: c_clock_gettime(CLOCK_PROCESS_CPUTIME_ID, a) diff --git a/rpython/rlib/rvmprof/src/vmprof_config.h b/rpython/rlib/rvmprof/src/vmprof_config.h --- a/rpython/rlib/rvmprof/src/vmprof_config.h +++ b/rpython/rlib/rvmprof/src/vmprof_config.h @@ -1,6 +1,10 @@ #define HAVE_SYS_UCONTEXT_H -#if defined(__FreeBSD__) -#define PC_FROM_UCONTEXT uc_mcontext.mc_rip +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + #ifdef __i386__ + #define PC_FROM_UCONTEXT uc_mcontext.mc_eip + #else + #define PC_FROM_UCONTEXT uc_mcontext.mc_rip + #endif #elif defined( __APPLE__) #if ((ULONG_MAX) == (UINT_MAX)) #define PC_FROM_UCONTEXT uc_mcontext->__ss.__eip @@ -8,10 +12,10 @@ #define PC_FROM_UCONTEXT uc_mcontext->__ss.__rip #endif #elif defined(__arm__) -#define PC_FROM_UCONTEXT uc_mcontext.arm_ip + #define PC_FROM_UCONTEXT uc_mcontext.arm_ip #elif defined(__linux) && defined(__i386) && defined(__GNUC__) -#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP] + #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP] #else -/* linux, gnuc */ -#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP] + /* linux, gnuc */ + #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP] #endif diff --git a/rpython/rlib/test/test_rawrefcount.py b/rpython/rlib/test/test_rawrefcount.py --- a/rpython/rlib/test/test_rawrefcount.py +++ b/rpython/rlib/test/test_rawrefcount.py @@ -116,7 +116,7 @@ assert rawrefcount.next_dead(PyObject) == lltype.nullptr(PyObjectS) assert rawrefcount._o_list == [] assert wr_p() is None - assert ob.c_ob_refcnt == 0 + assert ob.c_ob_refcnt == 1 # from the pending list assert ob.c_ob_pypy_link == 0 lltype.free(ob, flavor='raw') @@ -173,7 +173,7 @@ assert rawrefcount._d_list == [ob] assert rawrefcount._p_list == [] assert wr_p() is None - assert ob.c_ob_refcnt == 0 + assert ob.c_ob_refcnt == 1 # from _d_list assert ob.c_ob_pypy_link == 0 lltype.free(ob, flavor='raw') diff --git a/rpython/tool/runsubprocess.py b/rpython/tool/runsubprocess.py --- a/rpython/tool/runsubprocess.py +++ b/rpython/tool/runsubprocess.py @@ -20,6 +20,8 @@ def _run(executable, args, env, cwd): # note that this function can be *overridden* below # in some cases! + if sys.platform == 'win32': + executable = executable.replace('/','\\') if isinstance(args, str): args = str(executable) + ' ' + args shell = True diff --git a/rpython/translator/c/src/thread_pthread.c b/rpython/translator/c/src/thread_pthread.c --- a/rpython/translator/c/src/thread_pthread.c +++ b/rpython/translator/c/src/thread_pthread.c @@ -37,7 +37,7 @@ # define THREAD_STACK_SIZE 0 /* use default stack size */ # endif -# if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 +# if (defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 /* The default stack size for new threads on OSX is small enough that * we'll get hard crashes instead of 'maximum recursion depth exceeded' * exceptions. @@ -84,7 +84,7 @@ if (tss != 0) pthread_attr_setstacksize(&attrs, tss); #endif -#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) && !defined(__FreeBSD__) +#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) && !(defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); #endif _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit