Author: Ronan Lamy <[email protected]>
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)
+
[email protected]_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)
[email protected](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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit