Author: Ronan Lamy <ronan.l...@gmail.com> Branch: py3k Changeset: r85884:2f965b88873d Date: 2016-07-27 22:01 +0100 http://bitbucket.org/pypy/pypy/changeset/2f965b88873d/
Log: hg merge default diff too long, truncating to 2000 out of 5937 lines diff --git a/lib-python/2.7/test/test_hash.py b/lib-python/2.7/test/test_hash.py --- a/lib-python/2.7/test/test_hash.py +++ b/lib-python/2.7/test/test_hash.py @@ -174,7 +174,7 @@ class StringlikeHashRandomizationTests(HashRandomizationTests): if check_impl_detail(pypy=True): - EMPTY_STRING_HASH = -1 + EMPTY_STRING_HASH = -2 else: EMPTY_STRING_HASH = 0 diff --git a/lib_pypy/_pypy_winbase_build.py b/lib_pypy/_pypy_winbase_build.py new file mode 100644 --- /dev/null +++ b/lib_pypy/_pypy_winbase_build.py @@ -0,0 +1,91 @@ +# Note: uses the CFFI out-of-line ABI mode. We can't use the API +# mode because ffi.compile() needs to run the compiler, which +# needs 'subprocess', which needs 'msvcrt' and '_subprocess', +# which depend on '_pypy_winbase_cffi' already. +# +# Note that if you need to regenerate _pypy_winbase_cffi and +# can't use a preexisting PyPy to do that, then running this +# file should work as long as 'subprocess' is not imported +# by cffi. I had to hack in 'cffi._pycparser' to move an +#'import subprocess' to the inside of a function. (Also, +# CPython+CFFI should work as well.) +# +# This module supports both msvcrt.py and _subprocess.py. + +from cffi import FFI + +ffi = FFI() + +ffi.set_source("_pypy_winbase_cffi", None) + +# ---------- MSVCRT ---------- + +ffi.cdef(""" +typedef unsigned short wint_t; + +int _open_osfhandle(intptr_t osfhandle, int flags); +intptr_t _get_osfhandle(int fd); +int _setmode(int fd, int mode); +int _locking(int fd, int mode, long nbytes); + +int _kbhit(void); +int _getch(void); +wint_t _getwch(void); +int _getche(void); +wint_t _getwche(void); +int _putch(int); +wint_t _putwch(wchar_t); +int _ungetch(int); +wint_t _ungetwch(wint_t); +""") + +# ---------- SUBPROCESS ---------- + +ffi.cdef(""" +typedef struct { + DWORD cb; + char * lpReserved; + char * lpDesktop; + char * lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + LPBYTE lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; +} STARTUPINFO, *LPSTARTUPINFO; + +typedef struct { + HANDLE hProcess; + HANDLE hThread; + DWORD dwProcessId; + DWORD dwThreadId; +} PROCESS_INFORMATION, *LPPROCESS_INFORMATION; + +DWORD WINAPI GetVersion(void); +BOOL WINAPI CreatePipe(PHANDLE, PHANDLE, void *, DWORD); +BOOL WINAPI CloseHandle(HANDLE); +HANDLE WINAPI GetCurrentProcess(void); +BOOL WINAPI DuplicateHandle(HANDLE, HANDLE, HANDLE, LPHANDLE, + DWORD, BOOL, DWORD); +BOOL WINAPI CreateProcessA(char *, char *, void *, + void *, BOOL, DWORD, char *, + char *, LPSTARTUPINFO, LPPROCESS_INFORMATION); +DWORD WINAPI WaitForSingleObject(HANDLE, DWORD); +BOOL WINAPI GetExitCodeProcess(HANDLE, LPDWORD); +BOOL WINAPI TerminateProcess(HANDLE, UINT); +HANDLE WINAPI GetStdHandle(DWORD); +""") + +# -------------------- + +if __name__ == "__main__": + ffi.compile() diff --git a/lib_pypy/_pypy_winbase_cffi.py b/lib_pypy/_pypy_winbase_cffi.py new file mode 100644 --- /dev/null +++ b/lib_pypy/_pypy_winbase_cffi.py @@ -0,0 +1,10 @@ +# auto-generated file +import _cffi_backend + +ffi = _cffi_backend.FFI('_pypy_winbase_cffi', + _version = 0x2601, + _types = b'\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x07\x01\x00\x00\x09\x01\x00\x00\x00\x0F\x00\x00\x01\x0D\x00\x00\x19\x01\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x01\x0D\x00\x00\x00\x0F\x00\x00\x01\x0D\x00\x00\x50\x03\x00\x00\x13\x11\x00\x00\x53\x03\x00\x00\x15\x11\x00\x00\x07\x01\x00\x00\x0A\x01\x00\x00\x13\x11\x00\x00\x13\x11\x00\x00\x4F\x03\x00\x00\x4E\x03\x00\x00\x02\x0F\x00\x00\x01\x0D\x00\x00\x15\x03\x00\x00\x1F\x11\x00\x00\x15\x11\x00\x00\x0A\x01\x00\x00\x02\x0F\x00\x00\x01\x0D\x00\x00\x15\x11\x00\x00\x02\x0F\x00\x00\x01\x0D\x00\x00\x15\x11\x00\x00\x08\x01\x00\x00\x02\x0F\x00\x00\x01\x0D\x00\x00\x15\x11\x00\x00\x18\x03\x00\x00\x02\x0F\x00\x00\x01\x0D\x00\x00\x15\x11\x00\x00\x15\x11\x00\x00\x15\x11\x00\x00\x1F\x11\x00\x00\x0A\x01\x00\x00\x07\x01\x00\x00\x0A\x01\x00\x00\x02\x0F\x00\x00\x0D\x0D\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x18\x0D\x00\x00\x15\x11\x00\x 00\x0A\x01\x00\x00\x02\x0F\x00\x00\x18\x0D\x00\x00\x02\x0F\x00\x00\x42\x0D\x00\x00\x06\x01\x00\x00\x00\x0F\x00\x00\x42\x0D\x00\x00\x00\x0F\x00\x00\x42\x0D\x00\x00\x10\x01\x00\x00\x00\x0F\x00\x00\x15\x0D\x00\x00\x0A\x01\x00\x00\x02\x0F\x00\x00\x15\x0D\x00\x00\x02\x0F\x00\x00\x00\x09\x00\x00\x01\x09\x00\x00\x02\x01\x00\x00\x52\x03\x00\x00\x04\x01\x00\x00\x00\x01', + _globals = (b'\x00\x00\x24\x23CloseHandle',0,b'\x00\x00\x1E\x23CreatePipe',0,b'\x00\x00\x12\x23CreateProcessA',0,b'\x00\x00\x2F\x23DuplicateHandle',0,b'\x00\x00\x4C\x23GetCurrentProcess',0,b'\x00\x00\x2B\x23GetExitCodeProcess',0,b'\x00\x00\x49\x23GetStdHandle',0,b'\x00\x00\x3F\x23GetVersion',0,b'\x00\x00\x27\x23TerminateProcess',0,b'\x00\x00\x3B\x23WaitForSingleObject',0,b'\x00\x00\x38\x23_get_osfhandle',0,b'\x00\x00\x10\x23_getch',0,b'\x00\x00\x10\x23_getche',0,b'\x00\x00\x44\x23_getwch',0,b'\x00\x00\x44\x23_getwche',0,b'\x00\x00\x10\x23_kbhit',0,b'\x00\x00\x07\x23_locking',0,b'\x00\x00\x0C\x23_open_osfhandle',0,b'\x00\x00\x00\x23_putch',0,b'\x00\x00\x46\x23_putwch',0,b'\x00\x00\x03\x23_setmode',0,b'\x00\x00\x00\x23_ungetch',0,b'\x00\x00\x41\x23_ungetwch',0), + _struct_unions = ((b'\x00\x00\x00\x4E\x00\x00\x00\x02$PROCESS_INFORMATION',b'\x00\x00\x15\x11hProcess',b'\x00\x00\x15\x11hThread',b'\x00\x00\x18\x11dwProcessId',b'\x00\x00\x18\x11dwThreadId'),(b'\x00\x00\x00\x4F\x00\x00\x00\x02$STARTUPINFO',b'\x00\x00\x18\x11cb',b'\x00\x00\x13\x11lpReserved',b'\x00\x00\x13\x11lpDesktop',b'\x00\x00\x13\x11lpTitle',b'\x00\x00\x18\x11dwX',b'\x00\x00\x18\x11dwY',b'\x00\x00\x18\x11dwXSize',b'\x00\x00\x18\x11dwYSize',b'\x00\x00\x18\x11dwXCountChars',b'\x00\x00\x18\x11dwYCountChars',b'\x00\x00\x18\x11dwFillAttribute',b'\x00\x00\x18\x11dwFlags',b'\x00\x00\x42\x11wShowWindow',b'\x00\x00\x42\x11cbReserved2',b'\x00\x00\x51\x11lpReserved2',b'\x00\x00\x15\x11hStdInput',b'\x00\x00\x15\x11hStdOutput',b'\x00\x00\x15\x11hStdError')), + _typenames = (b'\x00\x00\x00\x1CLPPROCESS_INFORMATION',b'\x00\x00\x00\x1BLPSTARTUPINFO',b'\x00\x00\x00\x4EPROCESS_INFORMATION',b'\x00\x00\x00\x4FSTARTUPINFO',b'\x00\x00\x00\x42wint_t'), +) diff --git a/lib_pypy/_winapi.py b/lib_pypy/_winapi.py --- a/lib_pypy/_winapi.py +++ b/lib_pypy/_winapi.py @@ -10,152 +10,99 @@ # Declare external Win32 functions -import ctypes - -_kernel32 = ctypes.WinDLL('kernel32') - -_CloseHandle = _kernel32.CloseHandle -_CloseHandle.argtypes = [ctypes.c_int] -_CloseHandle.restype = ctypes.c_int - -_CreatePipe = _kernel32.CreatePipe -_CreatePipe.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), - ctypes.c_void_p, ctypes.c_int] -_CreatePipe.restype = ctypes.c_int - -_GetCurrentProcess = _kernel32.GetCurrentProcess -_GetCurrentProcess.argtypes = [] -_GetCurrentProcess.restype = ctypes.c_int +from _pypy_winbase_cffi import ffi as _ffi +_kernel32 = _ffi.dlopen('kernel32') GetVersion = _kernel32.GetVersion -GetVersion.argtypes = [] -GetVersion.restype = ctypes.c_int -_DuplicateHandle = _kernel32.DuplicateHandle -_DuplicateHandle.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int, - ctypes.POINTER(ctypes.c_int), - ctypes.c_int, ctypes.c_int, ctypes.c_int] -_DuplicateHandle.restype = ctypes.c_int -_WaitForSingleObject = _kernel32.WaitForSingleObject -_WaitForSingleObject.argtypes = [ctypes.c_int, ctypes.c_uint] -_WaitForSingleObject.restype = ctypes.c_int +# Now the _subprocess module implementation -_GetExitCodeProcess = _kernel32.GetExitCodeProcess -_GetExitCodeProcess.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_int)] -_GetExitCodeProcess.restype = ctypes.c_int +def _WinError(): + code, message = _ffi.getwinerror() + raise WindowsError(code, message) -_TerminateProcess = _kernel32.TerminateProcess -_TerminateProcess.argtypes = [ctypes.c_int, ctypes.c_int] -_TerminateProcess.restype = ctypes.c_int +_INVALID_HANDLE_VALUE = _ffi.cast("HANDLE", -1) -_GetStdHandle = _kernel32.GetStdHandle -_GetStdHandle.argtypes = [ctypes.c_int] -_GetStdHandle.restype = ctypes.c_int - -_GetModuleFileNameW = _kernel32.GetModuleFileNameW -_GetModuleFileNameW.argtypes = [ctypes.c_int, ctypes.c_wchar_p, ctypes.c_uint] -_GetModuleFileNameW.restype = ctypes.c_int - -class _STARTUPINFO(ctypes.Structure): - _fields_ = [('cb', ctypes.c_int), - ('lpReserved', ctypes.c_void_p), - ('lpDesktop', ctypes.c_char_p), - ('lpTitle', ctypes.c_char_p), - ('dwX', ctypes.c_int), - ('dwY', ctypes.c_int), - ('dwXSize', ctypes.c_int), - ('dwYSize', ctypes.c_int), - ('dwXCountChars', ctypes.c_int), - ('dwYCountChars', ctypes.c_int), - ("dwFillAttribute", ctypes.c_int), - ("dwFlags", ctypes.c_int), - ("wShowWindow", ctypes.c_short), - ("cbReserved2", ctypes.c_short), - ("lpReserved2", ctypes.c_void_p), - ("hStdInput", ctypes.c_int), - ("hStdOutput", ctypes.c_int), - ("hStdError", ctypes.c_int) - ] - -class _PROCESS_INFORMATION(ctypes.Structure): - _fields_ = [("hProcess", ctypes.c_int), - ("hThread", ctypes.c_int), - ("dwProcessID", ctypes.c_int), - ("dwThreadID", ctypes.c_int)] - -_CreateProcess = _kernel32.CreateProcessW -_CreateProcess.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_void_p, - ctypes.c_int, ctypes.c_int, ctypes.c_wchar_p, ctypes.c_wchar_p, - ctypes.POINTER(_STARTUPINFO), ctypes.POINTER(_PROCESS_INFORMATION)] -_CreateProcess.restype = ctypes.c_int - -del ctypes - -# Now the _winapi module implementation - -from ctypes import c_int as _c_int, byref as _byref, WinError as _WinError - -class _handle: - def __init__(self, handle): - self.handle = handle +class _handle(object): + def __init__(self, c_handle): + # 'c_handle' is a cffi cdata of type HANDLE, which is basically 'void *' + self.c_handle = c_handle + if int(self) != -1: + self.c_handle = _ffi.gc(self.c_handle, _kernel32.CloseHandle) def __int__(self): - return self.handle + return int(_ffi.cast("intptr_t", self.c_handle)) - def __del__(self): - if self.handle is not None: - _CloseHandle(self.handle) + def __repr__(self): + return '<_subprocess.handle %d at 0x%x>' % (int(self), id(self)) def Detach(self): - handle, self.handle = self.handle, None - return handle + h = int(self) + if h != -1: + c_handle = self.c_handle + self.c_handle = _INVALID_HANDLE_VALUE + _ffi.gc(c_handle, None) + return h def Close(self): - if self.handle not in (-1, None): - _CloseHandle(self.handle) - self.handle = None + if int(self) != -1: + c_handle = self.c_handle + self.c_handle = _INVALID_HANDLE_VALUE + _ffi.gc(c_handle, None) + _kernel32.CloseHandle(c_handle) def CreatePipe(attributes, size): - read = _c_int() - write = _c_int() + handles = _ffi.new("HANDLE[2]") - res = _CreatePipe(_byref(read), _byref(write), None, size) + res = _kernel32.CreatePipe(handles, handles + 1, _ffi.NULL, size) if not res: raise _WinError() - return _handle(read.value), _handle(write.value) + return _handle(handles[0]), _handle(handles[1]) def GetCurrentProcess(): - return _handle(_GetCurrentProcess()) + return _handle(_kernel32.GetCurrentProcess()) def DuplicateHandle(source_process, source, target_process, access, inherit, options=0): - target = _c_int() + # CPython: the first three arguments are expected to be integers + target = _ffi.new("HANDLE[1]") - res = _DuplicateHandle(int(source_process), int(source), int(target_process), - _byref(target), - access, inherit, options) + res = _kernel32.DuplicateHandle( + _ffi.cast("HANDLE", source_process), + _ffi.cast("HANDLE", source), + _ffi.cast("HANDLE", target_process), + target, access, inherit, options) if not res: raise _WinError() - return _handle(target.value) + return _handle(target[0]) + +def _z(input): + if input is None: + return _ffi.NULL + if isinstance(input, basestring): + return str(input) + raise TypeError("string/unicode/None expected, got %r" % ( + type(input).__name__,)) def CreateProcess(name, command_line, process_attr, thread_attr, inherit, flags, env, start_dir, startup_info): - si = _STARTUPINFO() + si = _ffi.new("STARTUPINFO *") if startup_info is not None: si.dwFlags = startup_info.dwFlags si.wShowWindow = startup_info.wShowWindow + # CPython: these three handles are expected to be _handle objects if startup_info.hStdInput: - si.hStdInput = int(startup_info.hStdInput) + si.hStdInput = startup_info.hStdInput.c_handle if startup_info.hStdOutput: - si.hStdOutput = int(startup_info.hStdOutput) + si.hStdOutput = startup_info.hStdOutput.c_handle if startup_info.hStdError: - si.hStdError = int(startup_info.hStdError) + si.hStdError = startup_info.hStdError.c_handle - pi = _PROCESS_INFORMATION() + pi = _ffi.new("PROCESS_INFORMATION *") flags |= CREATE_UNICODE_ENVIRONMENT if env is not None: @@ -164,47 +111,55 @@ envbuf += "%s=%s\0" % (k, v) envbuf += '\0' else: - envbuf = None + envbuf = _ffi.NULL - res = _CreateProcess(name, command_line, None, None, inherit, flags, envbuf, - start_dir, _byref(si), _byref(pi)) + res = _kernel32.CreateProcessA(_z(name), _z(command_line), _ffi.NULL, + _ffi.NULL, inherit, flags, envbuf, + _z(start_dir), si, pi) if not res: raise _WinError() - return _handle(pi.hProcess), _handle(pi.hThread), pi.dwProcessID, pi.dwThreadID + return _handle(pi.hProcess), _handle(pi.hThread), pi.dwProcessId, pi.dwThreadId def WaitForSingleObject(handle, milliseconds): - res = _WaitForSingleObject(int(handle), milliseconds) - + # CPython: the first argument is expected to be an integer. + res = _kernel32.WaitForSingleObject(_ffi.cast("HANDLE", handle), + milliseconds) if res < 0: raise _WinError() return res def GetExitCodeProcess(handle): - code = _c_int() + # CPython: the first argument is expected to be an integer. + code = _ffi.new("DWORD[1]") - res = _GetExitCodeProcess(int(handle), _byref(code)) + res = _kernel32.GetExitCodeProcess(_ffi.cast("HANDLE", handle), code) if not res: raise _WinError() - return code.value + return code[0] def TerminateProcess(handle, exitcode): - res = _TerminateProcess(int(handle), exitcode) + # CPython: the first argument is expected to be an integer. + # The second argument is silently wrapped in a UINT. + res = _kernel32.TerminateProcess(_ffi.cast("HANDLE", handle), + _ffi.cast("UINT", exitcode)) if not res: raise _WinError() def GetStdHandle(stdhandle): - res = _GetStdHandle(stdhandle) + stdhandle = _ffi.cast("DWORD", stdhandle) + res = _kernel32.GetStdHandle(stdhandle) if not res: return None else: - return res + # note: returns integer, not handle object + return int(_ffi.cast("intptr_t", res)) def CloseHandle(handle): res = _CloseHandle(handle) diff --git a/lib_pypy/cffi/_pycparser/__init__.py b/lib_pypy/cffi/_pycparser/__init__.py --- a/lib_pypy/cffi/_pycparser/__init__.py +++ b/lib_pypy/cffi/_pycparser/__init__.py @@ -10,7 +10,6 @@ __all__ = ['c_lexer', 'c_parser', 'c_ast'] __version__ = '2.14' -from subprocess import Popen, PIPE from .c_parser import CParser @@ -28,6 +27,7 @@ When successful, returns the preprocessed file's contents. Errors from cpp will be printed out. """ + from subprocess import Popen, PIPE path_list = [cpp_path] if isinstance(cpp_args, list): path_list += cpp_args diff --git a/lib_pypy/msvcrt.py b/lib_pypy/msvcrt.py --- a/lib_pypy/msvcrt.py +++ b/lib_pypy/msvcrt.py @@ -7,26 +7,39 @@ # XXX incomplete: implemented only functions needed by subprocess.py # PAC: 2010/08 added MS locking for Whoosh -import ctypes +# 07/2016: rewrote in CFFI + +import sys +if sys.platform != 'win32': + raise ImportError("The 'msvcrt' module is only available on Windows") + +import _rawffi +from _pypy_winbase_cffi import ffi as _ffi +_lib = _ffi.dlopen(_rawffi.get_libc().name) + import errno -from ctypes_support import standard_c_lib as _c -from ctypes_support import get_errno - -try: - open_osfhandle = _c._open_osfhandle -except AttributeError: # we are not on windows - raise ImportError try: from __pypy__ import builtinify, validate_fd except ImportError: builtinify = validate_fd = lambda f: f -open_osfhandle.argtypes = [ctypes.c_int, ctypes.c_int] -open_osfhandle.restype = ctypes.c_int +def _ioerr(): + e = _ffi.errno + raise IOError(e, errno.errorcode[e]) -_get_osfhandle = _c._get_osfhandle -_get_osfhandle.argtypes = [ctypes.c_int] -_get_osfhandle.restype = ctypes.c_int + +@builtinify +def open_osfhandle(fd, flags): + """"open_osfhandle(handle, flags) -> file descriptor + + Create a C runtime file descriptor from the file handle handle. The + flags parameter should be a bitwise OR of os.O_APPEND, os.O_RDONLY, + and os.O_TEXT. The returned file descriptor may be used as a parameter + to os.fdopen() to create a file object.""" + fd = _lib._open_osfhandle(fd, flags) + if fd == -1: + _ioerr() + return fd @builtinify def get_osfhandle(fd): @@ -38,62 +51,74 @@ validate_fd(fd) except OSError as e: raise IOError(*e.args) - return _get_osfhandle(fd) + result = _lib._get_osfhandle(fd) + if result == -1: + _ioerr() + return result -setmode = _c._setmode -setmode.argtypes = [ctypes.c_int, ctypes.c_int] -setmode.restype = ctypes.c_int +@builtinify +def setmode(fd, flags): + """setmode(fd, mode) -> Previous mode + + Set the line-end translation mode for the file descriptor fd. To set + it to text mode, flags should be os.O_TEXT; for binary, it should be + os.O_BINARY.""" + flags = _lib._setmode(fd, flags) + if flags == -1: + _ioerr() + return flags LK_UNLCK, LK_LOCK, LK_NBLCK, LK_RLCK, LK_NBRLCK = range(5) -_locking = _c._locking -_locking.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int] -_locking.restype = ctypes.c_int - @builtinify def locking(fd, mode, nbytes): - '''lock or unlock a number of bytes in a file.''' - rv = _locking(fd, mode, nbytes) + """"locking(fd, mode, nbytes) -> None + + Lock part of a file based on file descriptor fd from the C runtime. + Raises IOError on failure. The locked region of the file extends from + the current file position for nbytes bytes, and may continue beyond + the end of the file. mode must be one of the LK_* constants listed + below. Multiple regions in a file may be locked at the same time, but + may not overlap. Adjacent regions are not merged; they must be unlocked + individually.""" + rv = _lib._locking(fd, mode, nbytes) if rv != 0: - e = get_errno() - raise IOError(e, errno.errorcode[e]) + _ioerr() # Console I/O routines -kbhit = _c._kbhit -kbhit.argtypes = [] -kbhit.restype = ctypes.c_int +kbhit = _lib._kbhit -getch = _c._getch -getch.argtypes = [] -getch.restype = ctypes.c_char +@builtinify +def getch(): + return chr(_lib._getch()) -getwch = _c._getwch -getwch.argtypes = [] -getwch.restype = ctypes.c_wchar +@builtinify +def getwch(): + return unichr(_lib._getwch()) -getche = _c._getche -getche.argtypes = [] -getche.restype = ctypes.c_char +@builtinify +def getche(): + return chr(_lib._getche()) -getwche = _c._getwche -getwche.argtypes = [] -getwche.restype = ctypes.c_wchar +@builtinify +def getwche(): + return unichr(_lib._getwche()) -putch = _c._putch -putch.argtypes = [ctypes.c_char] -putch.restype = None +@builtinify +def putch(ch): + _lib._putch(ord(ch)) -putwch = _c._putwch -putwch.argtypes = [ctypes.c_wchar] -putwch.restype = None +@builtinify +def putwch(ch): + _lib._putwch(ord(ch)) -ungetch = _c._ungetch -ungetch.argtypes = [ctypes.c_char] -ungetch.restype = None +@builtinify +def ungetch(ch): + if _lib._ungetch(ord(ch)) == -1: # EOF + _ioerr() -ungetwch = _c._ungetwch -ungetwch.argtypes = [ctypes.c_wchar] -ungetwch.restype = None - -del ctypes +@builtinify +def ungetwch(ch): + if _lib._ungetwch(ord(ch)) == -1: # EOF + _ioerr() diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -40,7 +40,7 @@ "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "_continuation", "_cffi_backend", "_csv", "_pypyjson", "_posixsubprocess", # "cppyy", "micronumpy" - "faulthandler", + "faulthandler", "_jitlog", ]) from rpython.jit.backend import detect_cpu diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst --- a/pypy/doc/build.rst +++ b/pypy/doc/build.rst @@ -104,27 +104,24 @@ apt-get install gcc make libffi-dev pkg-config libz-dev libbz2-dev \ libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev libgdbm-dev \ - tk-dev libgc-dev liblzma-dev - -For the optional lzma module on PyPy3 you will also need ``liblzma-dev``. + tk-dev libgc-dev \ + liblzma-dev # For lzma on PyPy3. On Fedora:: dnf install gcc make libffi-devel pkgconfig zlib-devel bzip2-devel \ lib-sqlite3-devel ncurses-devel expat-devel openssl-devel tk-devel \ - gdbm-devel - -For the optional lzma module on PyPy3 you will also need ``xz-devel``. + gdbm-devel \ + xz-devel # For lzma on PyPy3. On SLES11:: zypper install gcc make python-devel pkg-config \ zlib-devel libopenssl-devel libbz2-devel sqlite3-devel \ - libexpat-devel libffi-devel python-curses + libexpat-devel libffi-devel python-curses \ + xz-devel # For lzma on PyPy3. (XXX plus the SLES11 version of libgdbm-dev and tk-dev) -For the optional lzma module on PyPy3 you will also need ``xz-devel``. - On Mac OS X, most of these build-time dependencies are installed alongside the Developer Tools. However, note that in order for the installation to find them you may need to run:: diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -377,10 +377,12 @@ * 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. + reproduced. Or, maybe we can download a VirtualBox or VMWare + virtual machine where the problem occurs. -* 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 giving us access would require us to use tools other than ssh, + make appointments, or 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. diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst --- a/pypy/doc/install.rst +++ b/pypy/doc/install.rst @@ -39,17 +39,16 @@ library. If you want to install 3rd party libraries, the most convenient way is -to install pip_ (unless you want to install virtualenv as explained -below; then you can directly use pip inside virtualenvs): +to install pip_ using ensurepip_ (unless you want to install virtualenv as +explained below; then you can directly use pip inside virtualenvs): .. code-block:: console - $ curl -O https://bootstrap.pypa.io/get-pip.py - $ ./pypy-2.1/bin/pypy get-pip.py - $ ./pypy-2.1/bin/pip install pygments # for example + $ ./pypy-xxx/bin/pypy -m ensurepip + $ ./pypy-xxx/bin/pip install pygments # for example -Third party libraries will be installed in ``pypy-2.1/site-packages``, and -the scripts in ``pypy-2.1/bin``. +Third party libraries will be installed in ``pypy-xxx/site-packages``, and +the scripts in ``pypy-xxx/bin``. Installing using virtualenv @@ -61,7 +60,7 @@ checkout:: # from a tarball - $ virtualenv -p /opt/pypy-c-jit-41718-3fb486695f20-linux/bin/pypy my-pypy-env + $ virtualenv -p /opt/pypy-xxx/bin/pypy my-pypy-env # from the mercurial checkout $ virtualenv -p /path/to/pypy/pypy/translator/goal/pypy-c my-pypy-env @@ -69,7 +68,7 @@ Note that bin/python is now a symlink to bin/pypy. .. _pip: http://pypi.python.org/pypi/pip - +.. _ensurepip: https://docs.python.org/2.7/library/ensurepip.html Building PyPy yourself ~~~~~~~~~~~~~~~~~~~~~~ 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 @@ -53,3 +53,51 @@ Refactor PyTupleObject to look like cpython's and allow subclassing PyTuple_Type + +.. branch: call-via-pyobj + +Use offsets from PyTypeObject to find actual c function to call rather than +fixed functions, allows function override after PyType_Ready is called + +.. branch: issue2335 + +Avoid exhausting the stack in the JIT due to successive guard +failures in the same Python function ending up as successive levels of +RPython functions, while at app-level the traceback is very short + +.. branch: use-madv-free + +Try harder to memory to the OS. See e.g. issue #2336. Note that it does +not show up as a reduction of the VIRT column in ``top``, and the RES +column might also not show the reduction, particularly on Linux >= 4.5 or +on OS/X: it uses MADV_FREE, which only marks the pages as returnable to +the OS if the memory is low. + +.. branch: cpyext-slotdefs2 + +Fill in more slots when creating a PyTypeObject from a W_TypeObject +More slots are still TBD, like tp_print and richcmp + +.. branch: json-surrogates + +Align json module decode with the cpython's impl, fixes issue 2345 + +.. branch: issue2343 + +Copy CPython's logic more closely for handling of ``__instancecheck__()`` +and ``__subclasscheck__()``. Fixes issue 2343. + +.. branch: msvcrt-cffi + +Rewrite the Win32 dependencies of 'subprocess' to use cffi instead +of ctypes. This avoids importing ctypes in many small programs and +scripts, which in turn avoids enabling threads (because ctypes +creates callbacks at import time, and callbacks need threads). + +.. branch: new-jit-log + +The new logging facility that integrates with and adds features to vmprof.com. + +.. branch: jitlog-32bit + +Resolve issues to use the new logging facility on a 32bit system diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py --- a/pypy/module/__builtin__/abstractinst.py +++ b/pypy/module/__builtin__/abstractinst.py @@ -43,9 +43,61 @@ raise # propagate other errors return space.type(w_obj) + +# ---------- isinstance ---------- + + +def p_recursive_isinstance_w(space, w_inst, w_cls): + # Copied straight from CPython 2.7. Does not handle 'cls' being a tuple. + if space.isinstance_w(w_cls, space.w_type): + return p_recursive_isinstance_type_w(space, w_inst, w_cls) + + check_class(space, w_cls, "isinstance() arg 2 must be a class, type," + " or tuple of classes and types") + try: + w_abstractclass = space.getattr(w_inst, space.wrap('__class__')) + except OperationError as e: + if e.async(space): # ignore most exceptions + raise + return False + else: + return p_abstract_issubclass_w(space, w_abstractclass, w_cls) + + +def p_recursive_isinstance_type_w(space, w_inst, w_type): + # subfunctionality of p_recursive_isinstance_w(): assumes that w_type is + # a type object. Copied straight from CPython 2.7. + if space.isinstance_w(w_inst, w_type): + return True + try: + w_abstractclass = space.getattr(w_inst, space.wrap('__class__')) + except OperationError as e: + if e.async(space): # ignore most exceptions + raise + else: + if w_abstractclass is not space.type(w_inst): + if space.isinstance_w(w_abstractclass, space.w_type): + return space.issubtype_w(w_abstractclass, w_type) + return False + + @jit.unroll_safe def abstract_isinstance_w(space, w_obj, w_klass_or_tuple, allow_override=False): """Implementation for the full 'isinstance(obj, klass_or_tuple)'.""" + # Copied from CPython 2.7's PyObject_Isinstance(). Additionally, + # if 'allow_override' is False (the default), then don't try to + # use a custom __instancecheck__ method. + + # WARNING: backward compatibility function name here. CPython + # uses the name "abstract" to refer to the logic of handling + # class-like objects, with a "__bases__" attribute. This function + # here is not related to that and implements the full + # PyObject_IsInstance() logic. + + # Quick test for an exact match + if space.type(w_obj) is w_klass_or_tuple: + return True + # -- case (anything, tuple) # XXX it might be risky that the JIT sees this if space.isinstance_w(w_klass_or_tuple, space.w_tuple): @@ -55,64 +107,55 @@ return False # -- case (anything, type) - try: - if allow_override: - w_result = space.isinstance_allow_override(w_obj, w_klass_or_tuple) - else: - w_result = space.isinstance(w_obj, w_klass_or_tuple) - except OperationError as e: # if w_klass_or_tuple was not a type, ignore it - if not e.match(space, space.w_TypeError): - raise # propagate other errors - else: - if space.is_true(w_result): - return True - # From now on we know that w_klass_or_tuple is indeed a type. - # Try also to compare it with obj.__class__, if this is not - # the same as type(obj). - w_pretendtype = abstract_getclass(space, w_obj) - try: - if space.is_w(w_pretendtype, space.type(w_obj)): - return False # common case: obj.__class__ is type(obj) - if not allow_override: - return space.issubtype_w(w_pretendtype, w_klass_or_tuple) - w_result = space.issubtype_allow_override(w_pretendtype, - w_klass_or_tuple) - except OperationError as e: - if e.async(space): - raise - return False # ignore most exceptions - else: - return space.is_true(w_result) + if allow_override: + w_check = space.lookup(w_klass_or_tuple, "__instancecheck__") + if w_check is not None: + # this is the common case: all type objects have a method + # __instancecheck__. The one in the base 'type' type calls + # back p_recursive_isinstance_type_w() from the present module. + return space.is_true(space.get_and_call_function( + w_check, w_klass_or_tuple, w_obj)) - return _abstract_isinstance_w_helper(space, w_obj, w_klass_or_tuple) + return p_recursive_isinstance_w(space, w_obj, w_klass_or_tuple) -def _abstract_isinstance_w_helper(space, w_obj, w_klass_or_tuple): - # -- case (anything, abstract-class) - check_class(space, w_klass_or_tuple, - "isinstance() arg 2 must be a class, type," - " or tuple of classes and types") - try: - w_abstractclass = space.getattr(w_obj, space.wrap('__class__')) - except OperationError as e: - if e.async(space): # ignore most exceptions - raise - return False - else: - return _issubclass_recurse(space, w_abstractclass, w_klass_or_tuple) +# ---------- issubclass ---------- @jit.unroll_safe -def _issubclass_recurse(space, w_derived, w_top): - """Internal helper for abstract cases. Here, w_top cannot be a tuple.""" - if space.is_w(w_derived, w_top): - return True - w_bases = _get_bases(space, w_derived) - if w_bases is not None: - for w_base in space.fixedview(w_bases): - if _issubclass_recurse(space, w_base, w_top): +def p_abstract_issubclass_w(space, w_derived, w_cls): + # Copied straight from CPython 2.7, function abstract_issubclass(). + # Don't confuse this with the function abstract_issubclass_w() below. + # Here, w_cls cannot be a tuple. + while True: + if space.is_w(w_derived, w_cls): + return True + w_bases = _get_bases(space, w_derived) + if w_bases is None: + return False + bases_w = space.fixedview(w_bases) + last_index = len(bases_w) - 1 + if last_index < 0: + return False + # Avoid recursivity in the single inheritance case; in general, + # don't recurse on the last item in the tuple (loop instead). + for i in range(last_index): + if p_abstract_issubclass_w(space, bases_w[i], w_cls): return True - return False + w_derived = bases_w[last_index] + + +def p_recursive_issubclass_w(space, w_derived, w_cls): + # From CPython's function of the same name (which as far as I can tell + # is not recursive). Copied straight from CPython 2.7. + if (space.isinstance_w(w_cls, space.w_type) and + space.isinstance_w(w_derived, space.w_type)): + return space.issubtype_w(w_derived, w_cls) + # + check_class(space, w_derived, "issubclass() arg 1 must be a class") + check_class(space, w_cls, "issubclass() arg 2 must be a class" + " or tuple of classes") + return p_abstract_issubclass_w(space, w_derived, w_cls) @jit.unroll_safe @@ -120,32 +163,46 @@ allow_override=False): """Implementation for the full 'issubclass(derived, klass_or_tuple)'.""" - # -- case (class-like-object, tuple-of-classes) + # WARNING: backward compatibility function name here. CPython + # uses the name "abstract" to refer to the logic of handling + # class-like objects, with a "__bases__" attribute. This function + # here is not related to that and implements the full + # PyObject_IsSubclass() logic. There is also p_abstract_issubclass_w(). + + # -- case (anything, tuple-of-classes) if space.isinstance_w(w_klass_or_tuple, space.w_tuple): for w_klass in space.fixedview(w_klass_or_tuple): if abstract_issubclass_w(space, w_derived, w_klass, allow_override): return True return False - # -- case (type, type) - try: - if not allow_override: - return space.issubtype_w(w_derived, w_klass_or_tuple) - w_result = space.issubtype_allow_override(w_derived, w_klass_or_tuple) - except OperationError as e: # if one of the args was not a type, ignore it - if not e.match(space, space.w_TypeError): - raise # propagate other errors - else: - return space.is_true(w_result) + # -- case (anything, type) + if allow_override: + w_check = space.lookup(w_klass_or_tuple, "__subclasscheck__") + if w_check is not None: + # this is the common case: all type objects have a method + # __subclasscheck__. The one in the base 'type' type calls + # back p_recursive_issubclass_w() from the present module. + return space.is_true(space.get_and_call_function( + w_check, w_klass_or_tuple, w_derived)) - check_class(space, w_derived, "issubclass() arg 1 must be a class") - # from here on, we are sure that w_derived is a class-like object + return p_recursive_issubclass_w(space, w_derived, w_klass_or_tuple) - # -- case (class-like-object, abstract-class) - check_class(space, w_klass_or_tuple, - "issubclass() arg 2 must be a class, type," - " or tuple of classes and types") - return _issubclass_recurse(space, w_derived, w_klass_or_tuple) + +# ------------------------------------------------------------ +# Exception helpers + +def exception_is_valid_obj_as_class_w(space, w_obj): + return BaseObjSpace.exception_is_valid_obj_as_class_w(space, w_obj) + +def exception_is_valid_class_w(space, w_cls): + return BaseObjSpace.exception_is_valid_class_w(space, w_cls) + +def exception_getclass(space, w_obj): + return BaseObjSpace.exception_getclass(space, w_obj) + +def exception_issubclass_w(space, w_cls1, w_cls2): + return BaseObjSpace.exception_issubclass_w(space, w_cls1, w_cls2) # ____________________________________________________________ # App-level interface diff --git a/pypy/module/__builtin__/test/test_abstractinst.py b/pypy/module/__builtin__/test/test_abstractinst.py --- a/pypy/module/__builtin__/test/test_abstractinst.py +++ b/pypy/module/__builtin__/test/test_abstractinst.py @@ -226,3 +226,26 @@ c = C() assert isinstance(c, C) assert not called + + def test_instancecheck_exception_not_eaten(self): + class M(object): + def __instancecheck__(self, obj): + raise TypeError("foobar") + + e = raises(TypeError, isinstance, 42, M()) + assert str(e.value) == "foobar" + + def test_issubclass_exception_not_eaten(self): + class M(object): + def __subclasscheck__(self, subcls): + raise TypeError("foobar") + + e = raises(TypeError, issubclass, 42, M()) + assert str(e.value) == "foobar" + + def test_issubclass_no_fallback(self): + class M(object): + def __subclasscheck__(self, subcls): + return False + + assert issubclass(42, M()) is False diff --git a/pypy/module/_jitlog/__init__.py b/pypy/module/_jitlog/__init__.py new file mode 100644 --- /dev/null +++ b/pypy/module/_jitlog/__init__.py @@ -0,0 +1,13 @@ +from pypy.interpreter.mixedmodule import MixedModule +from rpython.rlib.rvmprof import VMProfPlatformUnsupported + +class Module(MixedModule): + """ JitLog the new logging facility """ + appleveldefs = { + } + + interpleveldefs = { + 'enable': 'interp_jitlog.enable', + 'disable': 'interp_jitlog.disable', + 'JitlogError': 'space.fromcache(interp_jitlog.Cache).w_JitlogError', + } diff --git a/pypy/module/_jitlog/interp_jitlog.py b/pypy/module/_jitlog/interp_jitlog.py new file mode 100644 --- /dev/null +++ b/pypy/module/_jitlog/interp_jitlog.py @@ -0,0 +1,28 @@ +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.pyframe import PyFrame +from pypy.interpreter.pycode import PyCode +from pypy.interpreter.baseobjspace import W_Root +from rpython.rlib.rjitlog import rjitlog +from rpython.rlib import jit + +class Cache: + def __init__(self, space): + self.w_JitlogError = space.new_exception_class("_jitlog.JitlogError") + +def JitlogError(space, e): + w_JitlogError = space.fromcache(Cache).w_JitlogError + return OperationError(w_JitlogError, space.wrap(e.msg)) + +@unwrap_spec(fileno=int) +def enable(space, fileno): + """ Enable PyPy's logging facility. """ + try: + rjitlog.enable_jitlog(fileno) + except rjitlog.JitlogError, e: + raise JitlogError(space, e) + +@jit.dont_look_inside +def disable(space): + """ Disable PyPy's logging facility. """ + rjitlog.disable_jitlog() diff --git a/pypy/module/_jitlog/test/__init__.py b/pypy/module/_jitlog/test/__init__.py new file mode 100644 diff --git a/pypy/module/_jitlog/test/test__jitlog.py b/pypy/module/_jitlog/test/test__jitlog.py new file mode 100644 --- /dev/null +++ b/pypy/module/_jitlog/test/test__jitlog.py @@ -0,0 +1,52 @@ +import sys +import platform +from rpython.tool.udir import udir +from pypy.tool.pytest.objspace import gettestobjspace +from rpython.rlib.rjitlog import rjitlog as jl +from rpython.jit.metainterp.resoperation import opname + +class AppTestJitLog(object): + spaceconfig = {'usemodules': ['_jitlog', 'struct']} + + def setup_class(cls): + cls.w_tmpfilename = cls.space.wrap(str(udir.join('test__jitlog.1'))) + cls.w_mark_header = cls.space.wrap(jl.MARK_JITLOG_HEADER) + cls.w_version = cls.space.wrap(jl.JITLOG_VERSION_16BIT_LE) + cls.w_is_32bit = cls.space.wrap(sys.maxint == 2**31-1) + cls.w_machine = cls.space.wrap(platform.machine()) + cls.w_resops = cls.space.newdict() + space = cls.space + for key, value in opname.items(): + space.setitem(cls.w_resops, space.wrap(key), space.wrap(value)) + + def test_enable(self): + import _jitlog, struct + tmpfile = open(self.tmpfilename, 'wb') + fileno = tmpfile.fileno() + _jitlog.enable(fileno) + _jitlog.disable() + # no need to clsoe tmpfile, it is done by jitlog + + with open(self.tmpfilename, 'rb') as fd: + assert fd.read(1) == self.mark_header + assert fd.read(2) == self.version + assert bool(ord(fd.read(1))) == self.is_32bit + strcount, = struct.unpack('<i', fd.read(4)) + machine = fd.read(strcount) + assert machine == self.machine + # resoperations + count, = struct.unpack('<h', fd.read(2)) + opnames = set() + for i in range(count): + opnum = struct.unpack('<h', fd.read(2)) + strcount, = struct.unpack('<i', fd.read(4)) + opname = fd.read(strcount) + opnames.append((opnum, opname)) + + for opnum, opname in opnames: + # must be known resoperation + assert opnum in self.resops + # the name must equal + assert self.resops[opnum] == opname + + diff --git a/pypy/module/_pypyjson/interp_decoder.py b/pypy/module/_pypyjson/interp_decoder.py --- a/pypy/module/_pypyjson/interp_decoder.py +++ b/pypy/module/_pypyjson/interp_decoder.py @@ -363,10 +363,11 @@ hexdigits = self.getslice(start, i) try: val = int(hexdigits, 16) - if val & 0xfc00 == 0xd800: + if sys.maxunicode > 65535 and 0xd800 <= val <= 0xdfff: # surrogate pair - val = self.decode_surrogate_pair(i, val) - i += 6 + if self.ll_chars[i] == '\\' and self.ll_chars[i+1] == 'u': + val = self.decode_surrogate_pair(i, val) + i += 6 except ValueError: self._raise("Invalid \uXXXX escape (char %d)", i-1) return # help the annotator to know that we'll never go beyond @@ -378,8 +379,9 @@ return i def decode_surrogate_pair(self, i, highsurr): - if self.ll_chars[i] != '\\' or self.ll_chars[i+1] != 'u': - self._raise("Unpaired high surrogate at char %d", i) + """ uppon enter the following must hold: + chars[i] == "\\" and chars[i+1] == "u" + """ i += 2 hexdigits = self.getslice(i, i+4) lowsurr = int(hexdigits, 16) # the possible ValueError is caugth by the caller diff --git a/pypy/module/_pypyjson/test/test__pypyjson.py b/pypy/module/_pypyjson/test/test__pypyjson.py --- a/pypy/module/_pypyjson/test/test__pypyjson.py +++ b/pypy/module/_pypyjson/test/test__pypyjson.py @@ -183,6 +183,12 @@ res = _pypyjson.loads('"z\\ud834\\udd20x"') assert res == expected + def test_surrogate_pair(self): + import _pypyjson + json = '{"a":"\\uD83D"}' + res = _pypyjson.loads(json) + assert res == {u'a': u'\ud83d'} + def test_tab_in_string_should_fail(self): import _pypyjson # http://json.org/JSON_checker/test/fail25.json 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 @@ -2,6 +2,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt, wrap_oserror from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.typedef import interp_attrproperty from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.objspace.std.bytesobject import getbytevalue @@ -244,6 +245,7 @@ __new__ = interp2app(descr_new_cdll), ptr = interp2app(W_CDLL.ptr), getaddressindll = interp2app(W_CDLL.getaddressindll), + name = interp_attrproperty('name', W_CDLL), __doc__ = """ C Dynamically loaded library use CDLL(libname) to create a handle to a C library (the argument is processed the same way as dlopen processes it). On such a library you can call: 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 @@ -1215,6 +1215,11 @@ assert a[0] == b'd' a.free() + def test_cdll_name(self): + import _rawffi + lib = _rawffi.CDLL(self.lib_name) + assert lib.name == self.lib_name + class AppTestAutoFree: spaceconfig = dict(usemodules=['_rawffi', 'struct']) diff --git a/pypy/module/_vmprof/interp_vmprof.py b/pypy/module/_vmprof/interp_vmprof.py --- a/pypy/module/_vmprof/interp_vmprof.py +++ b/pypy/module/_vmprof/interp_vmprof.py @@ -3,7 +3,7 @@ from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pycode import PyCode from pypy.interpreter.baseobjspace import W_Root -from rpython.rlib import rvmprof +from rpython.rlib import rvmprof, jit # ____________________________________________________________ diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h --- a/pypy/module/cpyext/include/object.h +++ b/pypy/module/cpyext/include/object.h @@ -548,8 +548,10 @@ #define PyObject_TypeCheck(ob, tp) \ ((ob)->ob_type == (tp) || PyType_IsSubtype((ob)->ob_type, (tp))) -#define Py_TRASHCAN_SAFE_BEGIN(pyObj) -#define Py_TRASHCAN_SAFE_END(pyObj) +#define Py_TRASHCAN_SAFE_BEGIN(pyObj) do { +#define Py_TRASHCAN_SAFE_END(pyObj) ; } while(0); +/* note: the ";" at the start of Py_TRASHCAN_SAFE_END is needed + if the code has a label in front of the macro call */ /* Copied from CPython ----------------------------- */ PyAPI_FUNC(int) PyObject_AsReadBuffer(PyObject *, const void **, Py_ssize_t *); diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -1,4 +1,4 @@ -from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.lltypesystem import lltype, rffi, llmemory from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt @@ -10,9 +10,10 @@ from pypy.module.cpyext.api import ( CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O, METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function, - build_type_checkers, cpython_api, cpython_struct, generic_cpy_call) + build_type_checkers, cpython_api, cpython_struct, generic_cpy_call, + PyTypeObjectPtr) from pypy.module.cpyext.pyobject import ( - Py_DecRef, from_ref, make_ref, make_typedescr) + Py_DecRef, from_ref, make_ref, as_pyobj, make_typedescr) PyCFunction_typedef = rffi.COpaquePtr(typedef='PyCFunction') PyCFunction = lltype.Ptr(lltype.FuncType([PyObject, PyObject], PyObject)) @@ -151,28 +152,45 @@ class W_PyCWrapperObject(W_Root): def __init__(self, space, pto, method_name, wrapper_func, - wrapper_func_kwds, doc, func): + wrapper_func_kwds, doc, func, offset=None): self.space = space self.method_name = method_name self.wrapper_func = wrapper_func self.wrapper_func_kwds = wrapper_func_kwds self.doc = doc self.func = func + self.offset = offset pyo = rffi.cast(PyObject, pto) w_type = from_ref(space, pyo) assert isinstance(w_type, W_TypeObject) self.w_objclass = w_type def call(self, space, w_self, w_args, w_kw): + func_to_call = self.func + if self.offset: + pto = as_pyobj(space, self.w_objclass) + # make ptr the equivalent of this, using the offsets + #func_to_call = rffi.cast(rffi.VOIDP, ptr.c_tp_as_number.c_nb_multiply) + if pto: + cptr = rffi.cast(rffi.CCHARP, pto) + for o in self.offset: + ptr = rffi.cast(rffi.VOIDPP, rffi.ptradd(cptr, o))[0] + cptr = rffi.cast(rffi.CCHARP, ptr) + func_to_call = rffi.cast(rffi.VOIDP, cptr) + else: + # Should never happen, assert to get a traceback + assert False, "failed to convert w_type %s to PyObject" % str( + self.w_objclass) + assert func_to_call if self.wrapper_func is None: assert self.wrapper_func_kwds is not None - return self.wrapper_func_kwds(space, w_self, w_args, self.func, + return self.wrapper_func_kwds(space, w_self, w_args, func_to_call, w_kw) if space.is_true(w_kw): raise oefmt(space.w_TypeError, "wrapper %s doesn't take any keyword arguments", self.method_name) - return self.wrapper_func(space, w_self, w_args, self.func) + return self.wrapper_func(space, w_self, w_args, func_to_call) def descr_method_repr(self): return self.space.wrap(u"<slot wrapper '%s' of '%s' objects>" % @@ -298,12 +316,6 @@ def PyDescr_NewClassMethod(space, w_type, method): return space.wrap(W_PyCClassMethodObject(space, method, w_type)) -def PyDescr_NewWrapper(space, pto, method_name, wrapper_func, - wrapper_func_kwds, doc, func): - # not exactly the API sig - return space.wrap(W_PyCWrapperObject(space, pto, method_name, - wrapper_func, wrapper_func_kwds, doc, func)) - @cpython_api([lltype.Ptr(PyMethodDef), PyObject, CONST_STRING], PyObject) def Py_FindMethod(space, table, w_obj, name_ptr): """Return a bound method object for an extension type implemented in diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py --- a/pypy/module/cpyext/slotdefs.py +++ b/pypy/module/cpyext/slotdefs.py @@ -4,7 +4,7 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( - cpython_api, generic_cpy_call, PyObject, Py_TPFLAGS_CHECKTYPES, + cpython_api, generic_cpy_call, PyObject, Py_ssize_t, Py_TPFLAGS_CHECKTYPES, Py_buffer, mangle_name, pypy_decl) from pypy.module.cpyext.typeobjectdefs import ( unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc, @@ -380,6 +380,7 @@ ('tp_as_number.c_nb_absolute', '__abs__'), ('tp_as_number.c_nb_invert', '__invert__'), ('tp_as_number.c_nb_index', '__index__'), + ('tp_as_number.c_nb_hex', '__hex__'), ('tp_str', '__str__'), ('tp_repr', '__repr__'), ('tp_iter', '__iter__'), @@ -398,7 +399,7 @@ # binary functions for tp_name, attr in [('tp_as_number.c_nb_add', '__add__'), - ('tp_as_number.c_nb_subtract', '__subtract__'), + ('tp_as_number.c_nb_subtract', '__sub__'), ('tp_as_number.c_nb_multiply', '__mul__'), ('tp_as_number.c_nb_divide', '__div__'), ('tp_as_number.c_nb_remainder', '__mod__'), @@ -408,6 +409,8 @@ ('tp_as_number.c_nb_and', '__and__'), ('tp_as_number.c_nb_xor', '__xor__'), ('tp_as_number.c_nb_or', '__or__'), + ('tp_as_sequence.c_sq_concat', '__add__'), + ('tp_as_sequence.c_sq_inplace_concat', '__iadd__') ]: if name == tp_name: slot_fn = w_type.getdictvalue(space, attr) @@ -421,8 +424,26 @@ api_func = slot_func.api_func handled = True + # binary-with-Py_ssize_t-type + for tp_name, attr in [('tp_as_sequence.c_sq_item', '__getitem'), + ('tp_as_sequence.c_sq_repeat', '__mul__'), + ('tp_as_sequence.c_sq_repeat', '__mul__'), + ('tp_as_sequence.c_sq_inplace_repeat', '__imul__'), + ]: + if name == tp_name: + slot_fn = w_type.getdictvalue(space, attr) + if slot_fn is None: + return + + @cpython_api([PyObject, Py_ssize_t], PyObject, header=header) + @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) + def slot_func(space, w_self, arg): + return space.call_function(slot_fn, w_self, space.wrap(arg)) + api_func = slot_func.api_func + handled = True + # ternary functions - for tp_name, attr in [('tp_as_number.c_nb_power', ''), + for tp_name, attr in [('tp_as_number.c_nb_power', '__pow__'), ]: if name == tp_name: slot_fn = w_type.getdictvalue(space, attr) @@ -522,6 +543,8 @@ api_func = slot_tp_new.api_func else: # missing: tp_as_number.nb_nonzero, tp_as_number.nb_coerce + # tp_as_sequence.c_sq_contains, tp_as_sequence.c_sq_length + # richcmpfunc(s) return return lambda: llhelper(api_func.functype, api_func.get_wrapper(space)) 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 @@ -2604,6 +2604,13 @@ } +static PyObject * +switch_multiply(void) +{ + Arraytype.tp_as_number->nb_multiply = array_base_multiply; + Py_RETURN_NONE; +}; + PyDoc_STRVAR(module_doc, "This module defines an object type which can efficiently represent\n\ an array of basic values: characters, integers, floating point\n\ @@ -2855,6 +2862,7 @@ static PyMethodDef a_methods[] = { {"_array_reconstructor", array_reconstructor, METH_VARARGS, PyDoc_STR("Internal. Used for pickling support.")}, + {"switch_multiply", (PyCFunction)switch_multiply, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/pypy/module/cpyext/test/test_arraymodule.py b/pypy/module/cpyext/test/test_arraymodule.py --- a/pypy/module/cpyext/test/test_arraymodule.py +++ b/pypy/module/cpyext/test/test_arraymodule.py @@ -74,3 +74,7 @@ arr = module.array('i', [2]) res = [1, 2, 3] * arr assert res == [1, 2, 3, 1, 2, 3] + module.switch_multiply() + res = [1, 2, 3] * arr + assert res == [2, 4, 6] + diff --git a/pypy/module/cpyext/test/test_bytearrayobject.py b/pypy/module/cpyext/test/test_bytearrayobject.py --- a/pypy/module/cpyext/test/test_bytearrayobject.py +++ b/pypy/module/cpyext/test/test_bytearrayobject.py @@ -87,11 +87,12 @@ module = self.import_extension('foo', [ ("getbytearray", "METH_NOARGS", """ - PyObject* s1 = PyByteArray_FromStringAndSize("test", 4); + const char *c; + PyObject *s2, *s1 = PyByteArray_FromStringAndSize("test", 4); if (s1 == NULL) return NULL; - const char* c = PyByteArray_AsString(s1); - PyObject* s2 = PyByteArray_FromStringAndSize(c, 4); + c = PyByteArray_AsString(s1); + s2 = PyByteArray_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 @@ -126,7 +126,14 @@ source_strings=source_strings, compile_extra=compile_extra, link_extra=link_extra) - return str(soname) + from imp import get_suffixes, C_EXTENSION + pydname = soname + for suffix, mode, typ in get_suffixes(): + if typ == C_EXTENSION: + pydname = soname.new(purebasename=modname, ext=suffix) + soname.rename(pydname) + break + return str(pydname) def freeze_refcnts(self): rawrefcount._dont_free_any_more() @@ -358,7 +365,11 @@ space.sys.get('modules'), space.wrap(name)) else: - return os.path.dirname(mod) + path = os.path.dirname(mod) + if self.runappdirect: + return path + else: + return space.wrap(path) @gateway.unwrap_spec(mod=str, name=str) def reimport_module(space, mod, name): diff --git a/pypy/module/cpyext/test/test_datetime.py b/pypy/module/cpyext/test/test_datetime.py --- a/pypy/module/cpyext/test/test_datetime.py +++ b/pypy/module/cpyext/test/test_datetime.py @@ -176,13 +176,15 @@ """), ("test_datetime_macros", "METH_NOARGS", """ + PyObject* obj; + PyDateTime_DateTime *dt; PyDateTime_IMPORT; if (!PyDateTimeAPI) { PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI"); return NULL; } - PyObject* obj = PyDateTime_FromDateAndTime(2000, 6, 6, 6, 6, 6, 6); - PyDateTime_DateTime* dt = (PyDateTime_DateTime*)obj; + obj = PyDateTime_FromDateAndTime(2000, 6, 6, 6, 6, 6, 6); + dt = (PyDateTime_DateTime*)obj; PyDateTime_GET_YEAR(obj); PyDateTime_GET_YEAR(dt); @@ -209,13 +211,15 @@ """), ("test_time_macros", "METH_NOARGS", """ + PyObject* obj; + PyDateTime_Time* t; PyDateTime_IMPORT; if (!PyDateTimeAPI) { PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI"); return NULL; } - PyObject* obj = PyTime_FromTime(6, 6, 6, 6); - PyDateTime_Time* t = (PyDateTime_Time*)obj; + obj = PyTime_FromTime(6, 6, 6, 6); + t = (PyDateTime_Time*)obj; PyDateTime_TIME_GET_HOUR(obj); PyDateTime_TIME_GET_HOUR(t); @@ -233,13 +237,15 @@ """), ("test_delta_macros", "METH_NOARGS", """ + PyObject* obj; + PyDateTime_Delta* delta; PyDateTime_IMPORT; if (!PyDateTimeAPI) { PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI"); return NULL; } - PyObject* obj = PyDelta_FromDSU(6, 6, 6); - PyDateTime_Delta* delta = (PyDateTime_Delta*)obj; + obj = PyDelta_FromDSU(6, 6, 6); + delta = (PyDateTime_Delta*)obj; #if defined(PYPY_VERSION) || PY_VERSION_HEX >= 0x03030000 // These macros are only defined in CPython 3.x and PyPy. diff --git a/pypy/module/cpyext/test/test_import.py b/pypy/module/cpyext/test/test_import.py --- a/pypy/module/cpyext/test/test_import.py +++ b/pypy/module/cpyext/test/test_import.py @@ -39,7 +39,6 @@ class AppTestImportLogic(AppTestCpythonExtensionBase): def test_import_logic(self): - skip("leak?") path = self.import_module(name='test_import_module', load_it=False) import sys sys.path.append(path) diff --git a/pypy/module/cpyext/test/test_listobject.py b/pypy/module/cpyext/test/test_listobject.py --- a/pypy/module/cpyext/test/test_listobject.py +++ b/pypy/module/cpyext/test/test_listobject.py @@ -64,7 +64,7 @@ assert space.unwrap(w_s) == [2, 1] class AppTestListObject(AppTestCpythonExtensionBase): - def test_listobject(self): + def test_basic_listobject(self): import sys module = self.import_extension('foo', [ ("newlist", "METH_NOARGS", @@ -104,6 +104,15 @@ Py_RETURN_NONE; """ ), + ('test_tp_as_', "METH_NOARGS", + ''' + PyObject *l = PyList_New(3); + int ok = l->ob_type->tp_as_sequence != NULL; /* 1 */ + ok += 2 * (l->ob_type->tp_as_number == NULL); /* 2 */ + Py_DECREF(l); + return PyLong_FromLong(ok); /* should be 3 */ + ''' + ), ]) l = module.newlist() assert l == [3, -5, 1000] @@ -137,6 +146,9 @@ module.setlistitem(l,0) assert l == [None, 2, 3] + # tp_as_sequence should be filled, but tp_as_number should be NULL + assert module.test_tp_as_() == 3 + def test_list_macros(self): """The PyList_* macros cast, and calls expecting that build.""" module = self.import_extension('foo', [ diff --git a/pypy/module/cpyext/test/test_longobject.py b/pypy/module/cpyext/test/test_longobject.py --- a/pypy/module/cpyext/test/test_longobject.py +++ b/pypy/module/cpyext/test/test_longobject.py @@ -232,4 +232,40 @@ """)]) assert module.from_str() == 0 - + def test_slots(self): + module = self.import_extension('foo', [ + ("has_sub", "METH_NOARGS", + """ + PyObject *ret, *obj = PyLong_FromLong(42); + if (obj->ob_type->tp_as_number->nb_subtract) + ret = obj->ob_type->tp_as_number->nb_subtract(obj, obj); + else + ret = PyLong_FromLong(-1); + Py_DECREF(obj); + return ret; + """), + ("has_pow", "METH_NOARGS", + """ + PyObject *ret, *obj = PyLong_FromLong(42); + PyObject *one = PyLong_FromLong(1); + if (obj->ob_type->tp_as_number->nb_power) + ret = obj->ob_type->tp_as_number->nb_power(obj, one, one); + else + ret = PyLong_FromLong(-1); + Py_DECREF(obj); + return ret; + """), + ("has_hex", "METH_NOARGS", + """ + PyObject *ret, *obj = PyLong_FromLong(42); + if (obj->ob_type->tp_as_number->nb_hex) + ret = obj->ob_type->tp_as_number->nb_hex(obj); + else + ret = PyLong_FromLong(-1); + Py_DECREF(obj); + return ret; + """)]) + assert module.has_sub() == 0 + assert module.has_pow() == 0 + assert module.has_hex() == '0x2aL' + diff --git a/pypy/module/cpyext/test/test_number.py b/pypy/module/cpyext/test/test_number.py --- a/pypy/module/cpyext/test/test_number.py +++ b/pypy/module/cpyext/test/test_number.py @@ -62,3 +62,14 @@ api.PyNumber_Power(space.wrap(3), space.wrap(2), space.wrap(5))) assert 9 == space.unwrap( api.PyNumber_InPlacePower(space.wrap(3), space.wrap(2), space.w_None)) + + def test_PyNumber_Check(self): + mod = self.import_extension('foo', [ + ("test_PyNumber_Check", "METH_VARARGS", + ''' + PyObject *obj = PyTuple_GET_ITEM(args, 0); + int val = PyNumber_Check(obj); + return PyLong_FromLong(val); + ''')]) + val = mod.test_PyNumber_Check(10) + assert val == 1 diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py --- a/pypy/module/cpyext/test/test_typeobject.py +++ b/pypy/module/cpyext/test/test_typeobject.py @@ -710,7 +710,7 @@ x = list(it) assert x == [1] - def test_bool(self): + def test_intlike(self): module = self.import_extension('foo', [ ("newInt", "METH_VARARGS", """ @@ -720,10 +720,6 @@ if (!PyArg_ParseTuple(args, "i", &intval)) return NULL; - IntLike_Type.tp_flags |= Py_TPFLAGS_DEFAULT; - IntLike_Type.tp_as_number = &intlike_as_number; - intlike_as_number.nb_bool = intlike_nb_bool; - if (PyType_Ready(&IntLike_Type) < 0) return NULL; intObj = PyObject_New(IntLikeObject, &IntLike_Type); if (!intObj) { return NULL; @@ -731,8 +727,23 @@ intObj->value = intval; return (PyObject *)intObj; - """)], - """ + """), + ("check", "METH_VARARGS", """ + IntLikeObject *intObj; + int intval, isint; + + if (!PyArg_ParseTuple(args, "i", &intval)) + return NULL; + intObj = PyObject_New(IntLikeObject, &IntLike_Type); + if (!intObj) { + return NULL; + } + intObj->value = intval; + isint = PyNumber_Check((PyObject*)intObj); + Py_DECREF((PyObject*)intObj); + return PyLong_FromLong(isint); + """), + ], prologue= """ typedef struct { PyObject_HEAD @@ -751,6 +762,13 @@ return v->value; } + static PyObject* + intlike_nb_int(PyObject* o) + { + IntLikeObject *v = (IntLikeObject*)o; + return PyLong_FromLong(v->value); + } + PyTypeObject IntLike_Type = { PyObject_HEAD_INIT(0) /*ob_size*/ 0, @@ -758,11 +776,19 @@ /*tp_basicsize*/ sizeof(IntLikeObject), }; static PyNumberMethods intlike_as_number; + """, more_init=""" + IntLike_Type.tp_flags |= Py_TPFLAGS_DEFAULT; + IntLike_Type.tp_as_number = &intlike_as_number; + intlike_as_number.nb_bool = intlike_nb_nonzero; + intlike_as_number.nb_int = intlike_nb_int; + PyType_Ready(&IntLike_Type); """) assert not bool(module.newInt(0)) assert bool(module.newInt(1)) raises(SystemError, bool, module.newInt(-1)) raises(ValueError, bool, module.newInt(-42)) + val = module.check(10); + assert val == 1 def test_mathfunc(self): module = self.import_extension('foo', [ 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 @@ -17,9 +17,9 @@ generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL, Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder, - PyObjectFields, Py_TPFLAGS_BASETYPE, Py_buffer) + PyObjectFields, Py_TPFLAGS_BASETYPE, Py_buffer, PyTypeObject, PyTypeObjectPtr) from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject, - PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef, + W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef, W_PyCMethodObject, W_PyCFunctionObject) from pypy.module.cpyext.modsupport import convert_method_defs from pypy.module.cpyext.pyobject import ( @@ -30,7 +30,7 @@ from pypy.module.cpyext.state import State from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne from pypy.module.cpyext.typeobjectdefs import ( - PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc, + PyGetSetDef, PyMemberDef, newfunc, PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs) from pypy.objspace.std.typeobject import W_TypeObject, find_best_base @@ -238,7 +238,7 @@ i += 1 def update_all_slots(space, w_type, pto): - # XXX fill slots in pto + # fill slots in pto # Not very sure about it, but according to # test_call_tp_dealloc_when_created_from_python, we should not # overwrite slots that are already set: these ones are probably @@ -272,6 +272,15 @@ if len(slot_names) == 1: if not getattr(pto, slot_names[0]): setattr(pto, slot_names[0], slot_func_helper) + elif (w_type.getname(space) in ('list', 'tuple') and + slot_names[0] == 'c_tp_as_number'): + # XXX hack - hwo can we generalize this? The problem is method + # names like __mul__ map to more than one slot, and we have no + # convenient way to indicate which slots CPython have filled + # + # We need at least this special case since Numpy checks that + # (list, tuple) do __not__ fill tp_as_number + pass else: assert len(slot_names) == 2 struct = getattr(pto, slot_names[0]) @@ -296,6 +305,7 @@ for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers: if method_name in dict_w: continue + offset = [rffi.offsetof(lltype.typeOf(pto).TO, slot_names[0])] if len(slot_names) == 1: func = getattr(pto, slot_names[0]) else: @@ -303,14 +313,16 @@ struct = getattr(pto, slot_names[0]) if not struct: continue + offset.append(rffi.offsetof(lltype.typeOf(struct).TO, slot_names[1])) func = getattr(struct, slot_names[1]) func_voidp = rffi.cast(rffi.VOIDP, func) if not func: continue if wrapper_func is None and wrapper_func_kwds is None: continue - dict_w[method_name] = PyDescr_NewWrapper(space, pto, method_name, wrapper_func, - wrapper_func_kwds, doc, func_voidp) + w_obj = W_PyCWrapperObject(space, pto, method_name, wrapper_func, + wrapper_func_kwds, doc, func_voidp, offset=offset) + dict_w[method_name] = space.wrap(w_obj) if pto.c_tp_new: add_tp_new_wrapper(space, dict_w, pto) @@ -637,6 +649,7 @@ try: w_obj = _type_realize(space, py_obj) finally: + name = rffi.charp2str(pto.c_tp_name) pto.c_tp_flags &= ~Py_TPFLAGS_READYING pto.c_tp_flags |= Py_TPFLAGS_READY return w_obj @@ -718,7 +731,8 @@ base = pto.c_tp_base base_pyo = rffi.cast(PyObject, pto.c_tp_base) if base and not base.c_tp_flags & Py_TPFLAGS_READY: - type_realize(space, rffi.cast(PyObject, base_pyo)) + name = rffi.charp2str(base.c_tp_name) + type_realize(space, base_pyo) if base and not pto.c_ob_type: # will be filled later pto.c_ob_type = base.c_ob_type if not pto.c_tp_bases: diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -254,7 +254,7 @@ idx = space.str_w(w_idx) return self.getfield(space, idx) if space.is_w(w_idx, space.w_Ellipsis): - return self + return self.descr_view(space, space.type(self)) elif isinstance(w_idx, W_NDimArray) and w_idx.get_dtype().is_bool(): if w_idx.ndims() > 0: w_ret = self.getitem_filter(space, w_idx) diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -2605,17 +2605,11 @@ import numpy as np import sys a = np.array(1.5) - if '__pypy__' in sys.builtin_module_names: - assert a[...] is a - else: - assert a[...].base is a + assert a[...].base is a a[...] = 2.5 assert a == 2.5 a = np.array([1, 2, 3]) - if '__pypy__' in sys.builtin_module_names: - assert a[...] is a - else: - assert a[...].base is a + assert a[...].base is a a[...] = 4 assert (a == [4, 4, 4]).all() assert a[..., 0] == 4 diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -6,6 +6,7 @@ from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside from rpython.rlib import jit, jit_hooks +from rpython.rlib.rjitlog import rjitlog as jl from rpython.rlib.jit import current_trace_length, unroll_parameters,\ JitHookInterface from rpython.rtyper.annlowlevel import cast_instance_to_gcref @@ -42,6 +43,19 @@ from rpython.rlib import rvmprof return rvmprof.get_unique_id(bytecode) +@jl.returns(jl.MP_FILENAME, jl.MP_LINENO, + jl.MP_SCOPE, jl.MP_INDEX, jl.MP_OPCODE) +def get_location(next_instr, is_being_profiled, bytecode): + from pypy.tool.stdlib_opcode import opcode_method_names + bcindex = ord(bytecode.co_code[next_instr]) + opname = "" + if 0 <= bcindex < len(opcode_method_names): + opname = opcode_method_names[bcindex] + name = bytecode.co_name + if not name: + name = "" + return (bytecode.co_filename, bytecode.co_firstlineno, + name, intmask(next_instr), opname) def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode): return (bytecode.co_flags & CO_GENERATOR) != 0 @@ -52,6 +66,7 @@ virtualizables = ['frame'] pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location, + get_location = get_location, get_unique_id = get_unique_id, should_unroll_one_iteration = should_unroll_one_iteration, diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -57,7 +57,10 @@ cmdline.append(str(self.filepath)) # env = os.environ.copy() + # TODO old logging system env['PYPYLOG'] = self.log_string + ':' + str(logfile) + jitlogfile = str(logfile) + '.jlog' + env['JITLOG'] = str(jitlogfile) pipe = subprocess.Popen(cmdline, env=env, stdout=subprocess.PIPE, @@ -84,6 +87,7 @@ log = Log(rawtraces) log.result = eval(stdout) log.logfile = str(logfile) + log.jitlogfile = jitlogfile # summaries = logparser.extract_category(rawlog, 'jit-summary') if len(summaries) > 0: diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -424,6 +424,7 @@ --TICK-- i123 = arraylen_gc(p67, descr=<ArrayP .>) i119 = call_i(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=<Calli . i EF=5 OS=110>) + check_memory_error(i119) raw_store(i119, 0, i160, descr=<ArrayS 2>) raw_store(i119, 2, i160, descr=<ArrayS 2>) raw_store(i119, 4, i160, descr=<ArrayS 2>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py b/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py --- a/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py +++ b/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py @@ -8,7 +8,6 @@ mangle_descr) from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC - class TestLogParser(BaseTestPyPyC): log_string = 'jit-log-opt,jit-backend' diff --git a/pypy/module/thread/os_lock.py b/pypy/module/thread/os_lock.py --- a/pypy/module/thread/os_lock.py +++ b/pypy/module/thread/os_lock.py @@ -8,15 +8,13 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, make_weakref_descr -from pypy.interpreter.error import OperationError, oefmt -from rpython.rlib.rarithmetic import r_longlong, ovfcheck +from pypy.interpreter.error import oefmt +from rpython.rlib.rarithmetic import ( + r_longlong, ovfcheck, ovfcheck_float_to_longlong) # Force the declaration of the type 'thread.LockType' for RPython #import pypy.module.thread.rpython.exttable -LONGLONG_MAX = r_longlong(2 ** (r_longlong.BITS-1) - 1) -TIMEOUT_MAX = LONGLONG_MAX - RPY_LOCK_FAILURE, RPY_LOCK_ACQUIRED, RPY_LOCK_INTR = range(3) def parse_acquire_args(space, blocking, timeout): @@ -31,10 +29,12 @@ elif timeout == -1.0: microseconds = -1 else: - timeout *= 1e6 - if timeout > float(TIMEOUT_MAX): + # 0.0 => 0.0, but otherwise tends to round up + timeout = timeout * 1e6 + 0.999 + try: + microseconds = ovfcheck_float_to_longlong(timeout) + except OverflowError: raise oefmt(space.w_OverflowError, "timeout value is too large") - microseconds = r_longlong(timeout) return microseconds @@ -47,7 +47,8 @@ # Run signal handlers if we were interrupted space.getexecutioncontext().checksignals() if microseconds >= 0: - microseconds = r_longlong(endtime - (time.time() * 1e6)) + microseconds = r_longlong((endtime - (time.time() * 1e6)) + + 0.999) # Check for negative values, since those mean block _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit