Commits

Romain Guillebert  committed 2c1b044 Merge

Merge default

  • Participants
  • Parent commits a9b32d2, 68a4e65
  • Branches numpypy-array_prepare_-array_wrap

Comments (0)

Files changed (143)

File lib-python/2.7/test/test_memoryview.py

             self.assertTrue(m[0:6] == m[:])
             self.assertFalse(m[0:5] == m)
 
-            # Comparison with objects which don't support the buffer API
-            self.assertFalse(m == u"abcdef")
-            self.assertTrue(m != u"abcdef")
-            self.assertFalse(u"abcdef" == m)
-            self.assertTrue(u"abcdef" != m)
+            if test_support.check_impl_detail(cpython=True):
+                # what is supported and what is not supported by memoryview is
+                # very inconsisten on CPython. In PyPy, memoryview supports
+                # the buffer interface, and thus the following comparison
+                # succeeds. See also the comment in
+                # pypy.modules.__builtin__.interp_memoryview.W_MemoryView.descr_buffer
+                #
+                # Comparison with objects which don't support the buffer API
+                self.assertFalse(m == u"abcdef", "%s %s" % (self, tp))
+                self.assertTrue(m != u"abcdef")
+                self.assertFalse(u"abcdef" == m)
+                self.assertTrue(u"abcdef" != m)
 
             # Unordered comparisons are unimplemented, and therefore give
             # arbitrary results (they raise a TypeError in py3k)

File lib_pypy/_ctypes/array.py

-import _ffi
+from _rawffi import alt as _ffi
 import _rawffi
 
 from _ctypes.basics import _CData, cdata_from_address, _CDataMeta, sizeof
                     # we don't want to have buffers here
                     if len(val) > self._length_:
                         raise ValueError("%r too long" % (val,))
-                    for i in range(len(val)):
-                        self[i] = val[i]
+                    if isinstance(val, str):
+                        _rawffi.rawstring2charp(self._buffer.buffer, val)
+                    else:
+                        for i in range(len(val)):
+                            self[i] = val[i]
                     if len(val) < self._length_:
-                        self[len(val)] = '\x00'
+                        self._buffer[len(val)] = '\x00'
                 res.value = property(getvalue, setvalue)
 
                 def getraw(self):
                 def setraw(self, buffer):
                     if len(buffer) > self._length_:
                         raise ValueError("%r too long" % (buffer,))
-                    for i in range(len(buffer)):
-                        self[i] = buffer[i]
+                    _rawffi.rawstring2charp(self._buffer.buffer, buffer)
                 res.raw = property(getraw, setraw)
             elif subletter == 'u':
                 def getvalue(self):
                     # we don't want to have buffers here
                     if len(val) > self._length_:
                         raise ValueError("%r too long" % (val,))
+                    if isinstance(val, unicode):
+                        target = self._buffer
+                    else:
+                        target = self
                     for i in range(len(val)):
-                        self[i] = val[i]
+                        target[i] = val[i]
                     if len(val) < self._length_:
-                        self[len(val)] = '\x00'
+                        target[len(val)] = u'\x00'
                 res.value = property(getvalue, setvalue)
                 
             if '_length_' in typedict:

File lib_pypy/_ctypes/basics.py

 
 import _rawffi
-import _ffi
+from _rawffi import alt as _ffi
 import sys
 
 try: from __pypy__ import builtinify

File lib_pypy/_ctypes/function.py

 from _ctypes.basics import is_struct_shape
 from _ctypes.builtin import get_errno, set_errno, get_last_error, set_last_error
 import _rawffi
-import _ffi
+from _rawffi import alt as _ffi
 import sys
 import traceback
 

File lib_pypy/_ctypes/pointer.py

 
 import _rawffi
-import _ffi
+from _rawffi import alt as _ffi
 from _ctypes.basics import _CData, _CDataMeta, cdata_from_address, ArgumentError
 from _ctypes.basics import keepalive_key, store_reference, ensure_objects
 from _ctypes.basics import sizeof, byref, as_ffi_pointer

File lib_pypy/_ctypes/primitive.py

-import _ffi
+from _rawffi import alt as _ffi
 import _rawffi
 import weakref
 import sys

File lib_pypy/_ctypes/structure.py

 import _rawffi
 from _ctypes.basics import _CData, _CDataMeta, keepalive_key,\
      store_reference, ensure_objects, CArgObject
+from _ctypes.array import Array
+from _ctypes.pointer import _Pointer
 import inspect
 
 def names_and_fields(self, _fields_, superclass, anonymous_fields=None):
     def __set__(self, obj, value):
         fieldtype = self.ctype
         cobj = fieldtype.from_param(value)
-        if ensure_objects(cobj) is not None:
-            key = keepalive_key(self.num)
+        key = keepalive_key(self.num)
+        if issubclass(fieldtype, _Pointer) and isinstance(cobj, Array):
+            # if our value is an Array we need the whole thing alive
+            store_reference(obj, key, cobj)
+        elif ensure_objects(cobj) is not None:
             store_reference(obj, key, cobj._objects)
         arg = cobj._get_buffer_value()
         if fieldtype._fficompositesize is not None:

File lib_pypy/_ffi.py

+# Backward compatibility hack
+from _rawffi.alt import *

File pypy/config/pypyoption.py

      "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO",
      "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
      "binascii", "_multiprocessing", '_warnings',
-     "_collections", "_multibytecodec", "micronumpy", "_ffi",
+     "_collections", "_multibytecodec", "micronumpy",
      "_continuation", "_cffi_backend", "_csv", "cppyy", "_pypyjson"]
 ))
 
 translation_modules = default_modules.copy()
 translation_modules.update(dict.fromkeys(
     ["fcntl", "rctime", "select", "signal", "_rawffi", "zlib",
-     "struct", "_md5", "cStringIO", "array", "_ffi",
+     "struct", "_md5", "cStringIO", "array",
      "binascii",
      # the following are needed for pyrepl (and hence for the
      # interactive prompt/pdb)
     # no _rawffi if importing rpython.rlib.clibffi raises ImportError
     # or CompilationError or py.test.skip.Exception
     "_rawffi"   : ["rpython.rlib.clibffi"],
-    "_ffi"      : ["rpython.rlib.clibffi"],
 
     "zlib"      : ["rpython.rlib.rzlib"],
     "bz2"       : ["pypy.module.bz2.interp_bz2"],

File pypy/doc/_ref.txt

 .. _`rpython/translator/c/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/c/
 .. _`rpython/translator/c/src/stacklet/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/c/src/stacklet/
 .. _`rpython/translator/c/src/stacklet/stacklet.h`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/c/src/stacklet/stacklet.h
-.. _`rpython/translator/cli/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/cli/
-.. _`rpython/translator/jvm/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/jvm/
 .. _`rpython/translator/tool/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/tool/

File pypy/doc/config/translation.lldebug0.txt

+Like lldebug, but in addition compile C files with -O0

File pypy/doc/project-ideas.rst

 The actual details would be rather differen in PyPy, but we would like to have
 the same optimization implemented.
 
+Or maybe not.  We can also play around with the idea of using a single
+representation: as a byte string in utf-8.  (This idea needs some extra logic
+for efficient indexing, like a cache.)
+
 .. _`optimized unicode representation`: http://www.python.org/dev/peps/pep-0393/
 
 Translation Toolchain

File pypy/doc/whatsnew-head.rst

 Fix 3 broken links on PyPy published papers in docs.
 
 .. branch: jit-ordereddict
+
+.. branch: refactor-str-types
+Remove multimethods on str/unicode/bytearray and make the implementations share code.
+
+.. branch: remove-del-from-generatoriterator
+Speed up generators that don't yield inside try or wait blocks by skipping
+unnecessary cleanup.

File pypy/goal/getnightly.py

 if branch == 'default':
     branch = 'trunk'
 
-filename = 'pypy-c-jit-latest-%s.tar.bz2' % arch
+if '--nojit' in sys.argv:
+    kind = 'nojit'
+else:
+    kind = 'jit'
+
+filename = 'pypy-c-%s-latest-%s.tar.bz2' % (kind, arch)
 url = 'http://buildbot.pypy.org/nightly/%s/%s' % (branch, filename)
 tmp = py.path.local.mkdtemp()
 mydir = tmp.chdir()

File pypy/interpreter/astcompiler/codegen.py

             flags |= consts.CO_NESTED
         if scope.is_generator:
             flags |= consts.CO_GENERATOR
+        if scope.has_yield_inside_try:
+            flags |= consts.CO_YIELD_INSIDE_TRY
         if scope.has_variable_arg:
             flags |= consts.CO_VARARGS
         if scope.has_keywords_arg:

File pypy/interpreter/astcompiler/consts.py

 CO_FUTURE_UNICODE_LITERALS = 0x20000
 #pypy specific:
 CO_KILL_DOCSTRING = 0x100000
+CO_YIELD_INSIDE_TRY = 0x200000
 
 PyCF_SOURCE_IS_UTF8 = 0x0100
 PyCF_DONT_IMPLY_DEDENT = 0x0200

File pypy/interpreter/astcompiler/symtable.py

         self.child_has_free = False
         self.nested = False
         self.doc_removable = False
+        self._in_try_body_depth = 0
 
     def lookup(self, name):
         """Find the scope of identifier 'name'."""
             self.varnames.append(mangled)
         return mangled
 
+    def note_try_start(self, try_node):
+        """Called when a try is found, before visiting the body."""
+        self._in_try_body_depth += 1
+
+    def note_try_end(self, try_node):
+        """Called after visiting a try body."""
+        self._in_try_body_depth -= 1
+
     def note_yield(self, yield_node):
         """Called when a yield is found."""
         raise SyntaxError("'yield' outside function", yield_node.lineno,
         self.has_variable_arg = False
         self.has_keywords_arg = False
         self.is_generator = False
+        self.has_yield_inside_try = False
         self.optimized = True
         self.return_with_value = False
         self.import_star = None
             raise SyntaxError("'return' with argument inside generator",
                               self.ret.lineno, self.ret.col_offset)
         self.is_generator = True
+        if self._in_try_body_depth > 0:
+            self.has_yield_inside_try = True
 
     def note_return(self, ret):
         if ret.value:
         self.scope.new_temporary_name()
         if wih.optional_vars:
             self.scope.new_temporary_name()
-        ast.GenericASTVisitor.visit_With(self, wih)
+        wih.context_expr.walkabout(self)
+        if wih.optional_vars:
+            wih.optional_vars.walkabout(self)
+        self.scope.note_try_start(wih)
+        self.visit_sequence(wih.body)
+        self.scope.note_try_end(wih)
 
     def visit_arguments(self, arguments):
         scope = self.scope
         else:
             role = SYM_ASSIGNED
         self.note_symbol(name.id, role)
+
+    def visit_TryExcept(self, node):
+        self.scope.note_try_start(node)
+        self.visit_sequence(node.body)
+        self.scope.note_try_end(node)
+        self.visit_sequence(node.handlers)
+        self.visit_sequence(node.orelse)
+
+    def visit_TryFinally(self, node):
+        self.scope.note_try_start(node)
+        self.visit_sequence(node.body)
+        self.scope.note_try_end(node)
+        self.visit_sequence(node.finalbody)

File pypy/interpreter/astcompiler/test/test_symtable.py

             assert exc.msg == "'return' with argument inside generator"
         scp = self.func_scope("def f():\n    return\n    yield x")
 
+    def test_yield_inside_try(self):
+        scp = self.func_scope("def f(): yield x")
+        assert not scp.has_yield_inside_try
+        scp = self.func_scope("def f():\n  try:\n    yield x\n  except: pass")
+        assert scp.has_yield_inside_try
+        scp = self.func_scope("def f():\n  try:\n    yield x\n  finally: pass")
+        assert scp.has_yield_inside_try
+        scp = self.func_scope("def f():\n    with x: yield y")
+        assert scp.has_yield_inside_try
+
+    def test_yield_outside_try(self):
+        for input in ("try: pass\n    except: pass",
+                      "try: pass\n    except: yield y",
+                      "try: pass\n    finally: pass",
+                      "try: pass\n    finally: yield y",
+                      "with x: pass"):
+            input = "def f():\n    yield y\n    %s\n    yield y" % (input,)
+            assert not self.func_scope(input).has_yield_inside_try
+
     def test_return(self):
         for input in ("class x: return", "return"):
             exc = py.test.raises(SyntaxError, self.func_scope, input).value

File pypy/interpreter/baseobjspace.py

         msg = "__int__ returned non-int (type '%T')"
         raise operationerrfmt(space.w_TypeError, msg, w_result)
 
+    def ord(self, space):
+        typename = space.type(self).getname(space)
+        msg = "ord() expected string of length 1, but %s found"
+        raise operationerrfmt(space.w_TypeError, msg, typename)
+
     def __spacebind__(self, space):
         return self
 
         # This is here mostly just for gateway.int_unwrapping_space_method().
         return bool(self.int_w(w_obj))
 
+    def ord(self, w_obj):
+        return w_obj.ord(self)
+
     # This is all interface for gateway.py.
     def gateway_int_w(self, w_obj):
         if self.isinstance_w(w_obj, self.w_float):

File pypy/interpreter/gateway.py

     # When a BuiltinCode is stored in a Function object,
     # you get the functionality of CPython's built-in function type.
 
-    def __init__(self, func, unwrap_spec=None, self_type=None, descrmismatch=None):
+    def __init__(self, func, unwrap_spec=None, self_type=None,
+                 descrmismatch=None, doc=None):
         "NOT_RPYTHON"
         # 'implfunc' is the interpreter-level function.
         # Note that this uses a lot of (construction-time) introspection.
         Code.__init__(self, func.__name__)
-        self.docstring = func.__doc__
+        self.docstring = doc or func.__doc__
 
         self.identifier = "%s-%s-%s" % (func.__module__, func.__name__,
                                         getattr(self_type, '__name__', '*'))
     instancecache = {}
 
     def __new__(cls, f, app_name=None, unwrap_spec=None, descrmismatch=None,
-                as_classmethod=False):
+                as_classmethod=False, doc=None):
 
         "NOT_RPYTHON"
         # f must be a function whose name does NOT start with 'app_'
         cls.instancecache[key] = self
         self._code = BuiltinCode(f, unwrap_spec=unwrap_spec,
                                  self_type=self_type,
-                                 descrmismatch=descrmismatch)
+                                 descrmismatch=descrmismatch,
+                                 doc=doc)
         self.__name__ = f.func_name
         self.name = app_name
         self.as_classmethod = as_classmethod

File pypy/interpreter/generator.py

         code_name = self.pycode.co_name
         return space.wrap(code_name)
 
-    def __del__(self):
-        # Only bother enqueuing self to raise an exception if the frame is
-        # still not finished and finally or except blocks are present.
-        self.clear_all_weakrefs()
-        if self.frame is not None:
-            block = self.frame.lastblock
-            while block is not None:
-                if not isinstance(block, LoopBlock):
-                    self.enqueue_for_destruction(self.space,
-                                                 GeneratorIterator.descr_close,
-                                                 "interrupting generator of ")
-                    break
-                block = block.previous
-
     # Results can be either an RPython list of W_Root, or it can be an
     # app-level W_ListObject, which also has an append() method, that's why we
     # generate 2 versions of the function and 2 jit drivers.
         return unpack_into
     unpack_into = _create_unpack_into()
     unpack_into_w = _create_unpack_into()
+
+
+class GeneratorIteratorWithDel(GeneratorIterator):
+
+    def __del__(self):
+        # Only bother enqueuing self to raise an exception if the frame is
+        # still not finished and finally or except blocks are present.
+        self.clear_all_weakrefs()
+        if self.frame is not None:
+            block = self.frame.lastblock
+            while block is not None:
+                if not isinstance(block, LoopBlock):
+                    self.enqueue_for_destruction(self.space,
+                                                 GeneratorIterator.descr_close,
+                                                 "interrupting generator of ")
+                    break
+                block = block.previous

File pypy/interpreter/pycode.py

 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.astcompiler.consts import (
     CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED,
-    CO_GENERATOR, CO_KILL_DOCSTRING)
+    CO_GENERATOR, CO_KILL_DOCSTRING, CO_YIELD_INSIDE_TRY)
 from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT
 from rpython.rlib.rarithmetic import intmask
 from rpython.rlib.objectmodel import compute_hash
 # Magic numbers for the bytecode version in code objects.
 # See comments in pypy/module/imp/importing.
 cpython_magic, = struct.unpack("<i", imp.get_magic())   # host magic number
-default_magic = (0xf303 + 6) | 0x0a0d0000               # this PyPy's magic
+default_magic = (0xf303 + 7) | 0x0a0d0000               # this PyPy's magic
                                                         # (from CPython 2.7.0)
 
 # cpython_code_signature helper

File pypy/interpreter/pyframe.py

     def run(self):
         """Start this frame's execution."""
         if self.getcode().co_flags & pycode.CO_GENERATOR:
-            from pypy.interpreter.generator import GeneratorIterator
-            return self.space.wrap(GeneratorIterator(self))
+            if 1:# self.getcode().co_flags & pycode.CO_YIELD_INSIDE_TRY:
+                from pypy.interpreter.generator import GeneratorIteratorWithDel
+                return self.space.wrap(GeneratorIteratorWithDel(self))
+            else:
+                from pypy.interpreter.generator import GeneratorIterator
+                return self.space.wrap(GeneratorIterator(self))
         else:
             return self.execute_frame()
 

File pypy/interpreter/test/test_gateway.py

             never_called
         py.test.raises(AssertionError, space.wrap, gateway.interp2app_temp(g))
 
+    def test_interp2app_doc(self):
+        space = self.space
+        def f(space, w_x):
+            """foo"""
+        w_f = space.wrap(gateway.interp2app_temp(f))
+        assert space.unwrap(space.getattr(w_f, space.wrap('__doc__'))) == 'foo'
+        #
+        def g(space, w_x):
+            never_called
+        w_g = space.wrap(gateway.interp2app_temp(g, doc='bar'))
+        assert space.unwrap(space.getattr(w_g, space.wrap('__doc__'))) == 'bar'
+
 
 class AppTestPyTestMark:
     @py.test.mark.unlikely_to_exist

File pypy/interpreter/unicodehelper.py

 # ____________________________________________________________
 
 def encode(space, w_data, encoding=None, errors='strict'):
-    from pypy.objspace.std.unicodetype import encode_object
+    from pypy.objspace.std.unicodeobject import encode_object
     return encode_object(space, w_data, encoding, errors)
 
 # These functions take and return unwrapped rpython strings and unicodes

File pypy/module/__builtin__/interp_memoryview.py

         return W_MemoryView(buf)
 
     def descr_buffer(self, space):
-        """Note that memoryview() objects in PyPy support buffer(), whereas
-        not in CPython; but CPython supports passing memoryview() to most
-        built-in functions that accept buffers, with the notable exception
-        of the buffer() built-in."""
+        """
+        Note that memoryview() is very inconsistent in CPython: it does not
+        support the buffer interface but does support the new buffer
+        interface: as a result, it is possible to pass memoryview to
+        e.g. socket.send() but not to file.write().  For simplicity and
+        consistency, in PyPy memoryview DOES support buffer(), which means
+        that it is accepted in more places than CPython.
+        """
         return space.wrap(self.buf)
 
     def descr_tobytes(self, space):

File pypy/module/_cffi_backend/ctypestruct.py

         if self.fields_dict is None:
             space = self.space
             raise operationerrfmt(w_errorcls or space.w_TypeError,
-                                  "'%s' is not completed yet", self.name)
+                              "'%s' is opaque or not completed yet", self.name)
 
     def _alignof(self):
         self.check_complete(w_errorcls=self.space.w_ValueError)

File pypy/module/_cffi_backend/newtype.py

 SF_MSVC_BITFIELDS = 1
 SF_GCC_ARM_BITFIELDS = 2
 SF_GCC_BIG_ENDIAN = 4
+SF_PACKED = 8
 
 if sys.platform == 'win32':
     DEFAULT_SFLAGS = SF_MSVC_BITFIELDS
             boffset = 0         # reset each field at offset 0
         #
         # update the total alignment requirement, but skip it if the
-        # field is an anonymous bitfield
-        falign = ftype.alignof()
+        # field is an anonymous bitfield or if SF_PACKED
+        falign = 1 if sflags & SF_PACKED else ftype.alignof()
         do_align = True
         if (sflags & SF_GCC_ARM_BITFIELDS) == 0 and fbitsize >= 0:
             if (sflags & SF_MSVC_BITFIELDS) == 0:
                     if bits_already_occupied + fbitsize > 8 * ftype.size:
                         # it would not fit, we need to start at the next
                         # allowed position
+                        if ((sflags & SF_PACKED) != 0 and
+                            (bits_already_occupied & 7) != 0):
+                            raise operationerrfmt(space.w_NotImplementedError,
+                                "with 'packed', gcc would compile field "
+                                "'%s.%s' to reuse some bits in the previous "
+                                "field", w_ctype.name, fname)
                         field_offset_bytes += falign
                         assert boffset < field_offset_bytes * 8
                         boffset = field_offset_bytes * 8

File pypy/module/_cffi_backend/test/_backend_test_c.py

     p = newp(BArray, None)
     assert sizeof(p[2:9]) == 7 * sizeof(BInt)
 
+def test_packed():
+    BLong = new_primitive_type("long")
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BStruct = new_struct_type("struct foo")
+    complete_struct_or_union(BStruct, [('a1', BLong, -1),
+                                       ('a2', BChar, -1),
+                                       ('a3', BShort, -1)],
+                             None, -1, -1, 8)   # SF_PACKED==8
+    d = BStruct.fields
+    assert len(d) == 3
+    assert d[0][0] == 'a1'
+    assert d[0][1].type is BLong
+    assert d[0][1].offset == 0
+    assert d[0][1].bitshift == -1
+    assert d[0][1].bitsize == -1
+    assert d[1][0] == 'a2'
+    assert d[1][1].type is BChar
+    assert d[1][1].offset == sizeof(BLong)
+    assert d[1][1].bitshift == -1
+    assert d[1][1].bitsize == -1
+    assert d[2][0] == 'a3'
+    assert d[2][1].type is BShort
+    assert d[2][1].offset == sizeof(BLong) + sizeof(BChar)
+    assert d[2][1].bitshift == -1
+    assert d[2][1].bitsize == -1
+    assert sizeof(BStruct) == sizeof(BLong) + sizeof(BChar) + sizeof(BShort)
+    assert alignof(BStruct) == 1
+
+def test_packed_with_bitfields():
+    BLong = new_primitive_type("long")
+    BChar = new_primitive_type("char")
+    BStruct = new_struct_type("struct foo")
+    py.test.raises(NotImplementedError,
+                   complete_struct_or_union,
+                   BStruct, [('a1', BLong, 30),
+                             ('a2', BChar, 5)],
+                   None, -1, -1, 8)   # SF_PACKED==8
 
 def test_version():
     # this test is here mostly for PyPy

File pypy/module/_codecs/interp_codecs.py

 
 @unwrap_spec(data=str, errors='str_or_None')
 def escape_encode(space, data, errors='strict'):
-    from pypy.objspace.std.stringobject import string_escape_encode
+    from pypy.objspace.std.bytesobject import string_escape_encode
     result = string_escape_encode(data, quote="'")
     start = 1
     end = len(result) - 1

File pypy/module/_ffi/__init__.py

-from pypy.interpreter.mixedmodule import MixedModule
-import os
-
-class Module(MixedModule):
-
-    interpleveldefs = {
-        'types':   'interp_ffitype.W_types',
-        'CDLL':    'interp_funcptr.W_CDLL',
-        'FuncPtr': 'interp_funcptr.W_FuncPtr',
-        'get_libc':'interp_funcptr.get_libc',
-        '_StructDescr': 'interp_struct.W__StructDescr',
-        'Field':     'interp_struct.W_Field',
-    }
-    if os.name == 'nt':
-        interpleveldefs['WinDLL'] = 'interp_funcptr.W_WinDLL'
-    appleveldefs = {
-        'Structure': 'app_struct.Structure',
-        }

File pypy/module/_ffi/app_struct.py

-import _ffi
-
-class MetaStructure(type):
-
-    def __new__(cls, name, bases, dic):
-        cls._compute_shape(name, dic)
-        return type.__new__(cls, name, bases, dic)
-
-    @classmethod
-    def _compute_shape(cls, name, dic):
-        fields = dic.get('_fields_')
-        if fields is None:
-            return
-        struct_descr = _ffi._StructDescr(name, fields)
-        for field in fields:
-            dic[field.name] = field
-        dic['_struct_'] = struct_descr
-
-
-class Structure(object):
-    __metaclass__ = MetaStructure

File pypy/module/_ffi/interp_ffitype.py

-from rpython.rlib import libffi, clibffi
-from rpython.rlib.rarithmetic import intmask
-from rpython.rlib import jit
-from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.typedef import TypeDef, interp_attrproperty
-from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.error import OperationError
-
-
-class W_FFIType(W_Root):
-    _immutable_fields_ = ['name', 'w_structdescr', 'w_pointer_to']
-
-    def __init__(self, name, ffitype, w_structdescr=None, w_pointer_to=None):
-        self.name = name
-        self._ffitype = clibffi.FFI_TYPE_NULL
-        self.w_structdescr = w_structdescr
-        self.w_pointer_to = w_pointer_to
-        self.set_ffitype(ffitype)
-
-    @jit.elidable
-    def get_ffitype(self):
-        if not self._ffitype:
-            raise ValueError("Operation not permitted on an incomplete type")
-        return self._ffitype
-
-    def set_ffitype(self, ffitype):
-        if self._ffitype:
-            raise ValueError("The _ffitype is already set")
-        self._ffitype = ffitype
-        if ffitype and self.is_struct():
-            assert self.w_structdescr is not None
-
-    def descr_deref_pointer(self, space):
-        if self.w_pointer_to is None:
-            return space.w_None
-        return self.w_pointer_to
-
-    def descr_sizeof(self, space):
-        try:
-            return space.wrap(self.sizeof())
-        except ValueError:
-            msg = "Operation not permitted on an incomplete type"
-            raise OperationError(space.w_ValueError, space.wrap(msg))
-
-    def sizeof(self):
-        return intmask(self.get_ffitype().c_size)
-
-    def get_alignment(self):
-        return intmask(self.get_ffitype().c_alignment)
-
-    def repr(self, space):
-        return space.wrap(self.__repr__())
-
-    def __repr__(self):
-        name = self.name
-        if not self._ffitype:
-            name += ' (incomplete)'
-        return "<ffi type %s>" % name
-
-    def is_signed(self):
-        return (self is app_types.slong or
-                self is app_types.sint or
-                self is app_types.sshort or
-                self is app_types.sbyte or
-                self is app_types.slonglong)
-
-    def is_unsigned(self):
-        return (self is app_types.ulong or
-                self is app_types.uint or
-                self is app_types.ushort or
-                self is app_types.ubyte or
-                self is app_types.ulonglong)
-
-    def is_pointer(self):
-        return self.get_ffitype() is libffi.types.pointer
-
-    def is_char(self):
-        return self is app_types.char
-
-    def is_unichar(self):
-        return self is app_types.unichar
-
-    def is_longlong(self):
-        return libffi.IS_32_BIT and (self is app_types.slonglong or
-                                     self is app_types.ulonglong)
-
-    def is_double(self):
-        return self is app_types.double
-
-    def is_singlefloat(self):
-        return self is app_types.float
-
-    def is_void(self):
-        return self is app_types.void
-
-    def is_struct(self):
-        return libffi.types.is_struct(self.get_ffitype())
-
-    def is_char_p(self):
-        return self is app_types.char_p
-
-    def is_unichar_p(self):
-        return self is app_types.unichar_p
-
-
-W_FFIType.typedef = TypeDef(
-    'FFIType',
-    name = interp_attrproperty('name', W_FFIType),
-    __repr__ = interp2app(W_FFIType.repr),
-    deref_pointer = interp2app(W_FFIType.descr_deref_pointer),
-    sizeof = interp2app(W_FFIType.descr_sizeof),
-    )
-
-
-def build_ffi_types():
-    types = [
-        # note: most of the type name directly come from the C equivalent,
-        # with the exception of bytes: in C, ubyte and char are equivalent,
-        # but for _ffi the first expects a number while the second a 1-length
-        # string
-        W_FFIType('slong',     libffi.types.slong),
-        W_FFIType('sint',      libffi.types.sint),
-        W_FFIType('sshort',    libffi.types.sshort),
-        W_FFIType('sbyte',     libffi.types.schar),
-        W_FFIType('slonglong', libffi.types.slonglong),
-        #
-        W_FFIType('ulong',     libffi.types.ulong),
-        W_FFIType('uint',      libffi.types.uint),
-        W_FFIType('ushort',    libffi.types.ushort),
-        W_FFIType('ubyte',     libffi.types.uchar),
-        W_FFIType('ulonglong', libffi.types.ulonglong),
-        #
-        W_FFIType('char',      libffi.types.uchar),
-        W_FFIType('unichar',   libffi.types.wchar_t),
-        #
-        W_FFIType('double',    libffi.types.double),
-        W_FFIType('float',     libffi.types.float),
-        W_FFIType('void',      libffi.types.void),
-        W_FFIType('void_p',    libffi.types.pointer),
-        #
-        # missing types:
-
-        ## 's' : ffi_type_pointer,
-        ## 'z' : ffi_type_pointer,
-        ## 'O' : ffi_type_pointer,
-        ## 'Z' : ffi_type_pointer,
-
-        ]
-    d = dict([(t.name, t) for t in types])
-    w_char = d['char']
-    w_unichar = d['unichar']
-    d['char_p'] = W_FFIType('char_p', libffi.types.pointer, w_pointer_to = w_char)
-    d['unichar_p'] = W_FFIType('unichar_p', libffi.types.pointer, w_pointer_to = w_unichar)
-    return d
-
-class app_types:
-    pass
-app_types.__dict__ = build_ffi_types()
-
-
-def descr_new_pointer(space, w_cls, w_pointer_to):
-    try:
-        return descr_new_pointer.cache[w_pointer_to]
-    except KeyError:
-        if w_pointer_to is app_types.char:
-            w_result = app_types.char_p
-        elif w_pointer_to is app_types.unichar:
-            w_result = app_types.unichar_p
-        else:
-            w_pointer_to = space.interp_w(W_FFIType, w_pointer_to)
-            name = '(pointer to %s)' % w_pointer_to.name
-            w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to=w_pointer_to)
-        descr_new_pointer.cache[w_pointer_to] = w_result
-        return w_result
-descr_new_pointer.cache = {}
-
-
-class W_types(W_Root):
-    pass
-W_types.typedef = TypeDef(
-    'types',
-    Pointer = interp2app(descr_new_pointer, as_classmethod=True),
-    **app_types.__dict__)

File pypy/module/_ffi/interp_funcptr.py

-from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.error import OperationError, wrap_oserror, \
-    operationerrfmt
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef
-from pypy.module._ffi.interp_ffitype import W_FFIType
-#
-from rpython.rtyper.lltypesystem import lltype, rffi
-#
-from rpython.rlib import jit
-from rpython.rlib import libffi
-from rpython.rlib.clibffi import get_libc_name, StackCheckError, LibFFIError
-from rpython.rlib.rdynload import DLOpenError
-from rpython.rlib.rarithmetic import r_uint
-from rpython.rlib.objectmodel import we_are_translated
-from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter
-from pypy.module._rawffi.interp_rawffi import got_libffi_error, wrap_dlopenerror
-
-import os
-if os.name == 'nt':
-    def _getfunc(space, CDLL, w_name, w_argtypes, w_restype):
-        argtypes_w, argtypes, w_restype, restype = unpack_argtypes(
-            space, w_argtypes, w_restype)
-        if space.isinstance_w(w_name, space.w_str):
-            name = space.str_w(w_name)
-            try:
-                func = CDLL.cdll.getpointer(name, argtypes, restype,
-                                            flags = CDLL.flags)
-            except KeyError:
-                raise operationerrfmt(
-                    space.w_AttributeError,
-                    "No symbol %s found in library %s", name, CDLL.name)
-            except LibFFIError:
-                raise got_libffi_error(space)
-
-            return W_FuncPtr(func, argtypes_w, w_restype)
-        elif space.isinstance_w(w_name, space.w_int):
-            ordinal = space.int_w(w_name)
-            try:
-                func = CDLL.cdll.getpointer_by_ordinal(
-                    ordinal, argtypes, restype,
-                    flags = CDLL.flags)
-            except KeyError:
-                raise operationerrfmt(
-                    space.w_AttributeError,
-                    "No ordinal %d found in library %s", ordinal, CDLL.name)
-            except LibFFIError:
-                raise got_libffi_error(space)
-
-            return W_FuncPtr(func, argtypes_w, w_restype)
-        else:
-            raise OperationError(space.w_TypeError, space.wrap(
-                    'function name must be a string or integer'))
-else:
-    @unwrap_spec(name=str)
-    def _getfunc(space, CDLL, w_name, w_argtypes, w_restype):
-        name = space.str_w(w_name)
-        argtypes_w, argtypes, w_restype, restype = unpack_argtypes(
-            space, w_argtypes, w_restype)
-        try:
-            func = CDLL.cdll.getpointer(name, argtypes, restype,
-                                        flags = CDLL.flags)
-        except KeyError:
-            raise operationerrfmt(
-                space.w_AttributeError,
-                "No symbol %s found in library %s", name, CDLL.name)
-        except LibFFIError:
-            raise got_libffi_error(space)
-
-        return W_FuncPtr(func, argtypes_w, w_restype)
-
-def unwrap_ffitype(space, w_argtype, allow_void=False):
-    res = w_argtype.get_ffitype()
-    if res is libffi.types.void and not allow_void:
-        msg = 'void is not a valid argument type'
-        raise OperationError(space.w_TypeError, space.wrap(msg))
-    return res
-
-
-# ========================================================================
-
-class W_FuncPtr(W_Root):
-
-    _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype']
-
-    def __init__(self, func, argtypes_w, w_restype):
-        self.func = func
-        self.argtypes_w = argtypes_w
-        self.w_restype = w_restype
-        self.to_free = []
-
-    @jit.unroll_safe
-    def build_argchain(self, space, args_w):
-        expected = len(self.argtypes_w)
-        given = len(args_w)
-        if given != expected:
-            arg = 'arguments'
-            if len(self.argtypes_w) == 1:
-                arg = 'argument'
-            raise operationerrfmt(space.w_TypeError,
-                                  '%s() takes exactly %d %s (%d given)',
-                                  self.func.name, expected, arg, given)
-        #
-        argchain = libffi.ArgChain()
-        argpusher = PushArgumentConverter(space, argchain, self)
-        for i in range(expected):
-            w_argtype = self.argtypes_w[i]
-            w_arg = args_w[i]
-            argpusher.unwrap_and_do(w_argtype, w_arg)
-        return argchain
-
-    def call(self, space, args_w):
-        self = jit.promote(self)
-        argchain = self.build_argchain(space, args_w)
-        func_caller = CallFunctionConverter(space, self.func, argchain)
-        try:
-            return func_caller.do_and_wrap(self.w_restype)
-        except StackCheckError, e:
-            raise OperationError(space.w_ValueError, space.wrap(e.message))
-        #return self._do_call(space, argchain)
-
-    def free_temp_buffers(self, space):
-        for buf in self.to_free:
-            if not we_are_translated():
-                buf[0] = '\00' # invalidate the buffer, so that
-                               # test_keepalive_temp_buffer can fail
-            lltype.free(buf, flavor='raw')
-        self.to_free = []
-
-    def getaddr(self, space):
-        """
-        Return the physical address in memory of the function
-        """
-        return space.wrap(rffi.cast(rffi.LONG, self.func.funcsym))
-
-
-class PushArgumentConverter(FromAppLevelConverter):
-    """
-    A converter used by W_FuncPtr to unwrap the app-level objects into
-    low-level types and push them to the argchain.
-    """
-
-    def __init__(self, space, argchain, w_func):
-        FromAppLevelConverter.__init__(self, space)
-        self.argchain = argchain
-        self.w_func = w_func
-
-    def handle_signed(self, w_ffitype, w_obj, intval):
-        self.argchain.arg(intval)
-
-    def handle_unsigned(self, w_ffitype, w_obj, uintval):
-        self.argchain.arg(uintval)
-
-    def handle_pointer(self, w_ffitype, w_obj, intval):
-        self.argchain.arg(intval)
-
-    def handle_char(self, w_ffitype, w_obj, intval):
-        self.argchain.arg(intval)
-
-    def handle_unichar(self, w_ffitype, w_obj, intval):
-        self.argchain.arg(intval)
-
-    def handle_longlong(self, w_ffitype, w_obj, longlongval):
-        self.argchain.arg(longlongval)
-
-    def handle_char_p(self, w_ffitype, w_obj, strval):
-        buf = rffi.str2charp(strval)
-        self.w_func.to_free.append(rffi.cast(rffi.VOIDP, buf))
-        addr = rffi.cast(rffi.ULONG, buf)
-        self.argchain.arg(addr)
-
-    def handle_unichar_p(self, w_ffitype, w_obj, unicodeval):
-        buf = rffi.unicode2wcharp(unicodeval)
-        self.w_func.to_free.append(rffi.cast(rffi.VOIDP, buf))
-        addr = rffi.cast(rffi.ULONG, buf)
-        self.argchain.arg(addr)
-
-    def handle_float(self, w_ffitype, w_obj, floatval):
-        self.argchain.arg(floatval)
-
-    def handle_singlefloat(self, w_ffitype, w_obj, singlefloatval):
-        self.argchain.arg(singlefloatval)
-
-    def handle_struct(self, w_ffitype, w_structinstance):
-        # arg_raw directly takes value to put inside ll_args
-        ptrval = w_structinstance.rawmem
-        self.argchain.arg_raw(ptrval)
-
-    def handle_struct_rawffi(self, w_ffitype, w_structinstance):
-        # arg_raw directly takes value to put inside ll_args
-        ptrval = w_structinstance.ll_buffer
-        self.argchain.arg_raw(ptrval)
-
-
-class CallFunctionConverter(ToAppLevelConverter):
-    """
-    A converter used by W_FuncPtr to call the function, expect the result of
-    a correct low-level type and wrap it to the corresponding app-level type
-    """
-
-    def __init__(self, space, func, argchain):
-        ToAppLevelConverter.__init__(self, space)
-        self.func = func
-        self.argchain = argchain
-
-    def get_longlong(self, w_ffitype):
-        return self.func.call(self.argchain, rffi.LONGLONG)
-
-    def get_ulonglong(self, w_ffitype):
-        return self.func.call(self.argchain, rffi.ULONGLONG)
-
-    def get_signed(self, w_ffitype):
-        # if the declared return type of the function is smaller than LONG,
-        # the result buffer may contains garbage in its higher bits.  To get
-        # the correct value, and to be sure to handle the signed/unsigned case
-        # correctly, we need to cast the result to the correct type.  After
-        # that, we cast it back to LONG, because this is what we want to pass
-        # to space.wrap in order to get a nice applevel <int>.
-        #
-        restype = w_ffitype.get_ffitype()
-        call = self.func.call
-        if restype is libffi.types.slong:
-            return call(self.argchain, rffi.LONG)
-        elif restype is libffi.types.sint:
-            return rffi.cast(rffi.LONG, call(self.argchain, rffi.INT))
-        elif restype is libffi.types.sshort:
-            return rffi.cast(rffi.LONG, call(self.argchain, rffi.SHORT))
-        elif restype is libffi.types.schar:
-            return rffi.cast(rffi.LONG, call(self.argchain, rffi.SIGNEDCHAR))
-        else:
-            self.error(w_ffitype)
-
-    def get_unsigned(self, w_ffitype):
-        return self.func.call(self.argchain, rffi.ULONG)
-
-    def get_unsigned_which_fits_into_a_signed(self, w_ffitype):
-        # the same comment as get_signed apply
-        restype = w_ffitype.get_ffitype()
-        call = self.func.call
-        if restype is libffi.types.uint:
-            assert not libffi.IS_32_BIT
-            # on 32bit machines, we should never get here, because it's a case
-            # which has already been handled by get_unsigned above.
-            return rffi.cast(rffi.LONG, call(self.argchain, rffi.UINT))
-        elif restype is libffi.types.ushort:
-            return rffi.cast(rffi.LONG, call(self.argchain, rffi.USHORT))
-        elif restype is libffi.types.uchar:
-            return rffi.cast(rffi.LONG, call(self.argchain, rffi.UCHAR))
-        else:
-            self.error(w_ffitype)
-
-
-    def get_pointer(self, w_ffitype):
-        ptrres = self.func.call(self.argchain, rffi.VOIDP)
-        return rffi.cast(rffi.ULONG, ptrres)
-
-    def get_char(self, w_ffitype):
-        return self.func.call(self.argchain, rffi.UCHAR)
-
-    def get_unichar(self, w_ffitype):
-        return self.func.call(self.argchain, rffi.WCHAR_T)
-
-    def get_float(self, w_ffitype):
-        return self.func.call(self.argchain, rffi.DOUBLE)
-
-    def get_singlefloat(self, w_ffitype):
-        return self.func.call(self.argchain, rffi.FLOAT)
-
-    def get_struct(self, w_ffitype, w_structdescr):
-        addr = self.func.call(self.argchain, rffi.LONG, is_struct=True)
-        return w_structdescr.fromaddress(self.space, addr)
-
-    def get_struct_rawffi(self, w_ffitype, w_structdescr):
-        uintval = self.func.call(self.argchain, rffi.ULONG, is_struct=True)
-        return w_structdescr.fromaddress(self.space, uintval)
-
-    def get_void(self, w_ffitype):
-        return self.func.call(self.argchain, lltype.Void)
-
-
-def unpack_argtypes(space, w_argtypes, w_restype):
-    argtypes_w = [space.interp_w(W_FFIType, w_argtype)
-                  for w_argtype in space.listview(w_argtypes)]
-    argtypes = [unwrap_ffitype(space, w_argtype) for w_argtype in
-                argtypes_w]
-    w_restype = space.interp_w(W_FFIType, w_restype)
-    restype = unwrap_ffitype(space, w_restype, allow_void=True)
-    return argtypes_w, argtypes, w_restype, restype
-
-@unwrap_spec(addr=r_uint, name=str, flags=int)
-def descr_fromaddr(space, w_cls, addr, name, w_argtypes,
-                    w_restype, flags=libffi.FUNCFLAG_CDECL):
-    argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
-                                                               w_argtypes,
-                                                               w_restype)
-    addr = rffi.cast(rffi.VOIDP, addr)
-    try:
-        func = libffi.Func(name, argtypes, restype, addr, flags)
-        return W_FuncPtr(func, argtypes_w, w_restype)
-    except LibFFIError:
-        raise got_libffi_error(space)
-
-
-W_FuncPtr.typedef = TypeDef(
-    '_ffi.FuncPtr',
-    __call__ = interp2app(W_FuncPtr.call),
-    getaddr = interp2app(W_FuncPtr.getaddr),
-    free_temp_buffers = interp2app(W_FuncPtr.free_temp_buffers),
-    fromaddr = interp2app(descr_fromaddr, as_classmethod=True)
-    )
-
-
-
-# ========================================================================
-
-class W_CDLL(W_Root):
-    def __init__(self, space, name, mode):
-        self.flags = libffi.FUNCFLAG_CDECL
-        self.space = space
-        if name is None:
-            self.name = "<None>"
-        else:
-            self.name = name
-        try:
-            self.cdll = libffi.CDLL(name, mode)
-        except DLOpenError, e:
-            raise wrap_dlopenerror(space, e, self.name)
-
-    def getfunc(self, space, w_name, w_argtypes, w_restype):
-        return _getfunc(space, self, w_name, w_argtypes, w_restype)
-
-    @unwrap_spec(name=str)
-    def getaddressindll(self, space, name):
-        try:
-            address_as_uint = rffi.cast(lltype.Unsigned,
-                                        self.cdll.getaddressindll(name))
-        except KeyError:
-            raise operationerrfmt(
-                space.w_ValueError,
-                "No symbol %s found in library %s", name, self.name)
-        return space.wrap(address_as_uint)
-
-@unwrap_spec(name='str_or_None', mode=int)
-def descr_new_cdll(space, w_type, name, mode=-1):
-    return space.wrap(W_CDLL(space, name, mode))
-
-
-W_CDLL.typedef = TypeDef(
-    '_ffi.CDLL',
-    __new__     = interp2app(descr_new_cdll),
-    getfunc     = interp2app(W_CDLL.getfunc),
-    getaddressindll = interp2app(W_CDLL.getaddressindll),
-    )
-
-class W_WinDLL(W_CDLL):
-    def __init__(self, space, name, mode):
-        W_CDLL.__init__(self, space, name, mode)
-        self.flags = libffi.FUNCFLAG_STDCALL
-
-@unwrap_spec(name='str_or_None', mode=int)
-def descr_new_windll(space, w_type, name, mode=-1):
-    return space.wrap(W_WinDLL(space, name, mode))
-
-
-W_WinDLL.typedef = TypeDef(
-    '_ffi.WinDLL',
-    __new__     = interp2app(descr_new_windll),
-    getfunc     = interp2app(W_WinDLL.getfunc),
-    getaddressindll = interp2app(W_WinDLL.getaddressindll),
-    )
-
-# ========================================================================
-
-def get_libc(space):
-    try:
-        return space.wrap(W_CDLL(space, get_libc_name(), -1))
-    except OSError, e:
-        raise wrap_oserror(space, e)
-

File pypy/module/_ffi/interp_struct.py

-from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.rlib import clibffi
-from rpython.rlib import libffi
-from rpython.rlib import jit
-from rpython.rlib.rgc import must_be_light_finalizer
-from rpython.rlib.rarithmetic import r_uint, r_ulonglong, intmask
-from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.typedef import TypeDef, interp_attrproperty
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.error import operationerrfmt
-from pypy.module._ffi.interp_ffitype import W_FFIType
-from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter
-
-
-class W_Field(W_Root):
-    def __init__(self, name, w_ffitype):
-        self.name = name
-        self.w_ffitype = w_ffitype
-        self.offset = -1
-
-    def __repr__(self):
-        return '<Field %s %s>' % (self.name, self.w_ffitype.name)
-
-@unwrap_spec(name=str)
-def descr_new_field(space, w_type, name, w_ffitype):
-    w_ffitype = space.interp_w(W_FFIType, w_ffitype)
-    return W_Field(name, w_ffitype)
-
-W_Field.typedef = TypeDef(
-    'Field',
-    __new__ = interp2app(descr_new_field),
-    name = interp_attrproperty('name', W_Field),
-    ffitype = interp_attrproperty('w_ffitype', W_Field),
-    offset = interp_attrproperty('offset', W_Field),
-    )
-
-
-# ==============================================================================
-
-class FFIStructOwner(object):
-    """
-    The only job of this class is to stay outside of the reference cycle
-    W__StructDescr -> W_FFIType -> W__StructDescr and free the ffistruct
-    """
-
-    def __init__(self, ffistruct):
-        self.ffistruct = ffistruct
-
-    @must_be_light_finalizer
-    def __del__(self):
-        if self.ffistruct:
-            lltype.free(self.ffistruct, flavor='raw', track_allocation=True)
-
-
-class W__StructDescr(W_Root):
-
-    def __init__(self, name):
-        self.w_ffitype = W_FFIType('struct %s' % name, clibffi.FFI_TYPE_NULL,
-                                   w_structdescr=self)
-        self.fields_w = None
-        self.name2w_field = {}
-        self._ffistruct_owner = None
-
-    def define_fields(self, space, w_fields):
-        if self.fields_w is not None:
-            raise operationerrfmt(space.w_ValueError,
-                                  "%s's fields has already been defined",
-                                  self.w_ffitype.name)
-        fields_w = space.fixedview(w_fields)
-        # note that the fields_w returned by compute_size_and_alignement has a
-        # different annotation than the original: list(W_Root) vs list(W_Field)
-        size, alignment, fields_w = compute_size_and_alignement(space, fields_w)
-        self.fields_w = fields_w
-        field_types = [] # clibffi's types
-        for w_field in fields_w:
-            field_types.append(w_field.w_ffitype.get_ffitype())
-            self.name2w_field[w_field.name] = w_field
-        #
-        # on CPython, the FFIStructOwner might go into gc.garbage and thus the
-        # __del__ never be called. Thus, we don't track the allocation of the
-        # malloc done inside this function, else the leakfinder might complain
-        ffistruct = clibffi.make_struct_ffitype_e(size, alignment, field_types,
-                                                  track_allocation=False)
-        self.w_ffitype.set_ffitype(ffistruct.ffistruct)
-        self._ffistruct_owner = FFIStructOwner(ffistruct)
-
-    def check_complete(self, space):
-        if self.fields_w is None:
-            raise operationerrfmt(space.w_ValueError, "%s has an incomplete type",
-                                  self.w_ffitype.name)
-
-    def allocate(self, space):
-        self.check_complete(space)
-        return W__StructInstance(self)
-
-    @unwrap_spec(addr=int)
-    def fromaddress(self, space, addr):
-        self.check_complete(space)
-        rawmem = rffi.cast(rffi.VOIDP, addr)
-        return W__StructInstance(self, allocate=False, autofree=True, rawmem=rawmem)
-
-    @jit.elidable_promote('0')
-    def get_type_and_offset_for_field(self, space, name):
-        try:
-            w_field = self.name2w_field[name]
-        except KeyError:
-            raise operationerrfmt(space.w_AttributeError, '%s', name)
-
-        return w_field.w_ffitype, w_field.offset
-
-
-
-@unwrap_spec(name=str)
-def descr_new_structdescr(space, w_type, name, w_fields=None):
-    descr = W__StructDescr(name)
-    if not space.is_none(w_fields):
-        descr.define_fields(space, w_fields)
-    return descr
-
-def round_up(size, alignment):
-    return (size + alignment - 1) & -alignment
-
-def compute_size_and_alignement(space, fields_w):
-    size = 0
-    alignment = 1
-    fields_w2 = []
-    for w_field in fields_w:
-        w_field = space.interp_w(W_Field, w_field)
-        fieldsize = w_field.w_ffitype.sizeof()
-        fieldalignment = w_field.w_ffitype.get_alignment()
-        alignment = max(alignment, fieldalignment)
-        size = round_up(size, fieldalignment)
-        w_field.offset = size
-        size += fieldsize
-        fields_w2.append(w_field)
-    #
-    size = round_up(size, alignment)
-    return size, alignment, fields_w2
-
-
-
-W__StructDescr.typedef = TypeDef(
-    '_StructDescr',
-    __new__ = interp2app(descr_new_structdescr),
-    ffitype = interp_attrproperty('w_ffitype', W__StructDescr),
-    define_fields = interp2app(W__StructDescr.define_fields),
-    allocate = interp2app(W__StructDescr.allocate),
-    fromaddress = interp2app(W__StructDescr.fromaddress),
-    )
-
-
-# ==============================================================================
-
-NULL = lltype.nullptr(rffi.VOIDP.TO)
-
-class W__StructInstance(W_Root):
-
-    _immutable_fields_ = ['structdescr', 'rawmem']
-
-    def __init__(self, structdescr, allocate=True, autofree=True, rawmem=NULL):
-        self.structdescr = structdescr
-        self.autofree = autofree
-        if allocate:
-            assert not rawmem
-            assert autofree
-            size = structdescr.w_ffitype.sizeof()
-            self.rawmem = lltype.malloc(rffi.VOIDP.TO, size, flavor='raw',
-                                        zero=True, add_memory_pressure=True)
-        else:
-            self.rawmem = rawmem
-
-    @must_be_light_finalizer
-    def __del__(self):
-        if self.autofree and self.rawmem:
-            lltype.free(self.rawmem, flavor='raw')
-            self.rawmem = lltype.nullptr(rffi.VOIDP.TO)
-
-    def getaddr(self, space):
-        addr = rffi.cast(rffi.ULONG, self.rawmem)
-        return space.wrap(addr)
-
-    @unwrap_spec(name=str)
-    def getfield(self, space, name):
-        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(
-            space, name)
-        field_getter = GetFieldConverter(space, self.rawmem, offset)
-        return field_getter.do_and_wrap(w_ffitype)
-
-    @unwrap_spec(name=str)
-    def setfield(self, space, name, w_value):
-        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(
-            space, name)
-        field_setter = SetFieldConverter(space, self.rawmem, offset)
-        field_setter.unwrap_and_do(w_ffitype, w_value)
-
-
-class GetFieldConverter(ToAppLevelConverter):
-    """
-    A converter used by W__StructInstance to get a field from the struct and
-    wrap it to the correct app-level type.
-    """
-
-    def __init__(self, space, rawmem, offset):
-        self.space = space
-        self.rawmem = rawmem
-        self.offset = offset
-
-    def get_longlong(self, w_ffitype):
-        return libffi.struct_getfield_longlong(libffi.types.slonglong,
-                                               self.rawmem, self.offset)
-
-    def get_ulonglong(self, w_ffitype):
-        longlongval = libffi.struct_getfield_longlong(libffi.types.ulonglong,
-                                                      self.rawmem, self.offset)
-        return r_ulonglong(longlongval)
-
-
-    def get_signed(self, w_ffitype):
-        return libffi.struct_getfield_int(w_ffitype.get_ffitype(),
-                                          self.rawmem, self.offset)
-
-    def get_unsigned(self, w_ffitype):
-        value = libffi.struct_getfield_int(w_ffitype.get_ffitype(),
-                                           self.rawmem, self.offset)
-        return r_uint(value)
-
-    get_unsigned_which_fits_into_a_signed = get_signed
-    get_pointer = get_unsigned
-
-    def get_char(self, w_ffitype):
-        intval = libffi.struct_getfield_int(w_ffitype.get_ffitype(),
-                                            self.rawmem, self.offset)
-        return rffi.cast(rffi.UCHAR, intval)
-
-    def get_unichar(self, w_ffitype):
-        intval = libffi.struct_getfield_int(w_ffitype.get_ffitype(),
-                                            self.rawmem, self.offset)
-        return rffi.cast(rffi.WCHAR_T, intval)
-
-    def get_float(self, w_ffitype):
-        return libffi.struct_getfield_float(w_ffitype.get_ffitype(),
-                                            self.rawmem, self.offset)
-
-    def get_singlefloat(self, w_ffitype):
-        return libffi.struct_getfield_singlefloat(w_ffitype.get_ffitype(),
-                                                  self.rawmem, self.offset)
-
-    def get_struct(self, w_ffitype, w_structdescr):
-        assert isinstance(w_structdescr, W__StructDescr)
-        rawmem = rffi.cast(rffi.CCHARP, self.rawmem)
-        innermem = rffi.cast(rffi.VOIDP, rffi.ptradd(rawmem, self.offset))
-        # we return a reference to the inner struct, not a copy
-        # autofree=False because it's still owned by the parent struct
-        return W__StructInstance(w_structdescr, allocate=False, autofree=False,
-                                 rawmem=innermem)
-
-    ## def get_void(self, w_ffitype):
-    ##     ...
-
-
-class SetFieldConverter(FromAppLevelConverter):
-    """
-    A converter used by W__StructInstance to convert an app-level object to
-    the corresponding low-level value and set the field of a structure.
-    """
-
-    def __init__(self, space, rawmem, offset):
-        self.space = space
-        self.rawmem = rawmem
-        self.offset = offset
-
-    def handle_signed(self, w_ffitype, w_obj, intval):
-        libffi.struct_setfield_int(w_ffitype.get_ffitype(), self.rawmem, self.offset,
-                                   intval)
-
-    def handle_unsigned(self, w_ffitype, w_obj, uintval):
-        libffi.struct_setfield_int(w_ffitype.get_ffitype(), self.rawmem, self.offset,
-                                   intmask(uintval))
-
-    handle_pointer = handle_signed
-    handle_char = handle_signed
-    handle_unichar = handle_signed
-
-    def handle_longlong(self, w_ffitype, w_obj, longlongval):
-        libffi.struct_setfield_longlong(w_ffitype.get_ffitype(),
-                                        self.rawmem, self.offset, longlongval)
-
-    def handle_float(self, w_ffitype, w_obj, floatval):
-        libffi.struct_setfield_float(w_ffitype.get_ffitype(),
-                                     self.rawmem, self.offset, floatval)
-
-    def handle_singlefloat(self, w_ffitype, w_obj, singlefloatval):
-        libffi.struct_setfield_singlefloat(w_ffitype.get_ffitype(),
-                                           self.rawmem, self.offset, singlefloatval)
-
-    def handle_struct(self, w_ffitype, w_structinstance):
-        rawmem = rffi.cast(rffi.CCHARP, self.rawmem)
-        dst = rffi.cast(rffi.VOIDP, rffi.ptradd(rawmem, self.offset))
-        src = w_structinstance.rawmem
-        length = w_ffitype.sizeof()
-        rffi.c_memcpy(dst, src, length)
-
-    ## def handle_char_p(self, w_ffitype, w_obj, strval):
-    ##     ...
-
-    ## def handle_unichar_p(self, w_ffitype, w_obj, unicodeval):
-    ##     ...
-
-
-
-
-W__StructInstance.typedef = TypeDef(
-    '_StructInstance',
-    getaddr  = interp2app(W__StructInstance.getaddr),
-    getfield = interp2app(W__StructInstance.getfield),
-    setfield = interp2app(W__StructInstance.setfield),
-    )

File pypy/module/_ffi/test/__init__.py

Empty file removed.

File pypy/module/_ffi/test/test_ffitype.py

-from pypy.module._ffi.test.test_funcptr import BaseAppTestFFI
-
-class AppTestFFIType(BaseAppTestFFI):
-
-    def test_simple_types(self):
-        from _ffi import types
-        assert str(types.sint) == "<ffi type sint>"
-        assert str(types.uint) == "<ffi type uint>"
-        assert types.sint.name == 'sint'
-        assert types.uint.name == 'uint'
-        
-    def test_sizeof(self):
-        from _ffi import types
-        assert types.sbyte.sizeof() == 1
-        assert types.sint.sizeof() == 4
-
-    def test_typed_pointer(self):
-        from _ffi import types
-        intptr = types.Pointer(types.sint) # create a typed pointer to sint
-        assert intptr.deref_pointer() is types.sint
-        assert str(intptr) == '<ffi type (pointer to sint)>'
-        assert types.sint.deref_pointer() is None
-        raises(TypeError, "types.Pointer(42)")
-
-    def test_pointer_identity(self):
-        from _ffi import types
-        x = types.Pointer(types.slong)
-        y = types.Pointer(types.slong)
-        z = types.Pointer(types.char)
-        assert x is y
-        assert x is not z
-
-    def test_char_p_cached(self):
-        from _ffi import types
-        x = types.Pointer(types.char)
-        assert x is types.char_p
-        x = types.Pointer(types.unichar)
-        assert x is types.unichar_p
-

File pypy/module/_ffi/test/test_funcptr.py

-from rpython.rtyper.lltypesystem import rffi
-from rpython.rlib.clibffi import get_libc_name
-from rpython.rlib.libffi import types
-from rpython.rlib.libffi import CDLL
-from rpython.rlib.test.test_clibffi import get_libm_name
-
-import sys, py
-
-class BaseAppTestFFI(object):
-    spaceconfig = dict(usemodules=('_ffi', '_rawffi'))
-
-    @classmethod
-    def prepare_c_example(cls):
-        from rpython.tool.udir import udir
-        from rpython.translator.tool.cbuild import ExternalCompilationInfo
-        from rpython.translator.platform import platform
-
-        c_file = udir.ensure("test__ffi", dir=1).join("foolib.c")
-        # automatically collect the C source from the docstrings of the tests
-        snippets = ["""
-        #ifdef _WIN32
-        #define DLLEXPORT __declspec(dllexport)
-        #else
-        #define DLLEXPORT
-        #endif
-        """]
-        for name in dir(cls):
-            if name.startswith('test_'):
-                meth = getattr(cls, name)
-                # the heuristic to determine it it's really C code could be
-                # improved: so far we just check that there is a '{' :-)
-                if meth.__doc__ is not None and '{' in meth.__doc__:
-                    snippets.append(meth.__doc__)
-        #
-        c_file.write(py.code.Source('\n'.join(snippets)))
-        eci = ExternalCompilationInfo(export_symbols=[])
-        return str(platform.compile([c_file], eci, 'x', standalone=False))
-
-    def setup_class(cls):
-        space = cls.space
-        cls.w_iswin32 = space.wrap(sys.platform == 'win32')
-        cls.w_libfoo_name = space.wrap(cls.prepare_c_example())
-        cls.w_libc_name = space.wrap(get_libc_name())
-        libm_name = get_libm_name(sys.platform)
-        cls.w_libm_name = space.wrap(libm_name)
-        libm = CDLL(libm_name)
-        pow = libm.getpointer('pow', [], types.void)
-        pow_addr = rffi.cast(rffi.LONG, pow.funcsym)
-        cls._libm = libm     # otherwise it gets unloaded - argh!
-        cls.w_pow_addr = space.wrap(pow_addr)
-
-class AppTestFFI(BaseAppTestFFI):
-
-    def setup_class(cls):
-        BaseAppTestFFI.setup_class.im_func(cls)
-        space = cls.space
-        # these are needed for test_single_float_args
-        from ctypes import c_float
-        f_12_34 = c_float(12.34).value
-        f_56_78 = c_float(56.78).value
-        f_result = c_float(f_12_34 + f_56_78).value
-        cls.w_f_12_34_plus_56_78 = space.wrap(f_result)
-
-    def test_libload(self):
-        import _ffi
-        _ffi.CDLL(self.libc_name)
-
-    def test_libload_fail(self):
-        import _ffi
-        raises(OSError, _ffi.CDLL, "xxxxx_this_name_does_not_exist_xxxxx")
-
-    def test_libload_None(self):
-        if self.iswin32:
-            skip("unix specific")
-        from _ffi import CDLL, types
-        # this should return *all* loaded libs, dlopen(NULL)
-        dll = CDLL(None)
-        # libm should be loaded
-        res = dll.getfunc('sqrt', [types.double], types.double)(1.0)
-        assert res == 1.0
-
-    def test_callfunc(self):
-        from _ffi import CDLL, types
-        libm = CDLL(self.libm_name)
-        pow = libm.getfunc('pow', [types.double, types.double], types.double)
-        assert pow(2, 3) == 8
-
-    def test_getaddr(self):
-        from _ffi import CDLL, types
-        libm = CDLL(self.libm_name)
-        pow = libm.getfunc('pow', [types.double, types.double], types.double)
-        assert pow.getaddr() == self.pow_addr
-
-    def test_getaddressindll(self):
-        import sys
-        from _ffi import CDLL
-        libm = CDLL(self.libm_name)
-        pow_addr = libm.getaddressindll('pow')
-        fff = sys.maxint*2-1
-        if sys.platform == 'win32' or sys.platform == 'darwin':
-            fff = sys.maxint*2+1
-        assert pow_addr == self.pow_addr & fff
-
-    def test_func_fromaddr(self):
-        from _ffi import CDLL, types, FuncPtr
-        libm = CDLL(self.libm_name)
-        pow_addr = libm.getaddressindll('pow')
-        pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double],
-                               types.double)
-        assert pow(2, 3) == 8
-
-    def test_int_args(self):
-        """
-            DLLEXPORT int sum_xy(int x, int y)
-            {
-                return x+y;
-            }
-        """
-        import sys
-        from _ffi import CDLL, types
-        libfoo = CDLL(self.libfoo_name)
-        sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint)
-        assert sum_xy(30, 12) == 42
-        assert sum_xy(sys.maxint*2, 0) == -2
-
-    def test_void_result(self):
-        """
-            int dummy = 0;
-            DLLEXPORT void set_dummy(int val) { dummy = val; }
-            DLLEXPORT int get_dummy() { return dummy; }
-        """
-        from _ffi import CDLL, types
-        libfoo = CDLL(self.libfoo_name)
-        set_dummy = libfoo.getfunc('set_dummy', [types.sint], types.void)
-        get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
-        assert get_dummy() == 0
-        assert set_dummy(42) is None
-        assert get_dummy() == 42
-        set_dummy(0)
-
-    def test_pointer_args(self):
-        """
-            extern int dummy; // defined in test_void_result
-            DLLEXPORT int* get_dummy_ptr() { return &dummy; }
-            DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; }
-        """
-        from _ffi import CDLL, types
-        libfoo = CDLL(self.libfoo_name)
-        get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
-        get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p)
-        set_val_to_ptr = libfoo.getfunc('set_val_to_ptr',