Commits

Maciej Fijalkowski committed 8bd9e16 Merge

merge default

Comments (0)

Files changed (12)

lib-python/2.7/ctypes/__init__.py

         self._FuncPtr = _FuncPtr
 
         if handle is None:
-            self._handle = _ffi.CDLL(name, mode)
+            if flags & _FUNCFLAG_CDECL:
+                self._handle = _ffi.CDLL(name, mode)
+            else:
+                self._handle = _ffi.WinDLL(name, mode)
         else:
             self._handle = handle
 

lib_pypy/_ctypes/function.py

         address = self._get_address()
         ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
         ffires = restype.get_ffi_argtype()
-        return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires)
+        return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires, self._flags_)
 
     def _getfuncptr(self, argtypes, restype, thisarg=None):
         if self._ptr is not None and (argtypes is self._argtypes_ or argtypes == self._argtypes_):
             ptr = thisarg[0][self._com_index - 0x1000]
             ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
             ffires = restype.get_ffi_argtype()
-            return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires)
+            return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_)
         
         cdll = self.dll._handle
         try:

pypy/doc/cppyy.rst

   If a pointer is a global variable, the C++ side can replace the underlying
   object and the python side will immediately reflect that.
 
+* **PyObject***: Arguments and return types of ``PyObject*`` can be used, and
+  passed on to CPython API calls.
+  Since these CPython-like objects need to be created and tracked (this all
+  happens through ``cpyext``) this interface is not particularly fast.
+
 * **static data members**: Are represented as python property objects on the
   class and the meta-class.
   Both read and write access is as expected.

pypy/doc/whatsnew-1.9.rst

 _invalid_parameter_handler
 .. branch: win32-kill
 Add os.kill to windows even if translating python does not have os.kill
+.. branch: win_ffi
+Handle calling conventions for the _ffi and ctypes modules
 .. branch: win64-stage1
 .. branch: zlib-mem-pressure
 Memory "leaks" associated with zlib are fixed.

pypy/jit/backend/x86/test/test_ztranslation.py

         #
         from pypy.rpython.lltypesystem import lltype, rffi
         from pypy.rlib.libffi import types, CDLL, ArgChain
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         libm_name = get_libm_name(sys.platform)
         jitdriver2 = JitDriver(greens=[], reds = ['i', 'func', 'res', 'x'])
         def libffi_stuff(i, j):

pypy/module/_ffi/__init__.py

 from pypy.interpreter.mixedmodule import MixedModule
+import os
 
 class Module(MixedModule):
 
         '_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',
         }

pypy/module/_ffi/interp_funcptr.py

 #
 from pypy.rlib import jit
 from pypy.rlib import libffi
+from pypy.rlib.clibffi import get_libc_name, StackCheckError
 from pypy.rlib.rdynload import DLOpenError
 from pypy.rlib.rarithmetic import intmask, r_uint
 from pypy.rlib.objectmodel import we_are_translated
         self = jit.promote(self)
         argchain = self.build_argchain(space, args_w)
         func_caller = CallFunctionConverter(space, self.func, argchain)
-        return func_caller.do_and_wrap(self.w_restype)
+        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):
     restype = unwrap_ffitype(space, w_restype, allow_void=True)
     return argtypes_w, argtypes, w_restype, restype
 
-@unwrap_spec(addr=r_uint, name=str)
-def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_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)
-    func = libffi.Func(name, argtypes, restype, addr)
+    func = libffi.Func(name, argtypes, restype, addr, flags)
     return W_FuncPtr(func, argtypes_w, w_restype)
 
 
 
 class W_CDLL(Wrappable):
     def __init__(self, space, name, mode):
+        self.flags = libffi.FUNCFLAG_CDECL
         self.space = space
         if name is None:
             self.name = "<None>"
                                                                    w_argtypes,
                                                                    w_restype)
         try:
-            func = self.cdll.getpointer(name, argtypes, restype)
+            func = self.cdll.getpointer(name, argtypes, restype, 
+                                            flags = self.flags)
         except KeyError:
             raise operationerrfmt(space.w_AttributeError,
                                   "No symbol %s found in library %s", name, self.name)
     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):
-    from pypy.rlib.clibffi import get_libc_name
     try:
         return space.wrap(W_CDLL(space, get_libc_name(), -1))
     except OSError, e:

pypy/module/_ffi/test/test_funcptr.py

 from pypy.conftest import gettestobjspace
-from pypy.translator.platform import platform
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.module._rawffi.interp_rawffi import TYPEMAP
-from pypy.module._rawffi.tracker import Tracker
-from pypy.translator.platform import platform
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.clibffi import get_libc_name
+from pypy.rlib.libffi import types
+from pypy.rlib.libffi import CDLL
+from pypy.rlib.test.test_clibffi import get_libm_name
 
-import os, sys, py
+import sys, py
 
 class BaseAppTestFFI(object):
 
         return str(platform.compile([c_file], eci, 'x', standalone=False))
 
     def setup_class(cls):
-        from pypy.rpython.lltypesystem import rffi
-        from pypy.rlib.libffi import get_libc_name, CDLL, types
-        from pypy.rlib.test.test_libffi import get_libm_name
         space = gettestobjspace(usemodules=('_ffi', '_rawffi'))
         cls.space = space
         cls.w_iswin32 = space.wrap(sys.platform == 'win32')
 
     def test_getaddressindll(self):
         import sys
-        from _ffi import CDLL, types
+        from _ffi import CDLL
         libm = CDLL(self.libm_name)
         pow_addr = libm.getaddressindll('pow')
         fff = sys.maxint*2-1
         assert pow_addr == self.pow_addr & fff
 
     def test_func_fromaddr(self):
-        import sys
         from _ffi import CDLL, types, FuncPtr
         libm = CDLL(self.libm_name)
         pow_addr = libm.getaddressindll('pow')
             skip("unix specific")
         libnone = CDLL(None)
         raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)")
+
+    def test_calling_convention1(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types
+        libm = WinDLL(self.libm_name)
+        pow = libm.getfunc('pow', [types.double, types.double], types.double)
+        try:
+            pow(2, 3)
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_calling_convention2(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types
+        kernel = WinDLL('Kernel32.dll')
+        sleep = kernel.getfunc('Sleep', [types.uint], types.void)
+        sleep(10)
+
+    def test_calling_convention3(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import CDLL, types
+        wrong_kernel = CDLL('Kernel32.dll')
+        wrong_sleep = wrong_kernel.getfunc('Sleep', [types.uint], types.void)
+        try:
+            wrong_sleep(10)
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_func_fromaddr2(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import CDLL, types, FuncPtr
+        from _rawffi import FUNCFLAG_STDCALL
+        libm = CDLL(self.libm_name)
+        pow_addr = libm.getaddressindll('pow')
+        wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', 
+                [types.double, types.double], types.double, FUNCFLAG_STDCALL)
+        try:
+            wrong_pow(2, 3) == 8
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_func_fromaddr3(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types, FuncPtr
+        from _rawffi import FUNCFLAG_STDCALL
+        kernel = WinDLL('Kernel32.dll')
+        sleep_addr = kernel.getaddressindll('Sleep')
+        sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], 
+                            types.void, FUNCFLAG_STDCALL)
+        sleep(10)
+
+ 

pypy/module/_ffi/test/test_type_converter.py

     get_unichar_p = get_all
     get_float = get_all
     get_singlefloat = get_all
+    get_unsigned_which_fits_into_a_signed = get_all
     
     def convert(self, w_ffitype, val):
         self.val = val

pypy/module/pypyjit/test_pypy_c/test__ffi.py

-import py
 import sys
 from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
 
 class Test__ffi(BaseTestPyPyC):
 
     def test__ffi_call(self):
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         def main(libm_name):
             try:
                 from _ffi import CDLL, types
 
 
     def test__ffi_call_frame_does_not_escape(self):
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         def main(libm_name):
             try:
                 from _ffi import CDLL, types
         assert opnames.count('new_with_vtable') == 1
 
     def test__ffi_call_releases_gil(self):
-        from pypy.rlib.test.test_libffi import get_libc_name
+        from pypy.rlib.clibffi import get_libc_name
         def main(libc_name, n):
             import time
+            import os
             from threading import Thread
-            from _ffi import CDLL, types
             #
-            libc = CDLL(libc_name)
-            sleep = libc.getfunc('sleep', [types.uint], types.uint)
-            delays = [0]*n + [1]
+            if os.name == 'nt':
+                from _ffi import WinDLL, types
+                libc = WinDLL(libc_name)
+                sleep = libc.getfunc('Sleep', [types.uint], types.uint)
+                delays = [0]*n + [1000]
+            else:
+                from _ffi import CDLL, types
+                libc = CDLL(libc_name)
+                sleep = libc.getfunc('sleep', [types.uint], types.uint)
+                delays = [0]*n + [1]
             #
             def loop_of_sleeps(i, delays):
                 for delay in delays:
                 thread.join()
             end = time.time()
             return end - start
-        #
         log = self.run(main, [get_libc_name(), 200], threshold=150,
                        import_site=True)
         assert 1 <= log.result <= 1.5 # at most 0.5 seconds of overhead
 
 
     def test_ctypes_call(self):
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         def main(libm_name):
             import ctypes
             libm = ctypes.CDLL(libm_name)

pypy/rlib/libffi.py

 from __future__ import with_statement
 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.rlib.objectmodel import specialize, enforceargs, we_are_translated
+from pypy.rlib.objectmodel import specialize, enforceargs
 from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat, r_longlong
 from pypy.rlib import jit
 from pypy.rlib import clibffi
-from pypy.rlib.clibffi import get_libc_name, FUNCFLAG_CDECL, AbstractFuncPtr, \
-    push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT
+from pypy.rlib.clibffi import FUNCFLAG_CDECL, FUNCFLAG_STDCALL, \
+        AbstractFuncPtr, push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT
 from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal
 from pypy.rlib.rdynload import DLLHANDLE
 
+import os
+
 class types(object):
     """
     This namespace contains the primitive types you can use to declare the
         else:
             res = None
         self._free_buffers(ll_result, ll_args)
-        #check_fficall_result(ffires, self.flags)
+        clibffi.check_fficall_result(ffires, self.flags)
         return res
 
     def _free_buffers(self, ll_result, ll_args):
     def getaddressindll(self, name):
         return dlsym(self.lib, name)
 
+if os.name == 'nt':
+    class WinDLL(CDLL):
+        def getpointer(self, name, argtypes, restype, flags=FUNCFLAG_STDCALL):
+            return Func(name, argtypes, restype, dlsym(self.lib, name),
+                        flags=flags, keepalive=self)
 # ======================================================================
 
 @jit.oopspec('libffi_struct_getfield(ffitype, addr, offset)')

pypy/rlib/test/test_libffi.py

-import sys
+import os
 
 import py
 
 from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong
-from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name, make_struct_ffitype_e
+from pypy.rlib.test.test_clibffi import BaseFfiTest, make_struct_ffitype_e
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED
-from pypy.rlib.libffi import (CDLL, Func, get_libc_name, ArgChain, types,
+from pypy.rpython.llinterp import LLException
+from pypy.rlib.libffi import (CDLL, ArgChain, types,
                               IS_32_BIT, array_getitem, array_setitem)
 from pypy.rlib.libffi import (struct_getfield_int, struct_setfield_int,
                               struct_getfield_longlong, struct_setfield_longlong,
         #
         lltype.free(p, flavor='raw')
 
+    def test_windll(self):
+        if os.name != 'nt':
+            skip('Run only on windows')
+        from pypy.rlib.libffi import WinDLL
+        dll = WinDLL('Kernel32.dll')
+        sleep = dll.getpointer('Sleep',[types.uint], types.void)
+        chain = ArgChain()
+        chain.arg(10)
+        sleep.call(chain, lltype.Void, is_struct=False)
 
 class TestLibffiCall(BaseFfiTest):
     """
         eci = ExternalCompilationInfo(export_symbols=exports)
         cls.libfoo_name = str(platform.compile([c_file], eci, 'x',
                                                standalone=False))
+        cls.dll = cls.CDLL(cls.libfoo_name)
+
+    def teardown_class(cls):
+        if cls.dll:
+            cls.dll.__del__()
+            # Why doesn't this call cls.dll.__del__() ?
+            #del cls.dll
 
     def get_libfoo(self):
-        return self.CDLL(self.libfoo_name)
+        return self.dll    
 
     def call(self, funcspec, args, RESULT, is_struct=False, jitif=[]):
         """
         assert p[1] == 34
         lltype.free(p, flavor='raw')
         lltype.free(ffi_point_struct, flavor='raw')
+
+    if os.name == 'nt':
+        def test_stdcall_simple(self):
+            """
+                int __stdcall std_diff_xy(int x, Signed y)
+                {
+                    return x - y;
+                }
+            """
+            libfoo = self.get_libfoo()
+            func = (libfoo, 'std_diff_xy', [types.sint, types.signed], types.sint)
+            try:
+                self.call(func, [50, 8], lltype.Signed)
+            except ValueError, e:
+                assert e.message == 'Procedure called with not enough ' + \
+                     'arguments (8 bytes missing) or wrong calling convention'
+            except LLException, e:
+                #jitted code raises this
+                assert str(e) == "<LLException 'StackCheckError'>"
+            else:
+                assert 0, 'wrong calling convention should have raised'
+
+