Author: Matti Picus <matti.pi...@gmail.com>
Branch: cpyext-add_newdoc
Changeset: r91785:b2f03ffd8457
Date: 2017-07-07 10:53 +0300
http://bitbucket.org/pypy/pypy/changeset/b2f03ffd8457/

Log:    merge default into branch

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
@@ -21,3 +21,7 @@
 .. branch: issue-2592
 
 CPyext PyListObject.pop must return the value
+
+.. branch: cpyext-hash_notimpl
+
+If ``tp_hash`` is ``PyObject_HashNotImplemented``, set 
``obj.__dict__['__hash__']`` to None
diff --git a/pypy/module/_cffi_backend/errorbox.py 
b/pypy/module/_cffi_backend/errorbox.py
--- a/pypy/module/_cffi_backend/errorbox.py
+++ b/pypy/module/_cffi_backend/errorbox.py
@@ -86,8 +86,6 @@
                 return
 
             w_text = self.space.call_function(w_done)
-            # XXX Python 3: MessageBoxA() => MessageBoxW()
-
             p = rffi.str2charp(self.space.bytes_w(w_text),
                                track_allocation=False)
             if self.text_p:
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -456,13 +456,15 @@
     return decorate
 
 def api_func_from_cdef(func, cdef, cts,
-        error=_NOT_SPECIFIED, header=DEFAULT_HEADER):
+        error=_NOT_SPECIFIED, header=DEFAULT_HEADER,
+        result_is_ll=False):
     func._always_inline_ = 'try'
     cdecl = cts.parse_func(cdef)
     RESULT = cdecl.get_llresult(cts)
     api_function = ApiFunction(
         cdecl.get_llargs(cts), RESULT, func,
-        error=_compute_error(error, RESULT), cdecl=cdecl)
+        error=_compute_error(error, RESULT), cdecl=cdecl,
+        result_is_ll=result_is_ll)
     FUNCTIONS_BY_HEADER[header][cdecl.name] = api_function
     unwrapper = api_function.get_unwrapper()
     unwrapper.func = func
@@ -656,10 +658,12 @@
 
 
 class CpyextTypeSpace(CTypeSpace):
-    def decl(self, cdef, error=_NOT_SPECIFIED, header=DEFAULT_HEADER):
+    def decl(self, cdef, error=_NOT_SPECIFIED, header=DEFAULT_HEADER,
+            result_is_ll=False):
         def decorate(func):
             return api_func_from_cdef(
-                    func, cdef, self, error=error, header=header)
+                func, cdef, self, error=error, header=header,
+                result_is_ll=result_is_ll)
         return decorate
 
 
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -1,10 +1,171 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib import rgc  # Force registration of gc.collect
+from rpython.rlib.buffer import RawBuffer
 from pypy.interpreter.error import oefmt
+from pypy.interpreter.buffer import BufferView
 from pypy.module.cpyext.api import (
-    cpython_api, CANNOT_FAIL, cts, Py_buffer,
-    Py_ssize_t, Py_ssize_tP, generic_cpy_call,
+    cpython_api, Py_buffer, Py_ssize_t, Py_ssize_tP, CONST_STRINGP, cts,
+    generic_cpy_call,
     PyBUF_WRITABLE, PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES)
-from pypy.module.cpyext.pyobject import PyObject, Py_IncRef
+from pypy.module.cpyext.typeobjectdefs import releasebufferproc
+from pypy.module.cpyext.pyobject import PyObject, incref, decref, as_pyobj
+
+class CBuffer(RawBuffer):
+    _immutable_ = True
+    def __init__(self, view):
+        self.view = view
+        self.readonly = view.readonly
+
+    def getlength(self):
+        return self.view.getlength()
+
+    def getitem(self, index):
+        return self.view.ptr[index]
+
+    def getslice(self, start, stop, step, size):
+        assert step == 1
+        assert stop - start == size
+        ptr = rffi.ptradd(cts.cast('char *', self.view.ptr), start)
+        return rffi.charpsize2str(ptr, size)
+
+    def setitem(self, index, char):
+        self.view.ptr[index] = char
+
+    def setslice(self, index, s):
+        assert s is not None
+        ptr = rffi.ptradd(cts.cast('char *', self.view.ptr), index)
+        rffi.str2chararray(s, ptr, len(s))
+
+    def get_raw_address(self):
+        return cts.cast('char *', self.view.ptr)
+
+class CPyBuffer(BufferView):
+    # Similar to Py_buffer
+    _immutable_ = True
+
+    def __init__(self, space, ptr, size, w_obj, format='B', shape=None,
+                 strides=None, ndim=1, itemsize=1, readonly=True,
+                 needs_decref=False,
+                 releasebufferproc=rffi.cast(rffi.VOIDP, 0)):
+        self.space = space
+        self.ptr = ptr
+        self.size = size
+        self.w_obj = w_obj  # kept alive
+        self.pyobj = as_pyobj(space, w_obj)
+        self.format = format
+        self.ndim = ndim
+        self.itemsize = itemsize
+
+        if not shape:
+            self.shape = [size]
+        else:
+            self.shape = shape
+        if not strides:
+            self.strides = [1]
+        else:
+            self.strides = strides
+        self.readonly = readonly
+        self.needs_decref = needs_decref
+        self.releasebufferproc = releasebufferproc
+
+    def releasebuffer(self):
+        if self.pyobj:
+            if self.needs_decref:
+                if self.releasebufferproc:
+                    func_target = rffi.cast(releasebufferproc, 
self.releasebufferproc)
+                    with lltype.scoped_alloc(Py_buffer) as pybuf:
+                        pybuf.c_buf = self.ptr
+                        pybuf.c_len = self.size
+                        pybuf.c_ndim = cts.cast('int', self.ndim)
+                        pybuf.c_shape = cts.cast('Py_ssize_t*', pybuf.c__shape)
+                        pybuf.c_strides = cts.cast('Py_ssize_t*', 
pybuf.c__strides)
+                        for i in range(self.ndim):
+                            pybuf.c_shape[i] = self.shape[i]
+                            pybuf.c_strides[i] = self.strides[i]
+                        if self.format:
+                            pybuf.c_format = rffi.str2charp(self.format)
+                        else:
+                            pybuf.c_format = rffi.str2charp("B")
+                        generic_cpy_call(self.space, func_target, self.pyobj, 
pybuf)
+                decref(self.space, self.pyobj)
+            self.pyobj = lltype.nullptr(PyObject.TO)
+        else:
+            #do not call twice
+            return
+
+    def getlength(self):
+        return self.size
+
+    def getbytes(self, start, size):
+        return ''.join([self.ptr[i] for i in range(start, start + size)])
+
+    def setbytes(self, start, string):
+        # absolutely no safety checks, what could go wrong?
+        for i in range(len(string)):
+            self.ptr[start + i] = string[i]
+
+    def as_str(self):
+        return CBuffer(self).as_str()
+
+    def as_readbuf(self):
+        return CBuffer(self)
+
+    def as_writebuf(self):
+        assert not self.readonly
+        return CBuffer(self)
+
+    def get_raw_address(self):
+        return rffi.cast(rffi.CCHARP, self.ptr)
+
+    def getformat(self):
+        return self.format
+
+    def getshape(self):
+        return self.shape
+
+    def getstrides(self):
+        return self.strides
+
+    def getitemsize(self):
+        return self.itemsize
+
+    def getndim(self):
+        return self.ndim
+
+class FQ(rgc.FinalizerQueue):
+    Class = CPyBuffer
+    def finalizer_trigger(self):
+        while 1:
+            buf  = self.next_dead()
+            if not buf:
+                break
+            buf.releasebuffer()
+
+fq = FQ()
+
+
+@cpython_api([PyObject, CONST_STRINGP, Py_ssize_tP], rffi.INT_real, error=-1)
+def PyObject_AsCharBuffer(space, obj, bufferp, sizep):
+    """Returns a pointer to a read-only memory location usable as
+    character-based input.  The obj argument must support the single-segment
+    character buffer interface.  On success, returns 0, sets buffer to the
+    memory location and size to the buffer length.  Returns -1 and sets a
+    TypeError on error.
+    """
+    pto = obj.c_ob_type
+    pb = pto.c_tp_as_buffer
+    if not (pb and pb.c_bf_getreadbuffer and pb.c_bf_getsegcount):
+        raise oefmt(space.w_TypeError, "expected a character buffer object")
+    if generic_cpy_call(space, pb.c_bf_getsegcount,
+                        obj, lltype.nullptr(Py_ssize_tP.TO)) != 1:
+        raise oefmt(space.w_TypeError,
+                    "expected a single-segment buffer object")
+    size = generic_cpy_call(space, pb.c_bf_getcharbuffer,
+                            obj, 0, bufferp)
+    if size < 0:
+        return -1
+    sizep[0] = size
+    return 0
 
 @cpython_api([lltype.Ptr(Py_buffer), PyObject, rffi.VOIDP, Py_ssize_t,
               lltype.Signed, lltype.Signed], rffi.INT, error=-1)
@@ -20,7 +181,7 @@
     view.c_len = length
     view.c_obj = obj
     if obj:
-        Py_IncRef(space, obj)
+        incref(space, obj)
     view.c_itemsize = 1
     rffi.setintfield(view, 'c_readonly', readonly)
     rffi.setintfield(view, 'c_ndim', 1)
diff --git a/pypy/module/cpyext/include/memoryobject.h 
b/pypy/module/cpyext/include/memoryobject.h
--- a/pypy/module/cpyext/include/memoryobject.h
+++ b/pypy/module/cpyext/include/memoryobject.h
@@ -5,14 +5,7 @@
 extern "C" {
 #endif
 
-/* The struct is declared here but it shouldn't
-   be considered public. Don't access those fields directly,
-   use the functions instead! */
-typedef struct {
-    PyObject_HEAD
-    Py_buffer view;
-} PyMemoryViewObject;
-
+#include "cpyext_memoryobject.h"
 
 /* Get a pointer to the memoryview's private copy of the exporter's buffer. */
 #define PyMemoryView_GET_BUFFER(op) (&((PyMemoryViewObject *)(op))->view)
diff --git a/pypy/module/cpyext/memoryobject.py 
b/pypy/module/cpyext/memoryobject.py
--- a/pypy/module/cpyext/memoryobject.py
+++ b/pypy/module/cpyext/memoryobject.py
@@ -1,29 +1,22 @@
-from rpython.rlib.objectmodel import keepalive_until_here
-from pypy.interpreter.error import oefmt
 from pypy.module.cpyext.api import (
-    cpython_api, Py_buffer, CANNOT_FAIL, Py_MAX_FMT, Py_MAX_NDIMS,
-    build_type_checkers, Py_ssize_tP, PyObjectFields, cpython_struct,
-    bootstrap_function, Py_bufferP, slot_function, generic_cpy_call)
+    cpython_api, CANNOT_FAIL, Py_MAX_FMT, Py_MAX_NDIMS, build_type_checkers,
+    Py_ssize_tP, cts, parse_dir, bootstrap_function, Py_bufferP, slot_function)
 from pypy.module.cpyext.pyobject import (
-    PyObject, make_ref, as_pyobj, decref, from_ref, make_typedescr,
+    PyObject, make_ref, decref, from_ref, make_typedescr,
     get_typedescr, track_reference)
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rlib.rarithmetic import widen
 from pypy.objspace.std.memoryobject import W_MemoryView
 from pypy.module.cpyext.object import _dealloc
 from pypy.module.cpyext.import_ import PyImport_Import
+from pypy.module.cpyext.buffer import CPyBuffer, fq
+
+cts.parse_header(parse_dir / 'cpyext_memoryobject.h')
+PyMemoryViewObject = cts.gettype('PyMemoryViewObject*')
 
 PyMemoryView_Check, PyMemoryView_CheckExact = build_type_checkers("MemoryView")
 
 
-PyMemoryViewObjectStruct = lltype.ForwardReference()
-PyMemoryViewObject = lltype.Ptr(PyMemoryViewObjectStruct)
-PyMemoryViewObjectFields = PyObjectFields + \
-    (("view", Py_buffer),)
-cpython_struct(
-    "PyMemoryViewObject", PyMemoryViewObjectFields, PyMemoryViewObjectStruct,
-    level=2)
-
 @bootstrap_function
 def init_memoryobject(space):
     "Type description of PyDictObject"
@@ -32,7 +25,7 @@
                    attach=memory_attach,
                    dealloc=memory_dealloc,
                    realize=memory_realize,
-                  )
+                   )
 
 def memory_attach(space, py_obj, w_obj, w_userdata=None):
     """
@@ -61,7 +54,6 @@
     """
     Creates the memory object in the interpreter
     """
-    from pypy.module.cpyext.slotdefs import CPyBuffer, fq
     py_mem = rffi.cast(PyMemoryViewObject, obj)
     view = py_mem.c_view
     ndim = widen(view.c_ndim)
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -3,7 +3,7 @@
     cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
     PyVarObject, size_t, slot_function,
     Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
-    Py_GE, CONST_STRING, CONST_STRINGP, FILEP, fwrite)
+    Py_GE, CONST_STRING, FILEP, fwrite)
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, from_ref, Py_IncRef, Py_DecRef,
     get_typedescr)
@@ -432,30 +432,6 @@
     is active then NULL is returned but PyErr_Occurred() will return false."""
     return space.call_function(space.builtin.get('dir'), w_o)
 
-@cpython_api([PyObject, CONST_STRINGP, Py_ssize_tP], rffi.INT_real, error=-1)
-def PyObject_AsCharBuffer(space, obj, bufferp, sizep):
-    """Returns a pointer to a read-only memory location usable as
-    character-based input.  The obj argument must support the single-segment
-    character buffer interface.  On success, returns 0, sets buffer to the
-    memory location and size to the buffer length.  Returns -1 and sets a
-    TypeError on error.
-    """
-    pto = obj.c_ob_type
-
-    pb = pto.c_tp_as_buffer
-    if not (pb and pb.c_bf_getreadbuffer and pb.c_bf_getsegcount):
-        raise oefmt(space.w_TypeError, "expected a character buffer object")
-    if generic_cpy_call(space, pb.c_bf_getsegcount,
-                        obj, lltype.nullptr(Py_ssize_tP.TO)) != 1:
-        raise oefmt(space.w_TypeError,
-                    "expected a single-segment buffer object")
-    size = generic_cpy_call(space, pb.c_bf_getcharbuffer,
-                            obj, 0, bufferp)
-    if size < 0:
-        return -1
-    sizep[0] = size
-    return 0
-
 # Also in include/object.h
 Py_PRINT_RAW = 1 # No string quotes etc.
 
diff --git a/pypy/module/cpyext/parse/cpyext_memoryobject.h 
b/pypy/module/cpyext/parse/cpyext_memoryobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/parse/cpyext_memoryobject.h
@@ -0,0 +1,7 @@
+/* The struct is declared here but it shouldn't
+   be considered public. Don't access those fields directly,
+   use the functions instead! */
+typedef struct {
+    PyObject_HEAD
+    Py_buffer view;
+} PyMemoryViewObject;
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,6 @@
 
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.rarithmetic import widen
-from rpython.rlib import rgc  # Force registration of gc.collect
 from pypy.module.cpyext.api import (
     slot_function, generic_cpy_call, PyObject, Py_ssize_t,
     Py_TPFLAGS_CHECKTYPES, Py_buffer, Py_bufferP, PyTypeObjectPtr, cts)
@@ -13,22 +12,20 @@
     getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
     ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
     cmpfunc, hashfunc, descrgetfunc, descrsetfunc, objobjproc, objobjargproc,
-    readbufferproc, getbufferproc, releasebufferproc, ssizessizeobjargproc)
-from pypy.module.cpyext.pyobject import make_ref, decref, as_pyobj, from_ref
+    readbufferproc, getbufferproc, ssizessizeobjargproc)
+from pypy.module.cpyext.pyobject import make_ref, decref, from_ref
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.module.cpyext.memoryobject import fill_Py_buffer
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext import userslot
-from pypy.interpreter.buffer import BufferView
+from pypy.module.cpyext.buffer import CBuffer, CPyBuffer, fq
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.argument import Arguments
-from rpython.rlib.buffer import RawBuffer
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib.objectmodel import specialize, not_rpython
 from rpython.tool.sourcetools import func_renamer
 from rpython.flowspace.model import Constant
 from rpython.flowspace.specialcase import register_flow_sc
-from rpython.rtyper.annlowlevel import llhelper
 from pypy.module.sys.version import CPYTHON_VERSION
 
 PY3 = CPYTHON_VERSION[0] == 3
@@ -324,141 +321,6 @@
         space.fromcache(State).check_and_raise_exception(always=True)
     return space.newint(res)
 
-class CPyBuffer(BufferView):
-    # Similar to Py_buffer
-    _immutable_ = True
-
-    def __init__(self, space, ptr, size, w_obj, format='B', shape=None,
-                 strides=None, ndim=1, itemsize=1, readonly=True,
-                 needs_decref=False,
-                 releasebufferproc=rffi.cast(rffi.VOIDP, 0)):
-        self.space = space
-        self.ptr = ptr
-        self.size = size
-        self.w_obj = w_obj  # kept alive
-        self.pyobj = as_pyobj(space, w_obj)
-        self.format = format
-        self.ndim = ndim
-        self.itemsize = itemsize
-
-        if not shape:
-            self.shape = [size]
-        else:
-            self.shape = shape
-        if not strides:
-            self.strides = [1]
-        else:
-            self.strides = strides
-        self.readonly = readonly
-        self.needs_decref = needs_decref
-        self.releasebufferproc = releasebufferproc
-
-    def releasebuffer(self):
-        if self.pyobj:
-            if self.needs_decref:
-                if self.releasebufferproc:
-                    func_target = rffi.cast(releasebufferproc, 
self.releasebufferproc)
-                    with lltype.scoped_alloc(Py_buffer) as pybuf:
-                        pybuf.c_buf = self.ptr
-                        pybuf.c_len = self.size
-                        pybuf.c_ndim = cts.cast('int', self.ndim)
-                        pybuf.c_shape = cts.cast('Py_ssize_t*', pybuf.c__shape)
-                        pybuf.c_strides = cts.cast('Py_ssize_t*', 
pybuf.c__strides)
-                        for i in range(self.ndim):
-                            pybuf.c_shape[i] = self.shape[i]
-                            pybuf.c_strides[i] = self.strides[i]
-                        if self.format:
-                            pybuf.c_format = rffi.str2charp(self.format)
-                        else:
-                            pybuf.c_format = rffi.str2charp("B")
-                        generic_cpy_call(self.space, func_target, self.pyobj, 
pybuf)
-                decref(self.space, self.pyobj)
-            self.pyobj = lltype.nullptr(PyObject.TO)
-        else:
-            #do not call twice
-            return
-
-    def getlength(self):
-        return self.size
-
-    def getbytes(self, start, size):
-        return ''.join([self.ptr[i] for i in range(start, start + size)])
-
-    def setbytes(self, start, string):
-        # absolutely no safety checks, what could go wrong?
-        for i in range(len(string)):
-            self.ptr[start + i] = string[i]
-
-    def as_str(self):
-        return CBuffer(self).as_str()
-
-    def as_readbuf(self):
-        return CBuffer(self)
-
-    def as_writebuf(self):
-        assert not self.readonly
-        return CBuffer(self)
-
-    def get_raw_address(self):
-        return rffi.cast(rffi.CCHARP, self.ptr)
-
-    def getformat(self):
-        return self.format
-
-    def getshape(self):
-        return self.shape
-
-    def getstrides(self):
-        return self.strides
-
-    def getitemsize(self):
-        return self.itemsize
-
-    def getndim(self):
-        return self.ndim
-
-class FQ(rgc.FinalizerQueue):
-    Class = CPyBuffer
-    def finalizer_trigger(self):
-        while 1:
-            buf  = self.next_dead()
-            if not buf:
-                break
-            buf.releasebuffer()
-
-fq = FQ()
-
-
-class CBuffer(RawBuffer):
-    _immutable_ = True
-    def __init__(self, view):
-        self.view = view
-        self.readonly = view.readonly
-
-    def getlength(self):
-        return self.view.getlength()
-
-    def getitem(self, index):
-        return self.view.ptr[index]
-
-    def getslice(self, start, stop, step, size):
-        assert step == 1
-        assert stop - start == size
-        ptr = rffi.ptradd(cts.cast('char *', self.view.ptr), start)
-        return rffi.charpsize2str(ptr, size)
-
-    def setitem(self, index, char):
-        self.view.ptr[index] = char
-
-    def setslice(self, index, s):
-        assert s is not None
-        ptr = rffi.ptradd(cts.cast('char *', self.view.ptr), index)
-        rffi.str2chararray(s, ptr, len(s))
-
-    def get_raw_address(self):
-        return cts.cast('char *', self.view.ptr)
-
-
 def wrap_getreadbuffer(space, w_self, w_args, func):
     func_target = rffi.cast(readbufferproc, func)
     py_obj = make_ref(space, w_self)
diff --git a/pypy/module/cpyext/test/test_bytesobject.py 
b/pypy/module/cpyext/test/test_bytesobject.py
--- a/pypy/module/cpyext/test/test_bytesobject.py
+++ b/pypy/module/cpyext/test/test_bytesobject.py
@@ -11,7 +11,7 @@
     _PyString_Join)
 from pypy.module.cpyext.api import PyObjectP, PyObject, Py_ssize_tP, 
generic_cpy_call
 from pypy.module.cpyext.pyobject import Py_DecRef, from_ref, make_ref
-from pypy.module.cpyext.object import PyObject_AsCharBuffer
+from pypy.module.cpyext.buffer import PyObject_AsCharBuffer
 from pypy.module.cpyext.api import PyTypeObjectPtr
 
 
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
@@ -1425,3 +1425,31 @@
         module.add_doc_string_method(a.foo_43)
         assert a.foo_43.__doc__ == "A docstring"
 
+class AppTestHashable(AppTestCpythonExtensionBase):
+    def test_unhashable(self):
+        if not self.runappdirect:
+            skip('pointer to function equality available'
+                 ' only after translation')
+        module = self.import_extension('foo', [
+           ("new_obj", "METH_NOARGS",
+            '''
+                PyObject *obj;
+                obj = PyObject_New(PyObject, &Foo_Type);
+                return obj;
+            '''
+            )], prologue='''
+            static PyTypeObject Foo_Type = {
+                PyVarObject_HEAD_INIT(NULL, 0)
+                "foo.foo",
+            };
+            ''', more_init = '''
+                Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+                Foo_Type.tp_hash = PyObject_HashNotImplemented;
+                if (PyType_Ready(&Foo_Type) < 0) INITERROR;
+            ''')
+        obj = module.new_obj()
+        raises(TypeError, hash, obj)
+        assert type(obj).__dict__['__hash__'] is None
+        # this is equivalent to
+        from collections import Hashable
+        assert not isinstance(obj, Hashable)
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
@@ -345,13 +345,19 @@
                 setattr(struct, slot_names[1], slot_func_helper)
 
 def add_operators(space, dict_w, pto):
-    # XXX support PyObject_HashNotImplemented
+    from pypy.module.cpyext.object import PyObject_HashNotImplemented
+    hash_not_impl = PyObject_HashNotImplemented.api_func.get_llhelper(space)
     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])
+            if slot_names[0] == 'c_tp_hash':
+                if hash_not_impl == func:
+                    # special case for tp_hash == PyObject_HashNotImplemented
+                    dict_w[method_name] = space.w_None
+                    continue
         else:
             assert len(slot_names) == 2
             struct = getattr(pto, slot_names[0])
diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py
--- a/rpython/rlib/rvmprof/cintf.py
+++ b/rpython/rlib/rvmprof/cintf.py
@@ -58,6 +58,7 @@
         SHARED.join('compat.c'),
         SHARED.join('machine.c'),
         SHARED.join('vmp_stack.c'),
+        SHARED.join('vmprof_main.c'),
         # symbol table already in separate_module_files
     ] + separate_module_files,
     post_include_bits=[],
diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_main.c 
b/rpython/rlib/rvmprof/src/shared/vmprof_main.c
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rvmprof/src/shared/vmprof_main.c
@@ -0,0 +1,30 @@
+#ifdef VMPROF_UNIX
+
+#include <unistd.h>
+/* value: LSB bit is 1 if signals must be ignored; all other bits
+   are a counter for how many threads are currently in a signal handler */
+static long volatile signal_handler_value = 1;
+
+void vmprof_ignore_signals(int ignored)
+{
+    if (!ignored) {
+        __sync_fetch_and_and(&signal_handler_value, ~1L);
+    } else {
+        /* set the last bit, and wait until concurrently-running signal
+           handlers finish */
+        while (__sync_or_and_fetch(&signal_handler_value, 1L) != 1L) {
+            usleep(1);
+        }
+    }
+}
+
+long vmprof_enter_signal(void)
+{
+    return __sync_fetch_and_add(&signal_handler_value, 2L);
+}
+
+long vmprof_exit_signal(void)
+{
+    return __sync_sub_and_fetch(&signal_handler_value, 2L);
+}
+#endif
diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_main.h 
b/rpython/rlib/rvmprof/src/shared/vmprof_main.h
--- a/rpython/rlib/rvmprof/src/shared/vmprof_main.h
+++ b/rpython/rlib/rvmprof/src/shared/vmprof_main.h
@@ -60,25 +60,9 @@
 
 /************************************************************/
 
-/* value: last bit is 1 if signals must be ignored; all other bits
-   are a counter for how many threads are currently in a signal handler */
-static long volatile signal_handler_value = 1;
-
-RPY_EXTERN
-void vmprof_ignore_signals(int ignored)
-{
-    if (!ignored) {
-        __sync_fetch_and_and(&signal_handler_value, ~1L);
-    }
-    else {
-        /* set the last bit, and wait until concurrently-running signal
-           handlers finish */
-        while (__sync_or_and_fetch(&signal_handler_value, 1L) != 1L) {
-            usleep(1);
-        }
-    }
-}
-
+RPY_EXTERN void vmprof_ignore_signals(int ignored);
+RPY_EXTERN long vmprof_enter_signal(void);
+RPY_EXTERN long vmprof_exit_signal(void);
 
 /* *************************************************************
  * functions to write a profile file compatible with gperftools
@@ -276,7 +260,7 @@
     __sync_lock_release(&spinlock);
 #endif
 
-    long val = __sync_fetch_and_add(&signal_handler_value, 2L);
+    long val = vmprof_enter_signal();
 
     if ((val & 1) == 0) {
         int saved_errno = errno;
@@ -307,7 +291,7 @@
         errno = saved_errno;
     }
 
-    __sync_sub_and_fetch(&signal_handler_value, 2L);
+    vmprof_exit_signal();
 }
 
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to