Author: Philip Jenvey <pjen...@underboss.org> Branch: py3k Changeset: r65675:c8db1997988c Date: 2013-07-25 16:40 -0700 http://bitbucket.org/pypy/pypy/changeset/c8db1997988c/
Log: merge default diff --git a/lib-python/2.7/test/test_os.py b/lib-python/2.7/test/test_os.py --- a/lib-python/2.7/test/test_os.py +++ b/lib-python/2.7/test/test_os.py @@ -275,7 +275,7 @@ try: result.f_bfree = 1 self.fail("No exception thrown") - except TypeError: + except (TypeError, AttributeError): pass try: diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -626,7 +626,7 @@ Here is the order in which PyPy looks up Python modules: -*pypy/modules* +*pypy/module* mixed interpreter/app-level builtin modules, such as the ``sys`` and ``__builtin__`` module. @@ -657,7 +657,7 @@ on some classes being old-style. We just maintain those changes in place, -to see what is changed we have a branch called `vendot/stdlib` +to see what is changed we have a branch called `vendor/stdlib` wich contains the unmodified cpython stdlib .. _`mixed module mechanism`: diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -30,7 +30,7 @@ * update README * change the tracker to have a new release tag to file bugs against * go to pypy/tool/release and run: - force-builds.py /release/<release branch> + force-builds.py <release branch> * wait for builds to complete, make sure there are no failures * upload binaries to https://bitbucket.org/pypy/pypy/downloads diff --git a/pypy/doc/release-2.1.0-beta2.rst b/pypy/doc/release-2.1.0-beta2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.1.0-beta2.rst @@ -0,0 +1,62 @@ +=============== +PyPy 2.1 beta 2 +=============== + +We're pleased to announce the second beta of the upcoming 2.1 release of PyPy. +This beta adds one new feature to the 2.1 release and contains several bugfixes listed below. + +Highlights +========== + +* Support for os.statvfs and os.fstatvfs on unix systems. + +* Fixed issue `1533`_: fix an RPython-level OverflowError for space.float_w(w_big_long_number). + +* Fixed issue `1552`_: GreenletExit should inherit from BaseException. + +* Fixed issue `1537`_: numpypy __array_interface__ + +* Fixed issue `1238`_: Writing to an SSL socket in pypy sometimes failed with a "bad write retry" message. + +* `distutils`_: copy CPython's implementation of customize_compiler, dont call + split on environment variables, honour CFLAGS, CPPFLAGS, LDSHARED and + LDFLAGS. + +* During packaging, compile the CFFI tk extension. + +.. _`1533`: https://bugs.pypy.org/issue1533 +.. _`1552`: https://bugs.pypy.org/issue1552 +.. _`1537`: https://bugs.pypy.org/issue1537 +.. _`1238`: https://bugs.pypy.org/issue1238 +.. _`distutils`: https://bitbucket.org/pypy/pypy/src/0c6eeae0316c11146f47fcf83e21e24f11378be1/?at=distutils-cppldflags + + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7.3. It's fast due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or Windows +32. Also this release supports ARM machines running Linux 32bit - anything with +``ARMv6`` (like the Raspberry Pi) or ``ARMv7`` (like Beagleboard, +Chromebook, Cubieboard, etc.) that supports ``VFPv3`` should work. + +Windows 64 work is still stalling, we would welcome a volunteer +to handle that. + +How to use PyPy? +================ + +We suggest using PyPy from a `virtualenv`_. Once you have a virtualenv +installed, you can follow instructions from `pypy documentation`_ on how +to proceed. This document also covers other `installation schemes`_. + +.. _`pypy documentation`: http://doc.pypy.org/en/latest/getting-started.html#installing-using-virtualenv +.. _`virtualenv`: http://www.virtualenv.org/en/latest/ +.. _`installation schemes`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy +.. _`PyPy and pip`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy + + +Cheers, +The PyPy Team. diff --git a/pypy/doc/rffi.rst b/pypy/doc/rffi.rst --- a/pypy/doc/rffi.rst +++ b/pypy/doc/rffi.rst @@ -43,7 +43,7 @@ See cbuild_ for more info on ExternalCompilationInfo. .. _`low level types`: rtyper.html#low-level-type -.. _cbuild: https://bitbucket.org/pypy/pypy/src/tip/pypy/translator/tool/cbuild.py +.. _cbuild: https://bitbucket.org/pypy/pypy/src/tip/rpython/translator/tool/cbuild.py Types @@ -69,9 +69,3 @@ as a fake low-level implementation for tests performed by an llinterp. .. _`extfunc.py`: https://bitbucket.org/pypy/pypy/src/tip/pypy/rpython/extfunc.py - - -OO backends ------------ - -XXX to be written diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -31,3 +31,15 @@ more precise information about which functions can be called. Needed for Topaz. .. branch: ssl_moving_write_buffer + +.. branch: pythoninspect-fix +Make PyPy respect PYTHONINSPECT variable set via os.putenv in the same process +to start interactive prompt when the script execution finishes. This adds +new __pypy__.os.real_getenv call that bypasses Python cache and looksup env +in the underlying OS. Translatorshell now works on PyPy. + +.. branch: add-statvfs +Added os.statvfs and os.fstatvfs + +.. branch: statvfs_tests +Added some addition tests for statvfs. diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -550,8 +550,15 @@ # or # * PYTHONINSPECT is set and stdin is a tty. # + try: + # we need a version of getenv that bypasses Python caching + from __pypy__.os import real_getenv + except ImportError: + # dont fail on CPython here + real_getenv = os.getenv + return (interactive or - ((inspect or (readenv and os.getenv('PYTHONINSPECT'))) + ((inspect or (readenv and real_getenv('PYTHONINSPECT'))) and sys.stdin.isatty())) success = True 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 @@ -58,7 +58,7 @@ pdir = _get_next_path(ext='') p = pdir.ensure(dir=1).join('__main__.py') p.write(str(py.code.Source(source))) - # return relative path for testing purposes + # return relative path for testing purposes return py.path.local().bestrelpath(pdir) def pytest_funcarg__demo_script(request): @@ -768,6 +768,20 @@ expect_prompt=True, expect_banner=False) assert '42\n' in data + def test_putenv_fires_interactive_within_process(self): + try: + import __pypy__ + except ImportError: + py.test.skip("This can be only tested on PyPy with real_getenv") + + # should be noninteractive when piped in + data = 'import os\nos.putenv("PYTHONINSPECT", "1")\n' + self.run('', senddata=data, expect_prompt=False) + + # should go interactive with -c + data = data.replace('\n', ';') + self.run("-c '%s'" % data, expect_prompt=True) + def test_option_S_copyright(self): data = self.run('-S -i', expect_prompt=True, expect_banner=True) assert 'copyright' not in data @@ -1090,7 +1104,7 @@ pypy_c = os.path.join(self.trunkdir, 'pypy', 'goal', 'pypy-c') app_main.setup_bootstrap_path(pypy_c) newpath = sys.path[:] - # we get at least lib_pypy + # we get at least lib_pypy # lib-python/X.Y.Z, and maybe more (e.g. plat-linux2) assert len(newpath) >= 2 for p in newpath: diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -50,6 +50,13 @@ } +class OsModule(MixedModule): + appleveldefs = {} + interpleveldefs = { + 'real_getenv': 'interp_os.real_getenv' + } + + class Module(MixedModule): appleveldefs = { } @@ -82,6 +89,7 @@ "time": TimeModule, "thread": ThreadModule, "intop": IntOpModule, + "os": OsModule, } def setup_after_space_initialization(self): diff --git a/pypy/module/__pypy__/interp_os.py b/pypy/module/__pypy__/interp_os.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_os.py @@ -0,0 +1,9 @@ +import os + +from pypy.interpreter.gateway import unwrap_spec + + +@unwrap_spec(name='str0') +def real_getenv(space, name): + """Get an OS environment value skipping Python cache""" + return space.wrap(os.environ.get(name)) diff --git a/pypy/module/__pypy__/test/test_os.py b/pypy/module/__pypy__/test/test_os.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_os.py @@ -0,0 +1,16 @@ +class AppTestOs: + spaceconfig = dict(usemodules=['__pypy__']) + + def test_real_getenv(self): + import __pypy__.os + import os + + key = 'UNLIKELY_SET' + assert key not in os.environ + os.putenv(key, '42') + # this one skips Python cache + assert __pypy__.os.real_getenv(key) == '42' + # this one can only see things set on interpter start (cached) + assert os.getenv(key) is None + os.unsetenv(key) + assert __pypy__.os.real_getenv(key) is None diff --git a/pypy/module/_cffi_backend/libraryobj.py b/pypy/module/_cffi_backend/libraryobj.py --- a/pypy/module/_cffi_backend/libraryobj.py +++ b/pypy/module/_cffi_backend/libraryobj.py @@ -4,6 +4,7 @@ from pypy.interpreter.error import operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef +from pypy.module._rawffi.interp_rawffi import wrap_dlopenerror from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rdynload import DLLHANDLE, dlopen, dlsym, dlclose, DLOpenError @@ -24,9 +25,7 @@ try: self.handle = dlopen(ll_libname, flags) except DLOpenError, e: - raise operationerrfmt(space.w_OSError, - "cannot load library %s: %s", - filename, e.msg) + raise wrap_dlopenerror(space, e, filename) self.name = filename def __del__(self): diff --git a/pypy/module/_ffi/interp_funcptr.py b/pypy/module/_ffi/interp_funcptr.py --- a/pypy/module/_ffi/interp_funcptr.py +++ b/pypy/module/_ffi/interp_funcptr.py @@ -14,7 +14,7 @@ from rpython.rlib.rarithmetic import r_uint from rpython.rlib.objectmodel import we_are_translated from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter -from pypy.module._rawffi.interp_rawffi import got_libffi_error +from pypy.module._rawffi.interp_rawffi import got_libffi_error, wrap_dlopenerror import os if os.name == 'nt': @@ -325,8 +325,7 @@ try: self.cdll = libffi.CDLL(name, mode) except DLOpenError, e: - raise operationerrfmt(space.w_OSError, '%s: %s', self.name, - e.msg or 'unspecified error') + raise wrap_dlopenerror(space, e, self.name) def getfunc(self, space, w_name, w_argtypes, w_restype): return _getfunc(space, self, w_name, w_argtypes, w_restype) diff --git a/pypy/module/_ffi/test/test_type_converter.py b/pypy/module/_ffi/test/test_type_converter.py --- a/pypy/module/_ffi/test/test_type_converter.py +++ b/pypy/module/_ffi/test/test_type_converter.py @@ -150,7 +150,7 @@ return self.do_and_wrap(w_ffitype) -class TestFromAppLevel(object): +class TestToAppLevel(object): spaceconfig = dict(usemodules=('_ffi',)) def setup_class(cls): diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -141,6 +141,11 @@ raise OperationError(space.w_SystemError, space.wrap("not supported by libffi")) +def wrap_dlopenerror(space, e, filename): + msg = e.msg if e.msg else 'unspecified error' + return operationerrfmt(space.w_OSError, 'Cannot load library %s: %s', + filename, msg) + class W_CDLL(W_Root): def __init__(self, space, name, cdll): @@ -220,8 +225,7 @@ try: cdll = CDLL(name) except DLOpenError, e: - raise operationerrfmt(space.w_OSError, '%s: %s', name, - e.msg or 'unspecified error') + raise wrap_dlopenerror(space, e, name) except OSError, e: raise wrap_oserror(space, e) return space.wrap(W_CDLL(space, name, cdll)) diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -223,7 +223,8 @@ _rawffi.CDLL("xxxxx_this_name_does_not_exist_xxxxx") except OSError as e: print(e) - assert str(e).startswith("xxxxx_this_name_does_not_exist_xxxxx: ") + assert str(e).startswith( + "Cannot load library xxxxx_this_name_does_not_exist_xxxxx: ") else: raise AssertionError("did not fail??") diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py --- a/pypy/module/posix/__init__.py +++ b/pypy/module/posix/__init__.py @@ -17,12 +17,13 @@ 'setregid', 'setreuid', 'setsid', 'setuid', 'stat_float_times', 'statvfs', 'statvfs_result', 'symlink', 'sysconf', 'sysconf_names', 'tcgetpgrp', 'tcsetpgrp', 'ttyname', 'uname', 'wait', 'wait3', 'wait4' - ] +] # the Win32 urandom implementation isn't going to translate on JVM or CLI so # we have to remove it lltype_only_defs.append('urandom') + class Module(MixedModule): """This module provides access to operating system functionality that is standardized by the C Standard and the POSIX standard (a thinly @@ -32,18 +33,18 @@ applevel_name = os.name appleveldefs = { - 'error' : 'app_posix.error', - 'stat_result': 'app_posix.stat_result', - 'urandom': 'app_posix.urandom', - 'statvfs_result': 'app_posix.statvfs_result', + 'error': 'app_posix.error', + 'stat_result': 'app_posix.stat_result', + 'statvfs_result': 'app_posix.statvfs_result', + 'urandom': 'app_posix.urandom', } if os.name == 'nt': del appleveldefs['urandom'] # at interp on win32 appleveldefs.update({ - 'popen2' : 'app_posix.popen2', - 'popen3' : 'app_posix.popen3', - 'popen4' : 'app_posix.popen4', - }) + 'popen2': 'app_posix.popen2', + 'popen3': 'app_posix.popen3', + 'popen4': 'app_posix.popen4', + }) if hasattr(os, 'wait'): appleveldefs['wait'] = 'app_posix.wait' @@ -51,45 +52,47 @@ appleveldefs['wait3'] = 'app_posix.wait3' if hasattr(os, 'wait4'): appleveldefs['wait4'] = 'app_posix.wait4' - + interpleveldefs = { - 'open' : 'interp_posix.open', - 'lseek' : 'interp_posix.lseek', - 'write' : 'interp_posix.write', - 'isatty' : 'interp_posix.isatty', - 'read' : 'interp_posix.read', - 'close' : 'interp_posix.close', - 'closerange': 'interp_posix.closerange', - 'fstat' : 'interp_posix.fstat', - 'stat' : 'interp_posix.stat', - 'lstat' : 'interp_posix.lstat', - 'stat_float_times' : 'interp_posix.stat_float_times', - 'dup' : 'interp_posix.dup', - 'dup2' : 'interp_posix.dup2', - 'access' : 'interp_posix.access', - 'times' : 'interp_posix.times', - 'system' : 'interp_posix.system', - 'unlink' : 'interp_posix.unlink', - 'remove' : 'interp_posix.remove', - 'getcwd' : 'interp_posix.getcwd', - 'getcwdb' : 'interp_posix.getcwdb', - 'chdir' : 'interp_posix.chdir', - 'mkdir' : 'interp_posix.mkdir', - 'rmdir' : 'interp_posix.rmdir', - 'environ' : 'interp_posix.get(space).w_environ', - 'listdir' : 'interp_posix.listdir', - 'strerror' : 'interp_posix.strerror', - 'pipe' : 'interp_posix.pipe', - 'chmod' : 'interp_posix.chmod', - 'rename' : 'interp_posix.rename', - 'umask' : 'interp_posix.umask', - '_exit' : 'interp_posix._exit', - 'utime' : 'interp_posix.utime', - '_statfields': 'interp_posix.getstatfields(space)', - 'kill' : 'interp_posix.kill', - 'abort' : 'interp_posix.abort', - 'urandom' : 'interp_posix.urandom', - 'device_encoding' : 'interp_posix.device_encoding', + 'open': 'interp_posix.open', + 'lseek': 'interp_posix.lseek', + 'write': 'interp_posix.write', + 'isatty': 'interp_posix.isatty', + 'read': 'interp_posix.read', + 'close': 'interp_posix.close', + 'closerange': 'interp_posix.closerange', + + 'fstat': 'interp_posix.fstat', + 'stat': 'interp_posix.stat', + 'lstat': 'interp_posix.lstat', + 'stat_float_times': 'interp_posix.stat_float_times', + + 'dup': 'interp_posix.dup', + 'dup2': 'interp_posix.dup2', + 'access': 'interp_posix.access', + 'times': 'interp_posix.times', + 'system': 'interp_posix.system', + 'unlink': 'interp_posix.unlink', + 'remove': 'interp_posix.remove', + 'getcwd': 'interp_posix.getcwd', + 'getcwdb': 'interp_posix.getcwdb', + 'chdir': 'interp_posix.chdir', + 'mkdir': 'interp_posix.mkdir', + 'rmdir': 'interp_posix.rmdir', + 'environ': 'interp_posix.get(space).w_environ', + 'listdir': 'interp_posix.listdir', + 'strerror': 'interp_posix.strerror', + 'pipe': 'interp_posix.pipe', + 'chmod': 'interp_posix.chmod', + 'rename': 'interp_posix.rename', + 'umask': 'interp_posix.umask', + '_exit': 'interp_posix._exit', + 'utime': 'interp_posix.utime', + '_statfields': 'interp_posix.getstatfields(space)', + 'kill': 'interp_posix.kill', + 'abort': 'interp_posix.abort', + 'urandom': 'interp_posix.urandom', + 'device_encoding': 'interp_posix.device_encoding', } if hasattr(os, 'chown'): @@ -166,9 +169,9 @@ interpleveldefs['getlogin'] = 'interp_posix.getlogin' for name in ['setsid', 'getuid', 'geteuid', 'getgid', 'getegid', 'setuid', - 'seteuid', 'setgid', 'setegid', 'getgroups', 'getpgrp', - 'setpgrp', 'getppid', 'getpgid', 'setpgid', 'setreuid', - 'setregid', 'getsid', 'setsid']: + 'seteuid', 'setgid', 'setegid', 'getgroups', 'getpgrp', + 'setpgrp', 'getppid', 'getpgid', 'setpgid', 'setreuid', + 'setregid', 'getsid', 'setsid', 'fstatvfs', 'statvfs']: if hasattr(os, name): interpleveldefs[name] = 'interp_posix.%s' % (name,) # not visible via os, inconsistency in nt: @@ -176,7 +179,7 @@ interpleveldefs['_getfullpathname'] = 'interp_posix._getfullpathname' if hasattr(os, 'chroot'): interpleveldefs['chroot'] = 'interp_posix.chroot' - + for name in RegisterOs.w_star: if hasattr(os, name): interpleveldefs[name] = 'interp_posix.' + name @@ -185,7 +188,7 @@ # if it's an ootype translation, remove all the defs that are lltype # only backend = space.config.translation.backend - if backend == 'cli' or backend == 'jvm': + if backend == 'cli' or backend == 'jvm' : for name in lltype_only_defs: self.interpleveldefs.pop(name, None) MixedModule.__init__(self, space, w_name) @@ -193,7 +196,7 @@ def startup(self, space): from pypy.module.posix import interp_posix interp_posix.get(space).startup(space) - + for constant in dir(os): value = getattr(os, constant) if constant.isupper() and type(value) is int: diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py --- a/pypy/module/posix/interp_posix.py +++ b/pypy/module/posix/interp_posix.py @@ -1,14 +1,16 @@ -from pypy.interpreter.gateway import unwrap_spec, WrappedDefault +import os +import sys + from rpython.rlib import rposix, objectmodel, rurandom from rpython.rlib.objectmodel import specialize from rpython.rlib.rarithmetic import r_longlong from rpython.rlib.unroll import unrolling_iterable +from rpython.rtyper.module import ll_os_stat +from rpython.rtyper.module.ll_os import RegisterOs + +from pypy.interpreter.gateway import unwrap_spec, WrappedDefault from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2 -from rpython.rtyper.module.ll_os import RegisterOs -from rpython.rtyper.module import ll_os_stat -import os -import sys _WIN32 = sys.platform == 'win32' if _WIN32: @@ -203,6 +205,7 @@ STAT_FIELDS = unrolling_iterable(enumerate(ll_os_stat.STAT_FIELDS)) PORTABLE_STAT_FIELDS = unrolling_iterable( enumerate(ll_os_stat.PORTABLE_STAT_FIELDS)) +STATVFS_FIELDS = unrolling_iterable(enumerate(ll_os_stat.STATVFS_FIELDS)) def build_stat_result(space, st): if space.config.translation.type_system == 'ootype': @@ -243,6 +246,16 @@ space.wrap('stat_result')) return space.call_function(w_stat_result, w_tuple, w_keywords) + +def build_statvfs_result(space, st): + vals_w = [None] * len(ll_os_stat.STATVFS_FIELDS) + for i, (name, _) in STATVFS_FIELDS: + vals_w[i] = space.wrap(getattr(st, name)) + w_tuple = space.newtuple(vals_w) + w_statvfs_result = space.getattr(space.getbuiltinmodule(os.name), space.wrap('statvfs_result')) + return space.call_function(w_statvfs_result, w_tuple) + + @unwrap_spec(fd=c_int) def fstat(space, fd): """Perform a stat system call on the file referenced to by an open @@ -304,6 +317,26 @@ else: state.stat_float_times = space.bool_w(w_value) + +@unwrap_spec(fd=c_int) +def fstatvfs(space, fd): + try: + st = os.fstatvfs(fd) + except OSError as e: + raise wrap_oserror(space, e) + else: + return build_statvfs_result(space, st) + + +def statvfs(space, w_path): + try: + st = dispatch_filename(rposix.statvfs)(space, w_path) + except OSError as e: + raise wrap_oserror2(space, e, w_path) + else: + return build_statvfs_result(space, st) + + @unwrap_spec(fd=c_int) def dup(space, fd): """Create a copy of the file descriptor. Return the new file diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -168,7 +168,8 @@ assert stat.S_ISDIR(st.st_mode) def test_stat_exception(self): - import sys, errno + import sys + import errno for fn in [self.posix.stat, self.posix.lstat]: try: fn("nonexistentdir/nonexistentfile") @@ -182,6 +183,16 @@ assert isinstance(e, WindowsError) assert e.winerror == 3 + if hasattr(__import__(os.name), "statvfs"): + def test_statvfs(self): + st = self.posix.statvfs(".") + assert isinstance(st, self.posix.statvfs_result) + for field in [ + 'f_bsize', 'f_frsize', 'f_blocks', 'f_bfree', 'f_bavail', + 'f_files', 'f_ffree', 'f_favail', 'f_flag', 'f_namemax', + ]: + assert hasattr(st, field) + def test_pickle(self): import pickle, os st = self.posix.stat(os.curdir) diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -125,6 +125,9 @@ self.llbox = llbox def descr_getint(self, space): + if not jit_hooks.box_isint(self.llbox): + raise OperationError(space.w_NotImplementedError, + space.wrap("Box has no int value")) return space.wrap(jit_hooks.box_getint(self.llbox)) @unwrap_spec(no=int) @@ -182,7 +185,12 @@ @unwrap_spec(no=int) def descr_getarg(self, space, no): - return WrappedBox(jit_hooks.resop_getarg(self.op, no)) + try: + box = jit_hooks.resop_getarg(self.op, no) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Index out of range")) + return WrappedBox(box) @unwrap_spec(no=int, w_box=WrappedBox) def descr_setarg(self, space, no, w_box): @@ -232,7 +240,8 @@ getarg = interp2app(WrappedOp.descr_getarg), setarg = interp2app(WrappedOp.descr_setarg), result = GetSetProperty(WrappedOp.descr_getresult, - WrappedOp.descr_setresult) + WrappedOp.descr_setresult), + offset = interp_attrproperty("offset", cls=WrappedOp), ) WrappedOp.acceptable_as_base_class = False @@ -342,6 +351,10 @@ doc="bridge number (if a bridge)"), type = interp_attrproperty('type', cls=W_JitLoopInfo, doc="Loop type"), + asmaddr = interp_attrproperty('asmaddr', cls=W_JitLoopInfo, + doc="Address of machine code"), + asmlen = interp_attrproperty('asmlen', cls=W_JitLoopInfo, + doc="Length of machine code"), __repr__ = interp2app(W_JitLoopInfo.descr_repr), ) W_JitLoopInfo.acceptable_as_base_class = False diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -71,7 +71,7 @@ greenkey) di_loop_optimize = JitDebugInfo(MockJitDriverSD, logger, JitCellToken(), oplist, 'loop', greenkey) - di_loop.asminfo = AsmInfo(offset, 0, 0) + di_loop.asminfo = AsmInfo(offset, 0x42, 12) di_bridge = JitDebugInfo(MockJitDriverSD, logger, JitCellToken(), oplist, 'bridge', fail_descr=BasicFailDescr()) di_bridge.asminfo = AsmInfo(offset, 0, 0) @@ -123,6 +123,8 @@ assert info.greenkey[2] == False assert info.loop_no == 0 assert info.type == 'loop' + assert info.asmaddr == 0x42 + assert info.asmlen == 12 raises(TypeError, 'info.bridge_no') assert len(info.operations) == 4 int_add = info.operations[0] @@ -132,8 +134,10 @@ assert dmp.greenkey == (self.f.__code__, 0, False) assert dmp.call_depth == 0 assert dmp.call_id == 0 + assert dmp.offset == -1 assert int_add.name == 'int_add' assert int_add.num == self.int_add_num + assert int_add.offset == 0 self.on_compile_bridge() expected = ('<JitLoopInfo pypyjit, 4 operations, starting at ' '<(%s, 0, False)>>' % repr(self.f.__code__)) @@ -161,6 +165,20 @@ assert 'jit hook' in s.getvalue() assert 'ZeroDivisionError' in s.getvalue() + def test_on_compile_crashes(self): + import pypyjit + loops = [] + def hook(loop): + loops.append(loop) + pypyjit.set_compile_hook(hook) + self.on_compile() + loop = loops[0] + op = loop.operations[2] + # Should not crash the interpreter + raises(IndexError, op.getarg, 2) + assert op.name == 'guard_nonnull' + raises(NotImplementedError, op.getarg(0).getint) + def test_non_reentrant(self): import pypyjit l = [] diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -735,6 +735,10 @@ self.mc.RET() def _load_shadowstack_top_in_ebx(self, mc, gcrootmap): + """Loads the shadowstack top in ebx, and returns an integer + that gives the address of the stack top. If this integer doesn't + fit in 32 bits, it will be loaded in r11. + """ rst = gcrootmap.get_root_stack_top_addr() if rx86.fits_in_32bits(rst): mc.MOV_rj(ebx.value, rst) # MOV ebx, [rootstacktop] @@ -752,6 +756,9 @@ if rx86.fits_in_32bits(rst): self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx else: + # The integer 'rst' doesn't fit in 32 bits, so we know that + # _load_shadowstack_top_in_ebx() above loaded it in r11. + # Reuse it. Be careful not to overwrite r11 in the middle! self.mc.MOV_mr((X86_64_SCRATCH_REG.value, 0), ebx.value) # MOV [r11], ebx diff --git a/rpython/jit/tool/test/f.pypylog.bz2 b/rpython/jit/tool/test/f.pypylog.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..a982e459b1daa33547576733ccc0b560f99a3f79 GIT binary patch [cut] diff --git a/rpython/jit/tool/test/test_traceviewer.py b/rpython/jit/tool/test/test_traceviewer.py --- a/rpython/jit/tool/test/test_traceviewer.py +++ b/rpython/jit/tool/test/test_traceviewer.py @@ -1,7 +1,7 @@ import math import py from rpython.jit.tool.traceviewer import splitloops, FinalBlock, Block,\ - split_one_loop, postprocess, main, get_gradient_color + split_one_loop, postprocess, main, get_gradient_color, guard_number def test_gradient_color(): @@ -30,6 +30,20 @@ loops = splitloops(data) assert len(loops) == 2 + def test_no_of_loops_hexguards(self): + data = [preparse(""" + # Loop 0 : loop with 39 ops + debug_merge_point('', 0) + guard_class(p4, 141310752, descr=<Guard0x10abcdef0>) [p0, p1] + p60 = getfield_gc(p4, descr=<GcPtrFieldDescr 16>) + guard_nonnull(p60, descr=<Guard0x10abcdef1>) [p0, p1] + """), preparse(""" + # Loop 1 : loop with 46 ops + p21 = getfield_gc(p4, descr=<GcPtrFieldDescr 16>) + """)] + loops = splitloops(data) + assert len(loops) == 2 + def test_split_one_loop(self): real_loops = [FinalBlock(preparse(""" p21 = getfield_gc(p4, descr=<GcPtrFieldDescr 16>) @@ -50,12 +64,42 @@ assert loop.left.content == '' assert loop.right.content == 'extra' + def test_split_one_loop_hexguards(self): + real_loops = [FinalBlock(preparse(""" + p21 = getfield_gc(p4, descr=<GcPtrFieldDescr 16>) + guard_class(p4, 141310752, descr=<Guard0x10abcdef2>) [p0, p1] + """), None), FinalBlock(preparse(""" + p60 = getfield_gc(p4, descr=<GcPtrFieldDescr 16>) + guard_nonnull(p60, descr=<Guard0x10abcdef0>) [p0, p1] + """), None)] + real_loops[0].loop_no = 0 + real_loops[1].loop_no = 1 + allloops = real_loops[:] + split_one_loop(real_loops, 'Guard0x10abcdef0', 'extra', 1, guard_number(("0x10abcdef0", "0x")), allloops) + loop = real_loops[1] + assert isinstance(loop, Block) + assert loop.content.endswith('p1]') + loop.left = allloops[loop.left] + loop.right = allloops[loop.right] + assert loop.left.content == '' + assert loop.right.content == 'extra' + def test_postparse(self): real_loops = [FinalBlock("debug_merge_point('<code object _runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357> #40 POP_TOP', 0)", None)] postprocess(real_loops, real_loops[:], {}) assert real_loops[0].header.startswith("_runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357") + def test_postparse_new(self): + real_loops = [FinalBlock("debug_merge_point(0, 0, '<code object _optimize_charset. file '/usr/local/Cellar/pypy/2.0-beta2/lib-python/2.7/sre_compile.py'. line 207> #351 LOAD_FAST')", None)] + postprocess(real_loops, real_loops[:], {}) + assert real_loops[0].header.startswith("_optimize_charset. file '/usr/local/Cellar/pypy/2.0-beta2/lib-python/2.7/sre_compile.py'. line 207") + def test_load_actual(self): fname = py.path.local(__file__).join('..', 'data.log.bz2') main(str(fname), False, view=False) # assert did not explode + + def test_load_actual_f(self): + fname = py.path.local(__file__).join('..', 'f.pypylog.bz2') + main(str(fname), False, view=False) + # assert did not explode diff --git a/rpython/jit/tool/traceviewer.py b/rpython/jit/tool/traceviewer.py --- a/rpython/jit/tool/traceviewer.py +++ b/rpython/jit/tool/traceviewer.py @@ -56,6 +56,18 @@ BOX_COLOR = (128, 0, 96) +GUARDNO_RE = "((0x)?[\da-f]+)" +def guard_number(guardno_match): + if (len(guardno_match) == 1 # ("12354",) + or guardno_match[1] != "0x" # ("12345", None) + ): + return int(guardno_match[0]) + else: # ("0x12ef", "0x") + return int(guardno_match[0], 16) + +def guard_number_string(guardno_match): + return guardno_match[0] # its always the first group + class BasicBlock(object): counter = 0 startlineno = 0 @@ -85,13 +97,15 @@ def set_content(self, content): self._content = content - groups = re.findall('Guard(\d+)', content) + groups = re.findall('Guard' + GUARDNO_RE, content) if not groups: self.first_guard = -1 self.last_guard = -1 else: - self.first_guard = int(groups[0]) - self.last_guard = int(groups[-1]) + # guards can be out of order nowadays + groups = sorted(groups) + self.first_guard = guard_number(groups[0]) + self.last_guard = guard_number(groups[-1]) content = property(get_content, set_content) @@ -197,11 +211,11 @@ _loop.loop_no = no allloops.append(_loop) else: - m = re.search("bridge out of Guard (\d+)", firstline) + m = re.search("bridge out of Guard " + GUARDNO_RE, firstline) assert m - guard_s = 'Guard' + m.group(1) + guard_s = 'Guard' + guard_number_string(m.groups()) split_one_loop(real_loops, guard_s, loop, counter, - int(m.group(1)), allloops) + guard_number(m.groups()), allloops) counter += loop.count("\n") + 2 return real_loops, allloops @@ -211,7 +225,7 @@ memo.add(loop) if loop is None: return - m = re.search("debug_merge_point\('(<code object (.*?)> (.*?))'", loop.content) + m = re.search("debug_merge_point\((?:\d+,\ )*'(<code object (.*?)> (.*?))'", loop.content) if m is None: name = '?' loop.key = '?' @@ -236,7 +250,7 @@ content = loop.content loop.content = "Logfile at %d\n" % loop.startlineno + content loop.postprocess(loops, memo, counts) - + def postprocess(loops, allloops, counts): for loop in allloops: if isinstance(loop, Block): diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -111,6 +111,11 @@ from rpython.jit.metainterp.history import Const return isinstance(_cast_to_box(llbox), Const) +@register_helper(annmodel.SomeBool()) +def box_isint(llbox): + from rpython.jit.metainterp.history import INT + return _cast_to_box(llbox).type == INT + # ------------------------- stats interface --------------------------- @register_helper(annmodel.SomeBool()) diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -154,6 +154,15 @@ else: return os.lstat(path.as_bytes()) + +@specialize.argtype(0) +def statvfs(path): + if isinstance(path, str): + return os.statvfs(path) + else: + return os.statvfs(path.as_bytes()) + + @specialize.argtype(0) def unlink(path): if isinstance(path, str): diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py --- a/rpython/rtyper/module/ll_os.py +++ b/rpython/rtyper/module/ll_os.py @@ -1698,6 +1698,18 @@ from rpython.rtyper.module import ll_os_stat return ll_os_stat.register_stat_variant('lstat', traits) + @registering_if(os, 'fstatvfs') + def register_os_fstatvfs(self): + from rpython.rtyper.module import ll_os_stat + return ll_os_stat.register_statvfs_variant('fstatvfs', StringTraits()) + + if hasattr(os, 'statvfs'): + @registering_str_unicode(os.statvfs) + def register_os_statvfs(self, traits): + from rpython.rtyper.module import ll_os_stat + return ll_os_stat.register_statvfs_variant('statvfs', traits) + + # ------------------------------- os.W* --------------------------------- w_star = ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED', diff --git a/rpython/rtyper/module/ll_os_stat.py b/rpython/rtyper/module/ll_os_stat.py --- a/rpython/rtyper/module/ll_os_stat.py +++ b/rpython/rtyper/module/ll_os_stat.py @@ -2,20 +2,22 @@ and os.fstat(). In RPython like in plain Python the stat result can be indexed like a tuple but also exposes the st_xxx attributes. """ -import os, sys + +import os +import sys + from rpython.annotator import model as annmodel -from rpython.tool.pairtype import pairtype -from rpython.tool.sourcetools import func_with_new_name, func_renamer -from rpython.rtyper import extregistry -from rpython.rtyper.extfunc import register_external, extdef -from rpython.rtyper.lltypesystem import rffi, lltype -from rpython.rtyper.tool import rffi_platform as platform -from rpython.rtyper.lltypesystem.rtupletype import TUPLE_TYPE from rpython.rlib import rposix from rpython.rlib.rarithmetic import intmask -from rpython.rlib.objectmodel import specialize +from rpython.rtyper import extregistry +from rpython.rtyper.annlowlevel import hlstr +from rpython.rtyper.extfunc import extdef +from rpython.rtyper.lltypesystem import rffi, lltype +from rpython.rtyper.lltypesystem.rtupletype import TUPLE_TYPE +from rpython.rtyper.tool import rffi_platform as platform +from rpython.tool.pairtype import pairtype +from rpython.tool.sourcetools import func_renamer from rpython.translator.tool.cbuild import ExternalCompilationInfo -from rpython.rtyper.annlowlevel import hlstr # Support for float times is here. # - ALL_STAT_FIELDS contains Float fields if the system can retrieve @@ -47,12 +49,26 @@ ("st_flags", lltype.Signed), #("st_gen", lltype.Signed), -- new in CPy 2.5, not implemented #("st_birthtime", lltype.Float), -- new in CPy 2.5, not implemented - ] +] N_INDEXABLE_FIELDS = 10 # For OO backends, expose only the portable fields (the first 10). PORTABLE_STAT_FIELDS = ALL_STAT_FIELDS[:N_INDEXABLE_FIELDS] +STATVFS_FIELDS = [ + ("f_bsize", lltype.Signed), + ("f_frsize", lltype.Signed), + ("f_blocks", lltype.Signed), + ("f_bfree", lltype.Signed), + ("f_bavail", lltype.Signed), + ("f_files", lltype.Signed), + ("f_ffree", lltype.Signed), + ("f_favail", lltype.Signed), + ("f_flag", lltype.Signed), + ("f_namemax", lltype.Signed), +] + + # ____________________________________________________________ # # Annotation support @@ -79,6 +95,7 @@ def stat_result_reduce(st): return (st[0], st[1], st[2], st[3], st[4], st[5], st[6], st[7], st[8], st[9]) + def stat_result_recreate(tup): return make_stat_result(tup + extra_zeroes) s_reduced = annmodel.SomeTuple([annmodel.lltype_to_annotation(TYPE) @@ -86,6 +103,26 @@ extra_zeroes = (0,) * (len(STAT_FIELDS) - len(PORTABLE_STAT_FIELDS)) return s_reduced, stat_result_reduce, stat_result_recreate + +class SomeStatvfsResult(annmodel.SomeObject): + if hasattr(os, 'statvfs_result'): + knowntype = os.statvfs_result + else: + knowntype = None # will not be used + + def rtyper_makerepr(self, rtyper): + from rpython.rtyper.module import r_os_stat + return r_os_stat.StatvfsResultRepr(rtyper) + + def rtyper_makekey_ex(self, rtyper): + return self.__class__, + + def getattr(self, s_attr): + assert s_attr.is_constant() + TYPE = STATVFS_FIELD_TYPES[s_attr.const] + return annmodel.lltype_to_annotation(TYPE) + + class __extend__(pairtype(SomeStatResult, annmodel.SomeInteger)): def getitem((s_sta, s_int)): assert s_int.is_constant(), "os.stat()[index]: index must be constant" @@ -94,7 +131,17 @@ name, TYPE = STAT_FIELDS[index] return annmodel.lltype_to_annotation(TYPE) + +class __extend__(pairtype(SomeStatvfsResult, annmodel.SomeInteger)): + def getitem((s_stat, s_int)): + assert s_int.is_constant() + name, TYPE = STATVFS_FIELDS[s_int.const] + return annmodel.lltype_to_annotation(TYPE) + + s_StatResult = SomeStatResult() +s_StatvfsResult = SomeStatvfsResult() + def make_stat_result(tup): """Turn a tuple into an os.stat_result object.""" @@ -104,6 +151,11 @@ kwds[name] = tup[N_INDEXABLE_FIELDS + i] return os.stat_result(positional, kwds) + +def make_statvfs_result(tup): + return os.statvfs_result(tup) + + class MakeStatResultEntry(extregistry.ExtRegistryEntry): _about_ = make_stat_result @@ -114,22 +166,33 @@ from rpython.rtyper.module import r_os_stat return r_os_stat.specialize_make_stat_result(hop) + +class MakeStatvfsResultEntry(extregistry.ExtRegistryEntry): + _about_ = make_statvfs_result + + def compute_result_annotation(self, s_tup): + return s_StatvfsResult + + def specialize_call(self, hop): + from rpython.rtyper.module import r_os_stat + return r_os_stat.specialize_make_statvfs_result(hop) + # ____________________________________________________________ # # RFFI support if sys.platform.startswith('win'): _name_struct_stat = '_stati64' - INCLUDES = ['sys/types.h', 'sys/stat.h'] + INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h'] else: _name_struct_stat = 'stat' - INCLUDES = ['sys/types.h', 'sys/stat.h', 'unistd.h'] + INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h', 'unistd.h'] compilation_info = ExternalCompilationInfo( # This must be set to 64 on some systems to enable large file support. #pre_include_bits = ['#define _FILE_OFFSET_BITS 64'], # ^^^ nowadays it's always set in all C files we produce. - includes = INCLUDES + includes=INCLUDES ) if TIMESPEC is not None: @@ -141,7 +204,7 @@ def posix_declaration(try_to_add=None): - global STAT_STRUCT + global STAT_STRUCT, STATVFS_STRUCT LL_STAT_FIELDS = STAT_FIELDS[:] if try_to_add: @@ -173,15 +236,17 @@ class CConfig: _compilation_info_ = compilation_info STAT_STRUCT = platform.Struct('struct %s' % _name_struct_stat, LL_STAT_FIELDS) + STATVFS_STRUCT = platform.Struct('struct statvfs', STATVFS_FIELDS) + try: - config = platform.configure(CConfig, ignore_errors= - try_to_add is not None) + config = platform.configure(CConfig, ignore_errors=try_to_add is not None) except platform.CompilationError: if try_to_add: return # failed to add this field, give up raise STAT_STRUCT = lltype.Ptr(config['STAT_STRUCT']) + STATVFS_STRUCT = lltype.Ptr(config['STATVFS_STRUCT']) if try_to_add: STAT_FIELDS.append(try_to_add) @@ -202,6 +267,9 @@ STAT_FIELD_NAMES = [_name for (_name, _TYPE) in STAT_FIELDS] del _name, _TYPE +STATVFS_FIELD_TYPES = dict(STATVFS_FIELDS) +STATVFS_FIELD_NAMES = [name for name, tp in STATVFS_FIELDS] + def build_stat_result(st): # only for LL backends @@ -233,6 +301,21 @@ return make_stat_result(result) +def build_statvfs_result(st): + return make_statvfs_result(( + st.c_f_bsize, + st.c_f_frsize, + st.c_f_blocks, + st.c_f_bfree, + st.c_f_bavail, + st.c_f_files, + st.c_f_ffree, + st.c_f_favail, + st.c_f_flag, + st.c_f_namemax + )) + + def register_stat_variant(name, traits): if name != 'fstat': arg_is_path = True @@ -301,6 +384,56 @@ [s_arg], s_StatResult, "ll_os.ll_os_%s" % (name,), llimpl=posix_stat_llimpl, llfakeimpl=posix_fakeimpl) + +def register_statvfs_variant(name, traits): + if name != 'fstatvfs': + arg_is_path = True + s_arg = traits.str0 + ARG1 = traits.CCHARP + else: + arg_is_path = False + s_arg = int + ARG1 = rffi.INT + + posix_mystatvfs = rffi.llexternal(name, + [ARG1, STATVFS_STRUCT], rffi.INT, + compilation_info=compilation_info + ) + + @func_renamer('os_%s_llimpl' % (name,)) + def posix_statvfs_llimpl(arg): + stresult = lltype.malloc(STATVFS_STRUCT.TO, flavor='raw') + try: + if arg_is_path: + arg = traits.str2charp(arg) + error = rffi.cast(rffi.LONG, posix_mystatvfs(arg, stresult)) + if arg_is_path: + traits.free_charp(arg) + if error != 0: + raise OSError(rposix.get_errno(), "os_?statvfs failed") + return build_statvfs_result(stresult) + finally: + lltype.free(stresult, flavor='raw') + + @func_renamer('os_%s_fake' % (name,)) + def posix_fakeimpl(arg): + if s_arg == traits.str0: + arg = hlstr(arg) + st = getattr(os, name)(arg) + fields = [TYPE for fieldname, TYPE in STATVFS_FIELDS] + TP = TUPLE_TYPE(fields) + ll_tup = lltype.malloc(TP.TO) + for i, (fieldname, TYPE) in enumerate(STATVFS_FIELDS): + val = getattr(st, fieldname) + rffi.setintfield(ll_tup, 'item%d' % i, int(val)) + return ll_tup + + return extdef( + [s_arg], s_StatvfsResult, "ll_os.ll_os_%s" % (name,), + llimpl=posix_statvfs_llimpl, llfakeimpl=posix_fakeimpl + ) + + def make_win32_stat_impl(name, traits): from rpython.rlib import rwin32 from rpython.rtyper.module.ll_win32file import make_win32_traits diff --git a/rpython/rtyper/module/r_os_stat.py b/rpython/rtyper/module/r_os_stat.py --- a/rpython/rtyper/module/r_os_stat.py +++ b/rpython/rtyper/module/r_os_stat.py @@ -67,3 +67,52 @@ # no-op conversion from r_StatResult.r_tuple to r_StatResult hop.exception_cannot_occur() return v_result + + +class StatvfsResultRepr(Repr): + + def __init__(self, rtyper): + self.rtyper = rtyper + self.statvfs_fields = ll_os_stat.STATVFS_FIELDS + + self.statvfs_field_indexes = {} + for i, (name, TYPE) in enumerate(self.statvfs_fields): + self.statvfs_field_indexes[name] = i + + self.s_tuple = annmodel.SomeTuple([annmodel.lltype_to_annotation(TYPE) + for name, TYPE in self.statvfs_fields]) + self.r_tuple = rtyper.getrepr(self.s_tuple) + self.lowleveltype = self.r_tuple.lowleveltype + + def redispatch_getfield(self, hop, index): + rtyper = self.rtyper + s_index = rtyper.annotator.bookkeeper.immutablevalue(index) + hop2 = hop.copy() + hop2.forced_opname = 'getitem' + hop2.args_v = [hop2.args_v[0], Constant(index)] + hop2.args_s = [self.s_tuple, s_index] + hop2.args_r = [self.r_tuple, rtyper.getrepr(s_index)] + return hop2.dispatch() + + def rtype_getattr(self, hop): + s_attr = hop.args_s[1] + attr = s_attr.const + try: + index = self.statvfs_field_indexes[attr] + except KeyError: + raise TyperError("os.statvfs().%s: field not available" % (attr,)) + return self.redispatch_getfield(hop, index) + + +class __extend__(pairtype(StatvfsResultRepr, IntegerRepr)): + def rtype_getitem((r_sta, r_int), hop): + s_int = hop.args_s[1] + index = s_int.const + return r_sta.redispatch_getfield(hop, index) + + +def specialize_make_statvfs_result(hop): + r_StatvfsResult = hop.rtyper.getrepr(ll_os_stat.s_StatvfsResult) + [v_result] = hop.inputargs(r_StatvfsResult.r_tuple) + hop.exception_cannot_occur() + return v_result diff --git a/rpython/rtyper/module/test/test_ll_os.py b/rpython/rtyper/module/test/test_ll_os.py --- a/rpython/rtyper/module/test/test_ll_os.py +++ b/rpython/rtyper/module/test/test_ll_os.py @@ -46,6 +46,26 @@ data = getllimpl(os.getlogin)() assert data == expected +def test_statvfs(): + if not hasattr(os, 'statvfs'): + py.test.skip('posix specific function') + try: + expected = os.statvfs('.') + except OSError, e: + py.test.skip("the underlying os.statvfs() failed: %s" % e) + data = getllimpl(os.statvfs)('.') + assert data == expected + +def test_fstatvfs(): + if not hasattr(os, 'fstatvfs'): + py.test.skip('posix specific function') + try: + expected = os.fstatvfs(0) + except OSError, e: + py.test.skip("the underlying os.fstatvfs() failed: %s" % e) + data = getllimpl(os.fstatvfs)(0) + assert data == expected + def test_utimes(): if os.name != 'nt': py.test.skip('Windows specific feature') diff --git a/rpython/translator/c/gcc/trackgcroot.py b/rpython/translator/c/gcc/trackgcroot.py --- a/rpython/translator/c/gcc/trackgcroot.py +++ b/rpython/translator/c/gcc/trackgcroot.py @@ -478,7 +478,7 @@ 'rep', 'movs', 'movhp', 'lods', 'stos', 'scas', 'cwde', 'prefetch', # floating-point operations cannot produce GC pointers 'f', - 'cvt', 'ucomi', 'comi', 'subs', 'subp' , 'adds', 'addp', 'xorp', + 'cvt', 'ucomi', 'comi', 'subs', 'subp', 'adds', 'addp', 'xorp', 'movap', 'movd', 'movlp', 'movup', 'sqrt', 'rsqrt', 'movhlp', 'movlhp', 'mins', 'minp', 'maxs', 'maxp', 'unpck', 'pxor', 'por', # sse2 'shufps', 'shufpd', @@ -495,13 +495,15 @@ # sign-extending moves should not produce GC pointers 'cbtw', 'cwtl', 'cwtd', 'cltd', 'cltq', 'cqto', # zero-extending moves should not produce GC pointers - 'movz', + 'movz', # locked operations should not move GC pointers, at least so far 'lock', 'pause', # non-temporal moves should be reserved for areas containing # raw data, not GC pointers 'movnt', 'mfence', 'lfence', 'sfence', - ]) + # bit manipulations + 'bextr', + ]) # a partial list is hopefully good enough for now; it's all to support # only one corner case, tested in elf64/track_zero.s @@ -741,7 +743,7 @@ # tail-calls are equivalent to RET for us return InsnRet(self.CALLEE_SAVE_REGISTERS) return InsnStop("jump") - + def register_jump_to(self, label, lastinsn=None): if lastinsn is None: lastinsn = self.insns[-1] @@ -1020,7 +1022,7 @@ visit_movl = visit_mov visit_xorl = _maybe_32bit_dest(FunctionGcRootTracker.binary_insn) - + visit_pushq = FunctionGcRootTracker._visit_push visit_addq = FunctionGcRootTracker._visit_add _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit