Author: Ronan Lamy <[email protected]>
Branch: fix-result-types
Changeset: r77352:d19d89cd5590
Date: 2015-05-16 21:44 +0100
http://bitbucket.org/pypy/pypy/changeset/d19d89cd5590/

Log:    hg merge default

diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py
--- a/lib_pypy/datetime.py
+++ b/lib_pypy/datetime.py
@@ -1507,8 +1507,13 @@
 
         converter = _time.localtime if tz is None else _time.gmtime
 
-        t, frac = divmod(t, 1.0)
-        us = _round(frac * 1e6)
+        if isinstance(t, int):
+            us = 0
+        else:
+            t_full = t
+            t = int(_math.floor(t))
+            frac = t_full - t
+            us = _round(frac * 1e6)
 
         # If timestamp is less than one microsecond smaller than a
         # full second, us can be rounded up to 1000000.  In this case,
@@ -1527,8 +1532,13 @@
     @classmethod
     def utcfromtimestamp(cls, t):
         "Construct a UTC datetime from a POSIX timestamp (like time.time())."
-        t, frac = divmod(t, 1.0)
-        us = _round(frac * 1e6)
+        if isinstance(t, int):
+            us = 0
+        else:
+            t_full = t
+            t = int(_math.floor(t))
+            frac = t_full - t
+            us = _round(frac * 1e6)
 
         # If timestamp is less than one microsecond smaller than a
         # full second, us can be rounded up to 1000000.  In this case,
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -320,6 +320,13 @@
   http://bugs.python.org/issue14621, some of us believe it has no
   purpose in CPython either.
 
+* You can't store non-string keys in type objects.  For example::
+
+    class A(object):
+        locals()[42] = 3
+
+  won't work.
+
 * ``sys.setrecursionlimit(n)`` sets the limit only approximately,
   by setting the usable stack space to ``n * 768`` bytes.  On Linux,
   depending on the compiler settings, the default of 768KB is enough
@@ -361,8 +368,13 @@
   opposed to a dict proxy like in CPython. Mutating the dict will change the
   type and vice versa. For builtin types, a dictionary will be returned that
   cannot be changed (but still looks and behaves like a normal dictionary).
+  
+* some functions and attributes of the ``gc`` module behave in a
+  slightly different way: for example, ``gc.enable`` and
+  ``gc.disable`` are supported, but instead of enabling and disabling
+  the GC, they just enable and disable the execution of finalizers.
 
 * PyPy prints a random line from past #pypy IRC topics at startup in
-  interactive mode. In a released version, this behaviour is supressed, but
+  interactive mode. In a released version, this behaviour is suppressed, but
   setting the environment variable PYPY_IRC_TOPIC will bring it back. Note that
   downstream package providers have been known to totally disable this feature.
diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst
--- a/pypy/doc/embedding.rst
+++ b/pypy/doc/embedding.rst
@@ -51,6 +51,9 @@
    otherwise return 0.  You should really do your own error handling in the
    source. It'll acquire the GIL.
 
+   Note: this is meant to be called *only once* or a few times at most.  See
+   the `more complete example`_ below.
+
 .. function:: int pypy_execute_source_ptr(char* source, void* ptr);
 
    .. note:: Not available in PyPy <= 2.2.1
@@ -65,8 +68,9 @@
    Note that this function is not thread-safe itself, so you need to guard it
    with a mutex.
 
-Simple example
---------------
+
+Minimal example
+---------------
 
 Note that this API is a lot more minimal than say CPython C API, so at first
 it's obvious to think that you can't do much. However, the trick is to do
@@ -78,10 +82,10 @@
 
 .. code-block:: c
 
-    #include "include/PyPy.h"
+    #include "PyPy.h"
     #include <stdio.h>
 
-    const char source[] = "print 'hello from pypy'";
+    static char source[] = "print 'hello from pypy'";
 
     int main(void)
     {
@@ -103,154 +107,115 @@
 
 If we save it as ``x.c`` now, compile it and run it (on linux) with::
 
-    fijal@hermann:/opt/pypy$ gcc -o x x.c -lpypy-c -L.
-    fijal@hermann:/opt/pypy$ LD_LIBRARY_PATH=. ./x
+    $ gcc -g -o x x.c -lpypy-c -L/opt/pypy/bin -I/opt/pypy/include
+    $ LD_LIBRARY_PATH=/opt/pypy/bin ./x
     hello from pypy
 
-on OSX it is necessary to set the rpath of the binary if one wants to link to 
it::
+.. note:: If the compilation fails because of missing PyPy.h header file,
+          you are running PyPy <= 2.2.1.  Get it here__.
+
+.. __: 
https://bitbucket.org/pypy/pypy/raw/c4cd6eca9358066571500ac82aaacfdaa3889e8c/include/PyPy.h
+
+On OSX it is necessary to set the rpath of the binary if one wants to link to 
it,
+with a command like::
 
     gcc -o x x.c -lpypy-c -L. -Wl,-rpath -Wl,@executable_path
     ./x
     hello from pypy
 
-Worked!
 
-.. note:: If the compilation fails because of missing PyPy.h header file,
-          you are running PyPy <= 2.2.1, please see the section `Missing 
PyPy.h`_.
-
-Missing PyPy.h
---------------
-
-.. note:: PyPy.h is in the nightly builds and goes to new PyPy releases 
(>2.2.1).
-
-For PyPy <= 2.2.1, you can download PyPy.h from PyPy repository (it has been 
added in commit c4cd6ec):
-
-.. code-block:: bash
-
-    cd /opt/pypy/include
-    wget 
https://bitbucket.org/pypy/pypy/raw/c4cd6eca9358066571500ac82aaacfdaa3889e8c/include/PyPy.h
-
-
-More advanced example
+More complete example
 ---------------------
 
 .. note:: This example depends on pypy_execute_source_ptr which is not 
available
-          in PyPy <= 2.2.1. You might want to see the alternative example
-          below.
+          in PyPy <= 2.2.1.
 
 Typically we need something more to do than simply execute source. The 
following
 is a fully fledged example, please consult cffi documentation for details.
 It's a bit longish, but it captures a gist what can be done with the PyPy
 embedding interface:
 
+.. code-block:: python
+
+    # file "interface.py"
+    
+    import cffi
+
+    ffi = cffi.FFI()
+    ffi.cdef('''
+    struct API {
+        double (*add_numbers)(double x, double y);
+    };
+    ''')
+
+    # Better define callbacks at module scope, it's important to
+    # keep this object alive.
+    @ffi.callback("double (double, double)")
+    def add_numbers(x, y):
+        return x + y
+
+    def fill_api(ptr):
+        global api
+        api = ffi.cast("struct API*", ptr)
+        api.add_numbers = add_numbers
+
 .. code-block:: c
 
-    #include "include/PyPy.h"
+    /* C example */
+    #include "PyPy.h"
     #include <stdio.h>
 
-    char source[] = "from cffi import FFI\n\
-    ffi = FFI()\n\
-    @ffi.callback('int(int)')\n\
-    def func(a):\n\
-        print 'Got from C %d' % a\n\
-        return a * 2\n\
-    ffi.cdef('int callback(int (*func)(int));')\n\
-    c_func = ffi.cast('int(*)(int(*)(int))', c_argument)\n\
-    c_func(func)\n\
-    print 'finished the Python part'\n\
-    ";
+    struct API {
+        double (*add_numbers)(double x, double y);
+    };
 
-    int callback(int (*func)(int))
+    struct API api;   /* global var */
+
+    int initialize_api(void)
     {
-        printf("Calling to Python, result: %d\n", func(3));
-    }
-
-    int main()
-    {
+        static char source[] =
+            "import sys; sys.path.insert(0, '.'); "
+            "import interface; interface.fill_api(c_argument)";
         int res;
-        void *lib, *func;
 
         rpython_startup_code();
         res = pypy_setup_home("/opt/pypy/bin/libpypy-c.so", 1);
         if (res) {
-            printf("Error setting pypy home!\n");
+            fprintf(stderr, "Error setting pypy home!\n");
+            return -1;
+        }
+        res = pypy_execute_source_ptr(source, &api);
+        if (res) {
+            fprintf(stderr, "Error calling pypy_execute_source_ptr!\n");
+            return -1;
+        }
+        return 0;
+    }
+
+    int main(void)
+    {
+        if (initialize_api() < 0)
             return 1;
-        }
-        res = pypy_execute_source_ptr(source, (void*)callback);
-        if (res) {
-            printf("Error calling pypy_execute_source_ptr!\n");
-        }
-        return res;
+
+        printf("sum: %f\n", api.add_numbers(12.3, 45.6));
+
+        return 0;
     }
 
 you can compile and run it with::
 
-   fijal@hermann:/opt/pypy$ gcc -g -o x x.c -lpypy-c -L.
-   fijal@hermann:/opt/pypy$ LD_LIBRARY_PATH=. ./x
-   Got from C 3
-   Calling to Python, result: 6
-   finished the Python part
+    $ gcc -g -o x x.c -lpypy-c -L/opt/pypy/bin -I/opt/pypy/include
+    $ LD_LIBRARY_PATH=/opt/pypy/bin ./x
+    sum: 57.900000
 
-As you can see, we successfully managed to call Python from C and C from
-Python. Now having one callback might not be enough, so what typically happens
-is that we would pass a struct full of callbacks to ``pypy_execute_source_ptr``
-and fill the structure from Python side for the future use.
+As you can see, what we did is create a ``struct API`` that contains
+the custom API that we need in our particular case.  This struct is
+filled by Python to contain a function pointer that is then called
+form the C side.  It is also possible to do have other function
+pointers that are filled by the C side and called by the Python side,
+or even non-function-pointer fields: basically, the two sides
+communicate via this single C structure that defines your API.
 
-Alternative example
--------------------
-
-As ``pypy_execute_source_ptr`` is not available in PyPy 2.2.1, you might want 
to try 
-an alternative approach which relies on -export-dynamic flag to the GNU 
linker. 
-The downside to this approach is that it is platform dependent.
-
-.. code-block:: c
-
-    #include "include/PyPy.h"
-    #include <stdio.h>
-
-    char source[] = "from cffi import FFI\n\
-    ffi = FFI()\n\
-    @ffi.callback('int(int)')\n\
-    def func(a):\n\
-        print 'Got from C %d' % a\n\
-        return a * 2\n\
-    ffi.cdef('int callback(int (*func)(int));')\n\
-    lib = ffi.verify('int callback(int (*func)(int));')\n\
-    lib.callback(func)\n\
-    print 'finished the Python part'\n\
-    ";
-
-    int callback(int (*func)(int))
-    {
-        printf("Calling to Python, result: %d\n", func(3));
-    }
-
-    int main()
-    {
-        int res;
-        void *lib, *func;
-
-        rpython_startup_code();
-        res = pypy_setup_home("/opt/pypy/bin/libpypy-c.so", 1);
-        if (res) {
-            printf("Error setting pypy home!\n");
-            return 1;
-        }
-        res = pypy_execute_source(source);
-        if (res) {
-            printf("Error calling pypy_execute_source!\n");
-        }
-        return res;
-    }
-
-
-Make sure to pass -export-dynamic flag when compiling::
-
-   $ gcc -g -o x x.c -lpypy-c -L. -export-dynamic
-   $ LD_LIBRARY_PATH=. ./x
-   Got from C 3
-   Calling to Python, result: 6
-   finished the Python part
 
 Finding pypy_home
 -----------------
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
@@ -59,6 +59,7 @@
 exactly like `f(a, b)`.
 
 .. branch: issue2018
+
 branch issue2018:
 Allow prebuilt rpython dict with function values
 
@@ -66,26 +67,45 @@
 .. Merged but then backed out, hopefully it will return as vmprof2
 
 .. branch: object-dtype2
+
+branch object-dtype2:
 Extend numpy dtypes to allow using objects with associated garbage collection 
hook
 
 .. branch: vmprof2
+
+branch vmprof2:
 Add backend support for vmprof - a lightweight statistical profiler -
 to linux64, see client at https://vmprof.readthedocs.org
 
 .. branch: jit_hint_docs
+
+branch jit_hint_docs:
 Add more detail to @jit.elidable and @jit.promote in rpython/rlib/jit.py
 
 .. branch: remove-frame-debug-attrs
+
+branch remove_frame-debug-attrs:
 Remove the debug attributes from frames only used for tracing and replace
 them with a debug object that is created on-demand
 
 .. branch: can_cast
+
+branch can_cast:
 Implement np.can_cast, np.min_scalar_type and missing dtype comparison 
operations.
 
 .. branch: numpy-fixes
+
+branch numpy-fixes:
 Fix some error related to object dtype, non-contiguous arrays, inplement parts 
of 
 __array_interface__, __array_priority__, __array_wrap__
 
 .. branch: cells-local-stack
+
+branch cells-local-stack:
 Unify the PyFrame.cells and Pyframe.locals_stack_w lists, making frame objects
 1 or 3 words smaller.
+
+.. branch: pythonoptimize-env
+
+branch pythonoptimize-env
+Implement PYTHONOPTIMIZE environment variable, fixing issue #2044
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -12,7 +12,7 @@
 -i     : inspect interactively after running script; forces a prompt even
          if stdin does not appear to be a terminal; also PYTHONINSPECT=x
 -m mod : run library module as a script (terminates option list)
--O     : skip assert statements
+-O     : skip assert statements; also PYTHONOPTIMIZE=x
 -OO    : remove docstrings when importing modules in addition to -O
 -R     : ignored (see http://bugs.python.org/issue14621)
 -Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew
@@ -413,6 +413,21 @@
 
     return function(options, funcarg, iterargv)
 
+def parse_env(name, key, options):
+    ''' Modify options inplace if name exists in os.environ
+    '''
+    import os
+    v = os.getenv(name)
+    if v:
+        options[key] = max(1, options[key])
+        try:
+            newval = int(v)
+        except ValueError:
+            pass
+        else:
+            newval = max(1, newval)
+            options[key] = max(options[key], newval)
+
 def parse_command_line(argv):
     import os
     options = default_options.copy()
@@ -454,17 +469,15 @@
     sys.argv[:] = argv
 
     if not options["ignore_environment"]:
-        if os.getenv('PYTHONDEBUG'):
-            options["debug"] = 1
+        parse_env('PYTHONDEBUG', "debug", options)
         if os.getenv('PYTHONDONTWRITEBYTECODE'):
             options["dont_write_bytecode"] = 1
         if os.getenv('PYTHONNOUSERSITE'):
             options["no_user_site"] = 1
         if os.getenv('PYTHONUNBUFFERED'):
             options["unbuffered"] = 1
-        if os.getenv('PYTHONVERBOSE'):
-            options["verbose"] = 1
-
+        parse_env('PYTHONVERBOSE', "verbose", options)
+        parse_env('PYTHONOPTIMIZE', "optimize", options)
     if (options["interactive"] or
         (not options["ignore_environment"] and os.getenv('PYTHONINSPECT'))):
         options["inspect"] = 1
diff --git a/pypy/interpreter/test/test_app_main.py 
b/pypy/interpreter/test/test_app_main.py
--- a/pypy/interpreter/test/test_app_main.py
+++ b/pypy/interpreter/test/test_app_main.py
@@ -167,6 +167,11 @@
         self.check([], {'PYTHONNOUSERSITE': '1'}, sys_argv=[''], 
run_stdin=True, no_user_site=1)
         self.check([], {'PYTHONUNBUFFERED': '1'}, sys_argv=[''], 
run_stdin=True, unbuffered=1)
         self.check([], {'PYTHONVERBOSE': '1'}, sys_argv=[''], run_stdin=True, 
verbose=1)
+        self.check([], {'PYTHONOPTIMIZE': '1'}, sys_argv=[''], run_stdin=True, 
optimize=1)
+        self.check([], {'PYTHONOPTIMIZE': '0'}, sys_argv=[''], run_stdin=True, 
optimize=1)
+        self.check([], {'PYTHONOPTIMIZE': '10'}, sys_argv=[''], 
run_stdin=True, optimize=10)
+        self.check(['-O'], {'PYTHONOPTIMIZE': '10'}, sys_argv=[''], 
run_stdin=True, optimize=10)
+        self.check(['-OOO'], {'PYTHONOPTIMIZE': 'abc'}, sys_argv=[''], 
run_stdin=True, optimize=3)
 
     def test_sysflags(self):
         flags = (
diff --git a/pypy/module/_cffi_backend/ccallback.py 
b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -1,19 +1,21 @@
 """
 Callbacks.
 """
-import os
+import sys, os
 
-from rpython.rlib import clibffi, rweakref, jit
+from rpython.rlib import clibffi, rweakref, jit, jit_libffi
 from rpython.rlib.objectmodel import compute_unique_id, keepalive_until_here
 from rpython.rtyper.lltypesystem import lltype, rffi
 
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.module._cffi_backend import cerrno, misc
 from pypy.module._cffi_backend.cdataobj import W_CData
-from pypy.module._cffi_backend.ctypefunc import SIZE_OF_FFI_ARG, BIG_ENDIAN, 
W_CTypeFunc
+from pypy.module._cffi_backend.ctypefunc import SIZE_OF_FFI_ARG, W_CTypeFunc
 from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
 from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
 
+BIG_ENDIAN = sys.byteorder == 'big'
+
 # ____________________________________________________________
 
 
diff --git a/pypy/module/_cffi_backend/ctypefunc.py 
b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -188,7 +188,6 @@
 # ____________________________________________________________
 
 
-BIG_ENDIAN = sys.byteorder == 'big'
 USE_C_LIBFFI_MSVC = getattr(clibffi, 'USE_C_LIBFFI_MSVC', False)
 
 
@@ -399,16 +398,6 @@
         exchange_offset = rffi.sizeof(rffi.CCHARP) * nargs
         exchange_offset = self.align_arg(exchange_offset)
         cif_descr.exchange_result = exchange_offset
-        cif_descr.exchange_result_libffi = exchange_offset
-
-        if BIG_ENDIAN and self.fresult.is_primitive_integer:
-            # For results of precisely these types, libffi has a
-            # strange rule that they will be returned as a whole
-            # 'ffi_arg' if they are smaller.  The difference
-            # only matters on big-endian.
-            if self.fresult.size < SIZE_OF_FFI_ARG:
-                diff = SIZE_OF_FFI_ARG - self.fresult.size
-                cif_descr.exchange_result += diff
 
         # then enough room for the result, rounded up to sizeof(ffi_arg)
         exchange_offset += max(rffi.getintfield(self.rtype, 'c_size'),
diff --git a/pypy/module/cppyy/interp_cppyy.py 
b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -314,13 +314,6 @@
                 exchange_offset = rffi.sizeof(rffi.CCHARP) * nargs
                 exchange_offset = (exchange_offset + 7) & ~7     # alignment
                 cif_descr.exchange_result = exchange_offset
-                cif_descr.exchange_result_libffi = exchange_offset
-
-                # TODO: left this out while testing (see ctypefunc.py)
-                # For results of precisely these types, libffi has a
-                # strange rule that they will be returned as a whole
-                # 'ffi_arg' if they are smaller.  The difference
-                # only matters on big-endian.
 
                 # then enough room for the result, rounded up to 
sizeof(ffi_arg)
                 exchange_offset += max(rffi.getintfield(cif_descr.rtype, 
'c_size'),
diff --git a/pypy/module/micronumpy/compile.py 
b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -68,6 +68,7 @@
     w_complex = W_TypeObject("complex")
     w_dict = W_TypeObject("dict")
     w_object = W_TypeObject("object")
+    w_buffer = W_TypeObject("buffer")
 
     def __init__(self):
         """NOT_RPYTHON"""
diff --git a/pypy/module/micronumpy/descriptor.py 
b/pypy/module/micronumpy/descriptor.py
--- a/pypy/module/micronumpy/descriptor.py
+++ b/pypy/module/micronumpy/descriptor.py
@@ -566,6 +566,8 @@
         # testing, handle manually
         if space.eq_w(w_spec, space.wrap('u4,u4,u4')):
             w_lst = space.newlist([space.wrap('u4')]*3)
+        if space.eq_w(w_spec, space.wrap('u4,u4,u4')):
+            w_lst = space.newlist([space.wrap('u4')]*3)
         else:
             raise oefmt(space.w_RuntimeError,
                     "cannot parse w_spec")
diff --git a/pypy/module/micronumpy/ndarray.py 
b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -53,6 +53,11 @@
     def descr_set_shape(self, space, w_new_shape):
         shape = get_shape_from_iterable(space, self.get_size(), w_new_shape)
         self.implementation = self.implementation.set_shape(space, self, shape)
+        w_cls = space.type(self)
+        if not space.is_w(w_cls, space.gettypefor(W_NDimArray)):
+            # numpy madness - allow __array_finalize__(self, obj)
+            # to run, in MaskedArray this modifies obj._mask
+            wrap_impl(space, w_cls, self, self.implementation)
 
     def descr_get_strides(self, space):
         strides = self.implementation.get_strides()
@@ -883,6 +888,7 @@
         if dtype.is_object() != impl.dtype.is_object():
             raise oefmt(space.w_ValueError, 'expect trouble in ndarray.view,'
                 ' one of target dtype or dtype is object dtype')
+        w_type = w_type or space.type(self)
         v = impl.get_view(space, base, dtype, new_shape, strides, backstrides)
         w_ret = wrap_impl(space, w_type, self, v)
         return w_ret
diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py
--- a/pypy/module/micronumpy/nditer.py
+++ b/pypy/module/micronumpy/nditer.py
@@ -218,8 +218,8 @@
     backward = is_backward(imp, order)
     if arr.is_scalar():
         return ConcreteIter(imp, 1, [], [], [], op_flags, base)
-    if (imp.strides[0] < imp.strides[-1] and not backward) or \
-       (imp.strides[0] > imp.strides[-1] and backward):
+    if (abs(imp.strides[0]) < abs(imp.strides[-1]) and not backward) or \
+       (abs(imp.strides[0]) > abs(imp.strides[-1]) and backward):
         # flip the strides. Is this always true for multidimension?
         strides = imp.strides[:]
         backstrides = imp.backstrides[:]
diff --git a/pypy/module/micronumpy/strides.py 
b/pypy/module/micronumpy/strides.py
--- a/pypy/module/micronumpy/strides.py
+++ b/pypy/module/micronumpy/strides.py
@@ -185,8 +185,14 @@
 
 
 def _find_shape_and_elems(space, w_iterable, is_rec_type):
+    from pypy.objspace.std.bufferobject import W_Buffer
     shape = [space.len_w(w_iterable)]
-    batch = space.listview(w_iterable)
+    if space.isinstance_w(w_iterable, space.w_buffer):
+        batch = [space.wrap(0)] * shape[0]
+        for i in range(shape[0]):
+            batch[i] = space.ord(space.getitem(w_iterable, space.wrap(i)))
+    else:
+        batch = space.listview(w_iterable)
     while True:
         if not batch:
             return shape[:], []
diff --git a/pypy/module/micronumpy/support.py 
b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -7,8 +7,9 @@
 def issequence_w(space, w_obj):
     from pypy.module.micronumpy.base import W_NDimArray
     return (space.isinstance_w(w_obj, space.w_tuple) or
-            space.isinstance_w(w_obj, space.w_list) or
-            isinstance(w_obj, W_NDimArray))
+           space.isinstance_w(w_obj, space.w_list) or
+           space.isinstance_w(w_obj, space.w_buffer) or
+           isinstance(w_obj, W_NDimArray))
 
 
 def index_w(space, w_obj):
diff --git a/pypy/module/micronumpy/test/test_ndarray.py 
b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -1834,6 +1834,13 @@
         v = s.view(y.__class__)
         assert v.strides == (4, 24)
 
+        x = empty([12, 8, 8], 'float64')
+        y = x[::-4, :, :]
+        assert y.base is x
+        assert y.strides == (-2048, 64, 8)
+        y[:] = 1000
+        assert x[-1, 0, 0] == 1000 
+
         a = empty([3, 2, 1], dtype='float64')
         b = a.view(dtype('uint32'))
         assert b.strides == (16, 8, 4)
@@ -3951,6 +3958,11 @@
         assert np.greater(a, a) is NotImplemented
         assert np.less_equal(a, a) is NotImplemented
 
+    def test_create_from_memory(self):
+        import numpy as np
+        dat = np.array(__builtins__.buffer('1.0'), dtype=np.float64)
+        assert (dat == [49.0, 46.0, 48.0]).all()
+
 
 class AppTestPyPy(BaseNumpyAppTest):
     def setup_class(cls):
diff --git a/pypy/module/micronumpy/test/test_subtype.py 
b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -82,6 +82,7 @@
         assert isinstance(b, matrix)
         assert b.__array_priority__ == 0.0
         assert (b == a).all()
+        assert isinstance(b.view(), matrix) 
         a = array(5)[()]
         for s in [matrix, ndarray]:
             b = a.view(s)
@@ -125,7 +126,7 @@
         import numpy as np
         class InfoArray(np.ndarray):
             def __new__(subtype, shape, dtype=float, buffer=None, offset=0,
-                          strides=None, order='C', info=None):
+                          strides=None, order='C', info=1):
                 obj = np.ndarray.__new__(subtype, shape, dtype, buffer,
                          offset, strides, order)
                 obj.info = info
@@ -133,25 +134,31 @@
 
             def __array_finalize__(self, obj):
                 if obj is None:
-                    print 'finalize with None'
                     return
                 # printing the object itself will crash the test
-                print 'finalize with something',type(obj)
-                self.info = getattr(obj, 'info', None)
+                self.info = 1 + getattr(obj, 'info', 0)
+                if hasattr(obj, 'info'):
+                    obj.info += 100
+
         obj = InfoArray(shape=(3,))
         assert isinstance(obj, InfoArray)
-        assert obj.info is None
-        obj = InfoArray(shape=(3,), info='information')
-        assert obj.info == 'information'
+        assert obj.info == 1
+        obj = InfoArray(shape=(3,), info=10)
+        assert obj.info == 10
         v = obj[1:]
         assert isinstance(v, InfoArray)
         assert v.base is obj
-        assert v.info == 'information'
+        assert v.info == 11
         arr = np.arange(10)
         cast_arr = arr.view(InfoArray)
         assert isinstance(cast_arr, InfoArray)
         assert cast_arr.base is arr
-        assert cast_arr.info is None
+        assert cast_arr.info == 1
+        # Test that setshape calls __array_finalize__
+        cast_arr.shape = (5,2)
+        z = cast_arr.info
+        assert z == 101
+
 
     def test_sub_where(self):
         from numpy import where, ones, zeros, array
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py 
b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -181,12 +181,17 @@
                             dtypes=[dtype(int), dtype(int)],
                             stack_inputs=True,
                           )
-        ai = arange(18, dtype=int).reshape(2,3,3)
+        ai = arange(12*3*3, dtype='int32').reshape(12,3,3)
         exc = raises(ValueError, ufunc, ai[:,:,0])
         assert "perand 0 has a mismatch in its core dimension 1" in 
exc.value.message
         ai3 = ufunc(ai[0,:,:])
         ai2 = ufunc(ai)
         assert (ai2 == ai * 2).all()
+        # view
+        aiV = ai[::-2, :, :]
+        assert aiV.strides == (-72, 12, 4)
+        ai2 = ufunc(aiV)
+        assert (ai2 == aiV * 2).all()
 
     def test_frompyfunc_needs_nditer(self):
         def summer(in0):
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py 
b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -450,6 +450,9 @@
             if self.try_match(op, until_op):
                 # it matched! The '...' operator ends here
                 return op
+            self._assert(op != '--end--',
+                         'nothing in the end of the loop matches %r' %
+                          (until_op,))
 
     def match_any_order(self, iter_exp_ops, iter_ops, ignore_ops):
         exp_ops = []
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py 
b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -207,6 +207,88 @@
             guard_no_exception(descr=...)
         """, ignore_ops=['guard_not_invalidated'])
 
+    def test__cffi_call_c_int(self):
+        def main():
+            import os
+            try:
+                import _cffi_backend
+            except ImportError:
+                sys.stderr.write('SKIP: cannot import _cffi_backend\n')
+                return 0
+
+            libc = _cffi_backend.load_library(None)
+            BInt = _cffi_backend.new_primitive_type("int")
+            BClose = _cffi_backend.new_function_type([BInt], BInt)
+            _dup = libc.load_function(BClose, 'dup')
+            i = 0
+            fd0, fd1 = os.pipe()
+            while i < 300:
+                tmp = _dup(fd0)   # ID: cfficall
+                os.close(tmp)
+                i += 1
+            os.close(fd0)
+            os.close(fd1)
+            BLong = _cffi_backend.new_primitive_type("long")
+            return 42
+        #
+        log = self.run(main, [])
+        assert log.result == 42
+        loop, = log.loops_by_filename(self.filepath)
+        if sys.maxint > 2**32:
+            extra = "i98 = int_signext(i97, 4)"
+        else:
+            extra = ""
+        assert loop.match_by_id('cfficall', """
+            p96 = force_token()
+            setfield_gc(p0, p96, descr=<FieldP 
pypy.interpreter.pyframe.PyFrame.vable_token .>)
+            i97 = call_release_gil(91, i59, i50, descr=<Calli 4 i EF=7 OS=62>)
+            guard_not_forced(descr=...)
+            guard_no_exception(descr=...)
+            %s
+        """ % extra, ignore_ops=['guard_not_invalidated'])
+
+    def test__cffi_call_size_t(self):
+        def main():
+            import os
+            try:
+                import _cffi_backend
+            except ImportError:
+                sys.stderr.write('SKIP: cannot import _cffi_backend\n')
+                return 0
+
+            libc = _cffi_backend.load_library(None)
+            BInt = _cffi_backend.new_primitive_type("int")
+            BSizeT = _cffi_backend.new_primitive_type("size_t")
+            BChar = _cffi_backend.new_primitive_type("char")
+            BCharP = _cffi_backend.new_pointer_type(BChar)
+            BWrite = _cffi_backend.new_function_type([BInt, BCharP, BSizeT],
+                                                     BSizeT)  # not signed 
here!
+            _write = libc.load_function(BWrite, 'write')
+            i = 0
+            fd0, fd1 = os.pipe()
+            buffer = _cffi_backend.newp(BCharP, 'A')
+            while i < 300:
+                tmp = _write(fd1, buffer, 1)   # ID: cfficall
+                assert tmp == 1
+                assert os.read(fd0, 2) == 'A'
+                i += 1
+            os.close(fd0)
+            os.close(fd1)
+            return 42
+        #
+        log = self.run(main, [])
+        assert log.result == 42
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match_by_id('cfficall', """
+            p96 = force_token()
+            setfield_gc(p0, p96, descr=<FieldP 
pypy.interpreter.pyframe.PyFrame.vable_token .>)
+            i97 = call_release_gil(91, i59, i10, i12, 1, descr=<Calli . iii 
EF=7 OS=62>)
+            guard_not_forced(descr=...)
+            guard_no_exception(descr=...)
+            p98 = call(ConstClass(fromrarith_int__r_uint), i97, descr=<Callr . 
i EF=4>)
+            guard_no_exception(descr=...)
+        """, ignore_ops=['guard_not_invalidated'])
+
     def test_cffi_call_guard_not_forced_fails(self):
         # this is the test_pypy_c equivalent of
         # rpython/jit/metainterp/test/test_fficall::test_guard_not_forced_fails
diff --git a/rpython/jit/codewriter/jtransform.py 
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1953,11 +1953,6 @@
             assert False, 'unsupported oopspec: %s' % oopspec_name
         return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)
 
-    def rewrite_op_jit_ffi_save_result(self, op):
-        kind = op.args[0].value
-        assert kind in ('int', 'float', 'longlong', 'singlefloat')
-        return SpaceOperation('libffi_save_result_%s' % kind, op.args[1:], 
None)
-
     def rewrite_op_jit_force_virtual(self, op):
         op0 = SpaceOperation('-live-', [], None)
         op1 = self._do_builtin_call(op)
diff --git a/rpython/jit/metainterp/blackhole.py 
b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -1431,41 +1431,6 @@
     def bhimpl_copyunicodecontent(cpu, src, dst, srcstart, dststart, length):
         cpu.bh_copyunicodecontent(src, dst, srcstart, dststart, length)
 
-    def _libffi_save_result(self, cif_description, exchange_buffer, result):
-        ARRAY = lltype.Ptr(rffi.CArray(lltype.typeOf(result)))
-        cast_int_to_ptr = self.cpu.cast_int_to_ptr
-        cif_description = cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P)
-        exchange_buffer = cast_int_to_ptr(exchange_buffer, rffi.CCHARP)
-        #
-        data_out = rffi.ptradd(exchange_buffer, 
cif_description.exchange_result)
-        rffi.cast(ARRAY, data_out)[0] = result
-    _libffi_save_result._annspecialcase_ = 'specialize:argtype(3)'
-
-    @arguments("self", "i", "i", "i")
-    def bhimpl_libffi_save_result_int(self, cif_description,
-                                      exchange_buffer, result):
-        self._libffi_save_result(cif_description, exchange_buffer, result)
-
-    @arguments("self", "i", "i", "f")
-    def bhimpl_libffi_save_result_float(self, cif_description,
-                                        exchange_buffer, result):
-        result = longlong.getrealfloat(result)
-        self._libffi_save_result(cif_description, exchange_buffer, result)
-
-    @arguments("self", "i", "i", "f")
-    def bhimpl_libffi_save_result_longlong(self, cif_description,
-                                           exchange_buffer, result):
-        # 32-bit only: 'result' is here a LongLong
-        assert longlong.is_longlong(lltype.typeOf(result))
-        self._libffi_save_result(cif_description, exchange_buffer, result)
-
-    @arguments("self", "i", "i", "i")
-    def bhimpl_libffi_save_result_singlefloat(self, cif_description,
-                                              exchange_buffer, result):
-        result = longlong.int2singlefloat(result)
-        self._libffi_save_result(cif_description, exchange_buffer, result)
-
-
     # ----------
     # helpers to resume running in blackhole mode when a guard failed
 
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1331,34 +1331,6 @@
             metainterp.history.record(rop.VIRTUAL_REF_FINISH,
                                       [vrefbox, nullbox], None)
 
-    @arguments("box", "box", "box")
-    def _opimpl_libffi_save_result(self, box_cif_description,
-                                   box_exchange_buffer, box_result):
-        from rpython.rtyper.lltypesystem import llmemory
-        from rpython.rlib.jit_libffi import CIF_DESCRIPTION_P
-        from rpython.jit.backend.llsupport.ffisupport import get_arg_descr
-
-        cif_description = box_cif_description.getint()
-        cif_description = llmemory.cast_int_to_adr(cif_description)
-        cif_description = llmemory.cast_adr_to_ptr(cif_description,
-                                                   CIF_DESCRIPTION_P)
-
-        kind, descr, itemsize = get_arg_descr(self.metainterp.cpu, 
cif_description.rtype)
-
-        if kind != 'v':
-            ofs = cif_description.exchange_result
-            assert ofs % itemsize == 0     # alignment check (result)
-            self.metainterp.history.record(rop.SETARRAYITEM_RAW,
-                                           [box_exchange_buffer,
-                                            ConstInt(ofs // itemsize),
-                                            box_result],
-                                           None, descr)
-
-    opimpl_libffi_save_result_int         = _opimpl_libffi_save_result
-    opimpl_libffi_save_result_float       = _opimpl_libffi_save_result
-    opimpl_libffi_save_result_longlong    = _opimpl_libffi_save_result
-    opimpl_libffi_save_result_singlefloat = _opimpl_libffi_save_result
-
     # ------------------------------
 
     def setup_call(self, argboxes):
@@ -2910,7 +2882,7 @@
         self.history.operations.extend(extra_guards)
         #
         # note that the result is written back to the exchange_buffer by the
-        # special op libffi_save_result_{int,float}
+        # following operation, which should be a raw_store
 
     def direct_call_release_gil(self):
         op = self.history.operations.pop()
diff --git a/rpython/jit/metainterp/test/test_fficall.py 
b/rpython/jit/metainterp/test/test_fficall.py
--- a/rpython/jit/metainterp/test/test_fficall.py
+++ b/rpython/jit/metainterp/test/test_fficall.py
@@ -9,7 +9,7 @@
 from rpython.rlib import jit
 from rpython.rlib import jit_libffi
 from rpython.rlib.jit_libffi import (types, CIF_DESCRIPTION, FFI_TYPE_PP,
-                                     jit_ffi_call, jit_ffi_save_result)
+                                     jit_ffi_call)
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib.rarithmetic import intmask, r_longlong, r_singlefloat
 from rpython.rlib.longlong2float import float2longlong
@@ -48,13 +48,20 @@
     def _run(self, atypes, rtype, avalues, rvalue,
              expected_call_release_gil=1,
              supports_floats=True,
-             supports_longlong=True,
-             supports_singlefloats=True):
+             supports_longlong=False,
+             supports_singlefloats=False):
 
         cif_description = get_description(atypes, rtype)
 
+        expected_args = []
+        for avalue in avalues:
+            if lltype.typeOf(avalue) == rffi.ULONG:
+                avalue = intmask(avalue)
+            expected_args.append(avalue)
+        expected_args = tuple(expected_args)
+
         def verify(*args):
-            assert args == tuple(avalues)
+            assert args == expected_args
             return rvalue
         FUNC = lltype.FuncType([lltype.typeOf(avalue) for avalue in avalues],
                                lltype.typeOf(rvalue))
@@ -76,6 +83,10 @@
                 if lltype.typeOf(avalue) is lltype.SingleFloat:
                     got = float(got)
                     avalue = float(avalue)
+                elif (lltype.typeOf(avalue) is rffi.SIGNEDCHAR or
+                      lltype.typeOf(avalue) is rffi.UCHAR):
+                    got = intmask(got)
+                    avalue = intmask(avalue)
                 assert got == avalue
                 ofs += 16
             if rvalue is not None:
@@ -115,6 +126,9 @@
                 return res == 654321
             if isinstance(rvalue, r_singlefloat):
                 rvalue = float(rvalue)
+            if lltype.typeOf(rvalue) is rffi.ULONG:
+                res = intmask(res)
+                rvalue = intmask(rvalue)
             return res == rvalue
 
         with FakeFFI(fake_call_impl_any):
@@ -156,20 +170,24 @@
                       -42434445)
 
     def test_simple_call_float(self, **kwds):
+        kwds.setdefault('supports_floats', True)
         self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2, **kwds)
 
     def test_simple_call_longlong(self, **kwds):
+        kwds.setdefault('supports_longlong', True)
         maxint32 = 2147483647
         a = r_longlong(maxint32) + 1
         b = r_longlong(maxint32) + 2
         self._run([types.slonglong] * 2, types.slonglong, [a, b], a, **kwds)
 
-    def test_simple_call_singlefloat_args(self):
+    def test_simple_call_singlefloat_args(self, **kwds):
+        kwds.setdefault('supports_singlefloats', True)
         self._run([types.float] * 2, types.double,
                   [r_singlefloat(10.5), r_singlefloat(31.5)],
                   -4.5)
 
     def test_simple_call_singlefloat(self, **kwds):
+        kwds.setdefault('supports_singlefloats', True)
         self._run([types.float] * 2, types.float,
                   [r_singlefloat(10.5), r_singlefloat(31.5)],
                   r_singlefloat(-4.5), **kwds)
@@ -183,9 +201,20 @@
         self._run([types.signed] * 2, types.void, [456, 789], None)
 
     def test_returns_signedchar(self):
-        self._run([types.signed], types.sint8, [456],
+        self._run([types.sint8], types.sint8,
+                  [rffi.cast(rffi.SIGNEDCHAR, -28)],
                   rffi.cast(rffi.SIGNEDCHAR, -42))
 
+    def test_handle_unsigned(self):
+        self._run([types.ulong], types.ulong,
+                  [rffi.cast(rffi.ULONG, sys.maxint + 91348)],
+                  rffi.cast(rffi.ULONG, sys.maxint + 4242))
+
+    def test_handle_unsignedchar(self):
+        self._run([types.uint8], types.uint8,
+                  [rffi.cast(rffi.UCHAR, 191)],
+                  rffi.cast(rffi.UCHAR, 180))
+
     def _add_libffi_types_to_ll2types_maybe(self):
         # not necessary on the llgraph backend, but needed for x86.
         # see rpython/jit/backend/x86/test/test_fficall.py
@@ -255,7 +284,7 @@
                 # when n==50, fn() will force the frame, so guard_not_forced
                 # fails and we enter blackholing: this test makes sure that
                 # the result of call_release_gil is kept alive before the
-                # libffi_save_result, and that the corresponding box is passed
+                # raw_store, and that the corresponding box is passed
                 # in the fail_args. Before the fix, the result of
                 # call_release_gil was simply lost and when guard_not_forced
                 # failed, and the value of "res" was unpredictable.
@@ -291,7 +320,6 @@
         cd.atypes = atypes
         cd.exchange_size = 64    # 64 bytes of exchange data
         cd.exchange_result = 24
-        cd.exchange_result_libffi = 24
         cd.exchange_args[0] = 16
 
         def f():
@@ -324,8 +352,3 @@
     def test_simple_call_singlefloat_unsupported(self):
         self.test_simple_call_singlefloat(supports_singlefloats=False,
                                           expected_call_release_gil=0)
-
-    def test_simple_call_float_even_if_other_unsupported(self):
-        self.test_simple_call_float(supports_longlong=False,
-                                    supports_singlefloats=False)
-        # this is the default:      expected_call_release_gil=1
diff --git a/rpython/rlib/jit_libffi.py b/rpython/rlib/jit_libffi.py
--- a/rpython/rlib/jit_libffi.py
+++ b/rpython/rlib/jit_libffi.py
@@ -1,10 +1,9 @@
-
-from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.rtyper.extregistry import ExtRegistryEntry
+import sys
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rlib import clibffi, jit
 from rpython.rlib.rarithmetic import r_longlong, r_singlefloat
-from rpython.rlib.nonconst import NonConstant
-
+from rpython.rlib.unroll import unrolling_iterable
 
 FFI_CIF = clibffi.FFI_CIFP.TO
 FFI_TYPE = clibffi.FFI_TYPE_P.TO
@@ -13,6 +12,8 @@
 FFI_ABI = clibffi.FFI_ABI
 FFI_TYPE_STRUCT = clibffi.FFI_TYPE_STRUCT
 SIZE_OF_FFI_ARG = rffi.sizeof(clibffi.ffi_arg)
+SIZE_OF_SIGNED = rffi.sizeof(lltype.Signed)
+FFI_ARG_P = rffi.CArrayPtr(clibffi.ffi_arg)
 
 # Usage: for each C function, make one CIF_DESCRIPTION block of raw
 # memory.  Initialize it by filling all its fields apart from 'cif'.
@@ -33,11 +34,12 @@
 #  - 'exchange_result': the offset in that buffer for the result of the call.
 #    (this and the other offsets must be at least NARGS * sizeof(void*).)
 #
-#  - 'exchange_result_libffi': the actual offset passed to ffi_call().
-#    Differs on big-endian machines if the result is an integer type smaller
-#    than SIZE_OF_FFI_ARG (blame libffi).
+#  - 'exchange_args[nargs]': the offset in that buffer for each argument.
 #
-#  - 'exchange_args[nargs]': the offset in that buffer for each argument.
+# Each argument and the result should have enough room for at least
+# SIZE_OF_FFI_ARG bytes, even if they may be smaller.  (Unlike ffi_call,
+# we don't have any special rule about results that are integers smaller
+# than SIZE_OF_FFI_ARG).
 
 CIF_DESCRIPTION = lltype.Struct(
     'CIF_DESCRIPTION',
@@ -48,7 +50,6 @@
     ('atypes', FFI_TYPE_PP),   #
     ('exchange_size', lltype.Signed),
     ('exchange_result', lltype.Signed),
-    ('exchange_result_libffi', lltype.Signed),
     ('exchange_args', lltype.Array(lltype.Signed,
                           hints={'nolength': True, 'immutable': True})),
     hints={'immutable': True})
@@ -93,12 +94,16 @@
 ##
 ## The result is that now the jitcode looks like this:
 ##
-##     %i0 = libffi_call_int(...)
+##     %i0 = direct_call(libffi_call_int, ...)
 ##     -live-
-##     libffi_save_result_int(..., %i0)
+##     raw_store(exchange_result, %i0)
 ##
 ## the "-live-" is the key, because it make sure that the value is not lost if
 ## guard_not_forced fails.
+##
+## The value of %i0 is stored back in the exchange_buffer at the offset
+## exchange_result, which is usually where functions like jit_ffi_call_impl_int
+## have just read it from when called *in interpreter mode* only.
 
 
 def jit_ffi_call(cif_description, func_addr, exchange_buffer):
@@ -108,8 +113,10 @@
     reskind = types.getkind(cif_description.rtype)
     if reskind == 'v':
         jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer)
-    elif reskind == 'i' or reskind == 'u':
-        _do_ffi_call_int(cif_description, func_addr, exchange_buffer)
+    elif reskind == 'i':
+        _do_ffi_call_sint(cif_description, func_addr, exchange_buffer)
+    elif reskind == 'u':
+        _do_ffi_call_uint(cif_description, func_addr, exchange_buffer)
     elif reskind == 'f':
         _do_ffi_call_float(cif_description, func_addr, exchange_buffer)
     elif reskind == 'L': # L is for longlongs, on 32bit
@@ -126,54 +133,97 @@
         jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
 
 
-def _do_ffi_call_int(cif_description, func_addr, exchange_buffer):
+_short_sint_types = unrolling_iterable([rffi.SIGNEDCHAR, rffi.SHORT, rffi.INT])
+_short_uint_types = unrolling_iterable([rffi.UCHAR, rffi.USHORT, rffi.UINT])
+
+def _do_ffi_call_sint(cif_description, func_addr, exchange_buffer):
     result = jit_ffi_call_impl_int(cif_description, func_addr,
                                    exchange_buffer)
-    jit_ffi_save_result('int', cif_description, exchange_buffer, result)
+    size = types.getsize(cif_description.rtype)
+    for TP in _short_sint_types:     # short **signed** types
+        if size == rffi.sizeof(TP):
+            llop.raw_store(lltype.Void,
+                           llmemory.cast_ptr_to_adr(exchange_buffer),
+                           cif_description.exchange_result,
+                           rffi.cast(TP, result))
+            break
+    else:
+        # default case: expect a full signed number
+        llop.raw_store(lltype.Void,
+                       llmemory.cast_ptr_to_adr(exchange_buffer),
+                       cif_description.exchange_result,
+                       result)
+
+def _do_ffi_call_uint(cif_description, func_addr, exchange_buffer):
+    result = jit_ffi_call_impl_int(cif_description, func_addr,
+                                   exchange_buffer)
+    size = types.getsize(cif_description.rtype)
+    for TP in _short_uint_types:     # short **unsigned** types
+        if size == rffi.sizeof(TP):
+            llop.raw_store(lltype.Void,
+                           llmemory.cast_ptr_to_adr(exchange_buffer),
+                           cif_description.exchange_result,
+                           rffi.cast(TP, result))
+            break
+    else:
+        # default case: expect a full unsigned number
+        llop.raw_store(lltype.Void,
+                       llmemory.cast_ptr_to_adr(exchange_buffer),
+                       cif_description.exchange_result,
+                       rffi.cast(lltype.Unsigned, result))
 
 def _do_ffi_call_float(cif_description, func_addr, exchange_buffer):
     # a separate function in case the backend doesn't support floats
     result = jit_ffi_call_impl_float(cif_description, func_addr,
                                      exchange_buffer)
-    jit_ffi_save_result('float', cif_description, exchange_buffer, result)
+    llop.raw_store(lltype.Void,
+                   llmemory.cast_ptr_to_adr(exchange_buffer),
+                   cif_description.exchange_result,
+                   result)
 
 def _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer):
     # a separate function in case the backend doesn't support longlongs
     result = jit_ffi_call_impl_longlong(cif_description, func_addr,
                                         exchange_buffer)
-    jit_ffi_save_result('longlong', cif_description, exchange_buffer, result)
+    llop.raw_store(lltype.Void,
+                   llmemory.cast_ptr_to_adr(exchange_buffer),
+                   cif_description.exchange_result,
+                   result)
 
 def _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer):
     # a separate function in case the backend doesn't support singlefloats
     result = jit_ffi_call_impl_singlefloat(cif_description, func_addr,
                                            exchange_buffer)
-    jit_ffi_save_result('singlefloat', cif_description, exchange_buffer,result)
+    llop.raw_store(lltype.Void,
+                   llmemory.cast_ptr_to_adr(exchange_buffer),
+                   cif_description.exchange_result,
+                   result)
 
 
-# we must return a NonConstant else we get the constant -1 as the result of
-# the flowgraph, and the codewriter does not produce a box for the
-# result. Note that when not-jitted, the result is unused, but when jitted the
-# box of the result contains the actual value returned by the C function.
-
 @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
 def jit_ffi_call_impl_int(cif_description, func_addr, exchange_buffer):
     jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
-    return NonConstant(-1)
+    # read a complete 'ffi_arg' word
+    resultdata = rffi.ptradd(exchange_buffer, cif_description.exchange_result)
+    return rffi.cast(lltype.Signed, rffi.cast(FFI_ARG_P, resultdata)[0])
 
 @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
 def jit_ffi_call_impl_float(cif_description, func_addr, exchange_buffer):
     jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
-    return NonConstant(-1.0)
+    resultdata = rffi.ptradd(exchange_buffer, cif_description.exchange_result)
+    return rffi.cast(rffi.DOUBLEP, resultdata)[0]
 
 @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
 def jit_ffi_call_impl_longlong(cif_description, func_addr, exchange_buffer):
     jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
-    return r_longlong(-1)
+    resultdata = rffi.ptradd(exchange_buffer, cif_description.exchange_result)
+    return rffi.cast(rffi.LONGLONGP, resultdata)[0]
 
 @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
 def jit_ffi_call_impl_singlefloat(cif_description, func_addr, exchange_buffer):
     jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
-    return r_singlefloat(-1.0)
+    resultdata = rffi.ptradd(exchange_buffer, cif_description.exchange_result)
+    return rffi.cast(rffi.FLOATP, resultdata)[0]
 
 @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
 def jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer):
@@ -191,36 +241,12 @@
         data = rffi.ptradd(exchange_buffer, cif_description.exchange_args[i])
         buffer_array[i] = data
     resultdata = rffi.ptradd(exchange_buffer,
-                             cif_description.exchange_result_libffi)
+                             cif_description.exchange_result)
     clibffi.c_ffi_call(cif_description.cif, func_addr,
                        rffi.cast(rffi.VOIDP, resultdata),
                        buffer_array)
-    return -1
 
 
-
-def jit_ffi_save_result(kind, cif_description, exchange_buffer, result):
-    """
-    This is a no-op during normal execution, but actually fills the buffer
-    when jitted
-    """
-    pass
-
-class Entry(ExtRegistryEntry):
-    _about_ = jit_ffi_save_result
-
-    def compute_result_annotation(self, kind_s, *args_s):
-        from rpython.annotator import model as annmodel
-        assert isinstance(kind_s, annmodel.SomeString)
-        assert kind_s.const in ('int', 'float', 'longlong', 'singlefloat')
-
-    def specialize_call(self, hop):
-        hop.exception_cannot_occur()
-        vlist = hop.inputargs(lltype.Void, *hop.args_r[1:])
-        return hop.genop('jit_ffi_save_result', vlist,
-                         resulttype=lltype.Void)
-    
-
 # ____________________________________________________________
 
 class types(object):
@@ -282,6 +308,11 @@
 
     @staticmethod
     @jit.elidable
+    def getsize(ffi_type):
+        return rffi.getintfield(ffi_type, 'c_size')
+
+    @staticmethod
+    @jit.elidable
     def is_struct(ffi_type):
         return rffi.getintfield(ffi_type, 'c_type') == FFI_TYPE_STRUCT
 
diff --git a/rpython/rlib/rawstorage.py b/rpython/rlib/rawstorage.py
--- a/rpython/rlib/rawstorage.py
+++ b/rpython/rlib/rawstorage.py
@@ -19,9 +19,9 @@
 def raw_storage_getitem(TP, storage, index):
     "NOT_RPYTHON"
     _check_alignment(TP, index)
-    return raw_storage_getitem_unchecked(TP, storage, index)
+    return _raw_storage_getitem_unchecked(TP, storage, index)
 
-def raw_storage_getitem_unchecked(TP, storage, index):
+def _raw_storage_getitem_unchecked(TP, storage, index):
     "NOT_RPYTHON"
     return rffi.cast(rffi.CArrayPtr(TP), rffi.ptradd(storage, index))[0]
 
@@ -29,9 +29,9 @@
     "NOT_RPYTHON"
     TP = lltype.typeOf(item)
     _check_alignment(TP, index)
-    raw_storage_setitem_unchecked(storage, index, item)
+    _raw_storage_setitem_unchecked(storage, index, item)
 
-def raw_storage_setitem_unchecked(storage, index, item):
+def _raw_storage_setitem_unchecked(storage, index, item):
     "NOT_RPYTHON"
     TP = lltype.typeOf(item)
     rffi.cast(rffi.CArrayPtr(TP), rffi.ptradd(storage, index))[0] = item
@@ -80,13 +80,13 @@
         if we_are_translated():
             return raw_storage_getitem(TP, storage, index)
         else:
-            return raw_storage_getitem_unchecked(TP, storage, index)
+            return _raw_storage_getitem_unchecked(TP, storage, index)
     mask = _get_alignment_mask(TP)
     if (index & mask) == 0:
         if we_are_translated():
             return raw_storage_getitem(TP, storage, index)
         else:
-            return raw_storage_getitem_unchecked(TP, storage, index)
+            return _raw_storage_getitem_unchecked(TP, storage, index)
     ptr = rffi.ptradd(storage, index)
     with lltype.scoped_alloc(rffi.CArray(TP), 1) as s_array:
         rffi.c_memcpy(rffi.cast(rffi.VOIDP, s_array),
@@ -100,7 +100,7 @@
         if we_are_translated():
             raw_storage_setitem(storage, index, item)
         else:
-            raw_storage_setitem_unchecked(storage, index, item)
+            _raw_storage_setitem_unchecked(storage, index, item)
         return
     TP = lltype.typeOf(item)
     mask = _get_alignment_mask(TP)
@@ -108,7 +108,7 @@
         if we_are_translated():
             raw_storage_setitem(storage, index, item)
         else:
-            raw_storage_setitem_unchecked(storage, index, item)
+            _raw_storage_setitem_unchecked(storage, index, item)
         return
     ptr = rffi.ptradd(storage, index)
     with lltype.scoped_alloc(rffi.CArray(TP), 1) as s_array:
diff --git a/rpython/rlib/test/test_jit_libffi.py 
b/rpython/rlib/test/test_jit_libffi.py
--- a/rpython/rlib/test/test_jit_libffi.py
+++ b/rpython/rlib/test/test_jit_libffi.py
@@ -24,7 +24,6 @@
     cd.atypes = atypes
     cd.exchange_size = 64    # 64 bytes of exchange data
     cd.exchange_result = 24
-    cd.exchange_result_libffi = 24
     cd.exchange_args[0] = 16
     #
     jit_ffi_prep_cif(cd)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to