Author: Amaury Forgeot d'Arc <amaur...@gmail.com>
Branch: more-rposix
Changeset: r77366:34b437c9bc0c
Date: 2015-05-17 20:51 +0200
http://bitbucket.org/pypy/pypy/changeset/34b437c9bc0c/

Log:    hg merge default

diff too long, truncating to 2000 out of 6416 lines

diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py
--- a/lib-python/2.7/socket.py
+++ b/lib-python/2.7/socket.py
@@ -145,6 +145,34 @@
             name = hostname
     return name
 
+class RefCountingWarning(UserWarning):
+    pass
+
+def _do_reuse_or_drop(socket, methname):
+    try:
+        method = getattr(socket, methname)
+    except (AttributeError, TypeError):
+        warnings.warn("""'%s' object has no _reuse/_drop methods
+{{
+    You make use (or a library you are using makes use) of the internal
+    classes '_socketobject' and '_fileobject' in socket.py, initializing
+    them with custom objects.  On PyPy, these custom objects need two
+    extra methods, _reuse() and _drop(), that maintain an explicit
+    reference counter.  When _drop() has been called as many times as
+    _reuse(), then the object should be freed.
+
+    Without these methods, you get the warning here.  This is to
+    prevent the following situation: if your (or the library's) code
+    relies on reference counting for prompt closing, then on PyPy, the
+    __del__ method will be called later than on CPython.  You can
+    easily end up in a situation where you open and close a lot of
+    (high-level) '_socketobject' or '_fileobject', but the (low-level)
+    custom objects will accumulate before their __del__ are called.
+    You quickly risk running out of file descriptors, for example.
+}}""" % (socket.__class__.__name__,), RefCountingWarning, stacklevel=3)
+    else:
+        method()
+
 
 _socketmethods = (
     'bind', 'connect', 'connect_ex', 'fileno', 'listen',
@@ -182,19 +210,7 @@
         if _sock is None:
             _sock = _realsocket(family, type, proto)
         else:
-            # PyPy note about refcounting: implemented with _reuse()/_drop()
-            # on the class '_socket.socket'.  Python 3 did it differently
-            # with a reference counter on this class 'socket._socketobject'
-            # instead, but it is a less compatible change.
-            
-            # Note that a few libraries (like eventlet) poke at the
-            # private implementation of socket.py, passing custom
-            # objects to _socketobject().  These libraries need the
-            # following fix for use on PyPy: the custom objects need
-            # methods _reuse() and _drop() that maintains an explicit
-            # reference counter, starting at 0.  When it drops back to
-            # zero, close() must be called.
-            _sock._reuse()
+            _do_reuse_or_drop(_sock, '_reuse')
 
         self._sock = _sock
 
@@ -228,13 +244,13 @@
     def close(self):
         s = self._sock
         self._sock = _closedsocket()
-        s._drop()
+        _do_reuse_or_drop(s, '_drop')
     close.__doc__ = _realsocket.close.__doc__
 
     def accept(self):
         sock, addr = self._sock.accept()
         sockobj = _socketobject(_sock=sock)
-        sock._drop()    # already a copy in the _socketobject()
+        _do_reuse_or_drop(sock, '_drop') # already a copy in the 
_socketobject()
         return sockobj, addr
     accept.__doc__ = _realsocket.accept.__doc__
 
@@ -290,14 +306,7 @@
                  "_close"]
 
     def __init__(self, sock, mode='rb', bufsize=-1, close=False):
-        # Note that a few libraries (like eventlet) poke at the
-        # private implementation of socket.py, passing custom
-        # objects to _fileobject().  These libraries need the
-        # following fix for use on PyPy: the custom objects need
-        # methods _reuse() and _drop() that maintains an explicit
-        # reference counter, starting at 0.  When it drops back to
-        # zero, close() must be called.
-        sock._reuse()
+        _do_reuse_or_drop(sock, '_reuse')
         self._sock = sock
         self.mode = mode # Not actually used in this version
         if bufsize < 0:
@@ -338,7 +347,7 @@
                 if self._close:
                     s.close()
                 else:
-                    s._drop()
+                    _do_reuse_or_drop(s, '_drop')
 
     def __del__(self):
         try:
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -276,7 +276,11 @@
             if argtypes:
                 args = 
[argtype._CData_retval(argtype.from_address(arg)._buffer)
                         for argtype, arg in zip(argtypes, args)]
-            return to_call(*args)
+            try:
+                return to_call(*args)
+            except SystemExit, e:
+                handle_system_exit(e)
+                raise
         return f
 
     def __call__(self, *args, **kwargs):
@@ -305,7 +309,11 @@
             except (UnicodeError, TypeError, ValueError), e:
                 raise ArgumentError(str(e))
             try:
-                res = self.callable(*newargs)
+                try:
+                    res = self.callable(*newargs)
+                except SystemExit, e:
+                    handle_system_exit(e)
+                    raise
             except:
                 exc_info = sys.exc_info()
                 traceback.print_tb(exc_info[2], file=sys.stderr)
@@ -715,3 +723,22 @@
     make_fastpath_subclass.memo[CFuncPtr] = CFuncPtrFast
     return CFuncPtrFast
 make_fastpath_subclass.memo = {}
+
+
+def handle_system_exit(e):
+    # issue #1194: if we get SystemExit here, then exit the interpreter.
+    # Highly obscure imho but some people seem to depend on it.
+    if sys.flags.inspect:
+        return   # Don't exit if -i flag was given.
+    else:
+        code = e.code
+        if isinstance(code, int):
+            exitcode = code
+        else:
+            f = getattr(sys, 'stderr', None)
+            if f is None:
+                f = sys.__stderr__
+            print >> f, code
+            exitcode = 1
+
+        _rawffi.exit(exitcode)
diff --git a/lib_pypy/_functools.py b/lib_pypy/_functools.py
--- a/lib_pypy/_functools.py
+++ b/lib_pypy/_functools.py
@@ -8,16 +8,16 @@
     partial(func, *args, **keywords) - new function with partial application
     of the given arguments and keywords.
     """
-
-    def __init__(self, *args, **keywords):
-        if not args:
-            raise TypeError('__init__() takes at least 2 arguments (1 given)')
-        func, args = args[0], args[1:]
+    def __init__(*args, **keywords):
+        if len(args) < 2:
+            raise TypeError('__init__() takes at least 2 arguments (%d given)'
+                            % len(args))
+        self, func, args = args[0], args[1], args[2:]
         if not callable(func):
             raise TypeError("the first argument must be callable")
         self._func = func
         self._args = args
-        self._keywords = keywords or None
+        self._keywords = keywords
 
     def __delattr__(self, key):
         if key == '__dict__':
@@ -37,19 +37,22 @@
         return self._keywords
 
     def __call__(self, *fargs, **fkeywords):
-        if self.keywords is not None:
-            fkeywords = dict(self.keywords, **fkeywords)
-        return self.func(*(self.args + fargs), **fkeywords)
+        if self._keywords:
+            fkeywords = dict(self._keywords, **fkeywords)
+        return self._func(*(self._args + fargs), **fkeywords)
 
     def __reduce__(self):
         d = dict((k, v) for k, v in self.__dict__.iteritems() if k not in
                 ('_func', '_args', '_keywords'))
         if len(d) == 0:
             d = None
-        return (type(self), (self.func,),
-                (self.func, self.args, self.keywords, d))
+        return (type(self), (self._func,),
+                (self._func, self._args, self._keywords, d))
 
     def __setstate__(self, state):
-        self._func, self._args, self._keywords, d = state
+        func, args, keywords, d = state
         if d is not None:
             self.__dict__.update(d)
+        self._func = func
+        self._args = args
+        self._keywords = keywords
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/lib_pypy/gdbm.py b/lib_pypy/gdbm.py
--- a/lib_pypy/gdbm.py
+++ b/lib_pypy/gdbm.py
@@ -1,4 +1,6 @@
 import cffi, os, sys
+import thread
+_lock = thread.allocate_lock()
 
 ffi = cffi.FFI()
 ffi.cdef('''
@@ -40,6 +42,7 @@
 
 try:
     verify_code = '''
+    #include <stdlib.h>
     #include "gdbm.h"
 
     static datum pygdbm_fetch(GDBM_FILE gdbm_file, char *dptr, int dsize) {
@@ -86,101 +89,121 @@
     return {'dptr': ffi.new("char[]", key), 'dsize': len(key)}
 
 class gdbm(object):
-    ll_dbm = None
+    __ll_dbm = None
+
+    # All public methods need to acquire the lock; all private methods
+    # assume the lock is already held.  Thus public methods cannot call
+    # other public methods.
 
     def __init__(self, filename, iflags, mode):
-        res = lib.gdbm_open(filename, 0, iflags, mode, ffi.NULL)
-        self.size = -1
-        if not res:
-            self._raise_from_errno()
-        self.ll_dbm = res
+        with _lock:
+            res = lib.gdbm_open(filename, 0, iflags, mode, ffi.NULL)
+            self.__size = -1
+            if not res:
+                self.__raise_from_errno()
+            self.__ll_dbm = res
 
     def close(self):
-        if self.ll_dbm:
-            lib.gdbm_close(self.ll_dbm)
-            self.ll_dbm = None
+        with _lock:
+            if self.__ll_dbm:
+                lib.gdbm_close(self.__ll_dbm)
+                self.__ll_dbm = None
 
-    def _raise_from_errno(self):
+    def __raise_from_errno(self):
         if ffi.errno:
             raise error(ffi.errno, os.strerror(ffi.errno))
         raise error(lib.gdbm_errno, lib.gdbm_strerror(lib.gdbm_errno))
 
     def __len__(self):
-        if self.size < 0:
-            self.size = len(self.keys())
-        return self.size
+        with _lock:
+            if self.__size < 0:
+                self.__size = len(self.__keys())
+            return self.__size
 
     def __setitem__(self, key, value):
-        self._check_closed()
-        self._size = -1
-        r = lib.gdbm_store(self.ll_dbm, _fromstr(key), _fromstr(value),
-                           lib.GDBM_REPLACE)
-        if r < 0:
-            self._raise_from_errno()
+        with _lock:
+            self.__check_closed()
+            self.__size = -1
+            r = lib.gdbm_store(self.__ll_dbm, _fromstr(key), _fromstr(value),
+                               lib.GDBM_REPLACE)
+            if r < 0:
+                self.__raise_from_errno()
 
     def __delitem__(self, key):
-        self._check_closed()
-        res = lib.gdbm_delete(self.ll_dbm, _fromstr(key))
-        if res < 0:
-            raise KeyError(key)
+        with _lock:
+            self.__check_closed()
+            self.__size = -1
+            res = lib.gdbm_delete(self.__ll_dbm, _fromstr(key))
+            if res < 0:
+                raise KeyError(key)
 
     def __contains__(self, key):
-        self._check_closed()
-        key = _checkstr(key)
-        return lib.pygdbm_exists(self.ll_dbm, key, len(key))
+        with _lock:
+            self.__check_closed()
+            key = _checkstr(key)
+            return lib.pygdbm_exists(self.__ll_dbm, key, len(key))
     has_key = __contains__
 
     def __getitem__(self, key):
-        self._check_closed()
-        key = _checkstr(key)        
-        drec = lib.pygdbm_fetch(self.ll_dbm, key, len(key))
-        if not drec.dptr:
-            raise KeyError(key)
-        res = str(ffi.buffer(drec.dptr, drec.dsize))
-        lib.free(drec.dptr)
-        return res
+        with _lock:
+            self.__check_closed()
+            key = _checkstr(key)
+            drec = lib.pygdbm_fetch(self.__ll_dbm, key, len(key))
+            if not drec.dptr:
+                raise KeyError(key)
+            res = str(ffi.buffer(drec.dptr, drec.dsize))
+            lib.free(drec.dptr)
+            return res
 
-    def keys(self):
-        self._check_closed()
+    def __keys(self):
+        self.__check_closed()
         l = []
-        key = lib.gdbm_firstkey(self.ll_dbm)
+        key = lib.gdbm_firstkey(self.__ll_dbm)
         while key.dptr:
             l.append(str(ffi.buffer(key.dptr, key.dsize)))
-            nextkey = lib.gdbm_nextkey(self.ll_dbm, key)
+            nextkey = lib.gdbm_nextkey(self.__ll_dbm, key)
             lib.free(key.dptr)
             key = nextkey
         return l
 
+    def keys(self):
+        with _lock:
+            return self.__keys()
+
     def firstkey(self):
-        self._check_closed()
-        key = lib.gdbm_firstkey(self.ll_dbm)
-        if key.dptr:
-            res = str(ffi.buffer(key.dptr, key.dsize))
-            lib.free(key.dptr)
-            return res
+        with _lock:
+            self.__check_closed()
+            key = lib.gdbm_firstkey(self.__ll_dbm)
+            if key.dptr:
+                res = str(ffi.buffer(key.dptr, key.dsize))
+                lib.free(key.dptr)
+                return res
 
     def nextkey(self, key):
-        self._check_closed()
-        key = lib.gdbm_nextkey(self.ll_dbm, _fromstr(key))
-        if key.dptr:
-            res = str(ffi.buffer(key.dptr, key.dsize))
-            lib.free(key.dptr)
-            return res
+        with _lock:
+            self.__check_closed()
+            key = lib.gdbm_nextkey(self.__ll_dbm, _fromstr(key))
+            if key.dptr:
+                res = str(ffi.buffer(key.dptr, key.dsize))
+                lib.free(key.dptr)
+                return res
 
     def reorganize(self):
-        self._check_closed()
-        if lib.gdbm_reorganize(self.ll_dbm) < 0:
-            self._raise_from_errno()
+        with _lock:
+            self.__check_closed()
+            if lib.gdbm_reorganize(self.__ll_dbm) < 0:
+                self.__raise_from_errno()
 
-    def _check_closed(self):
-        if not self.ll_dbm:
+    def __check_closed(self):
+        if not self.__ll_dbm:
             raise error(0, "GDBM object has already been closed")
 
     __del__ = close
 
     def sync(self):
-        self._check_closed()
-        lib.gdbm_sync(self.ll_dbm)
+        with _lock:
+            self.__check_closed()
+            lib.gdbm_sync(self.__ll_dbm)
 
 def open(filename, flags='r', mode=0666):
     if flags[0] == 'r':
diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info
--- a/lib_pypy/greenlet.egg-info
+++ b/lib_pypy/greenlet.egg-info
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: greenlet
-Version: 0.4.5
+Version: 0.4.6
 Summary: Lightweight in-process concurrent programming
 Home-page: https://github.com/python-greenlet/greenlet
 Author: Ralf Schmitt (for CPython), PyPy team
diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py
--- a/lib_pypy/greenlet.py
+++ b/lib_pypy/greenlet.py
@@ -1,7 +1,7 @@
 import sys
 import _continuation
 
-__version__ = "0.4.5"
+__version__ = "0.4.6"
 
 # ____________________________________________________________
 # Exceptions
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,11 +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/goal/pypy.ico b/pypy/goal/pypy.ico
new file mode 100644
index 
0000000000000000000000000000000000000000..09d07dcc5a783200f440c68c0987926a80d6b667
GIT binary patch

[cut]

diff --git a/pypy/goal/targetpypystandalone.py 
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -238,6 +238,7 @@
 
         config.translation.suggest(check_str_without_nul=True)
         config.translation.suggest(shared=True)
+        config.translation.suggest(icon=os.path.join(this_dir, 'pypy.ico'))
         if config.translation.shared:
             if config.translation.output is not None:
                 raise Exception("Cannot use the --output option with PyPy "
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/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1091,7 +1091,7 @@
 
     def call_valuestack(self, w_func, nargs, frame):
         from pypy.interpreter.function import Function, Method, is_builtin_code
-        if frame.is_being_profiled and is_builtin_code(w_func):
+        if frame.get_is_being_profiled() and is_builtin_code(w_func):
             # XXX: this code is copied&pasted :-( from the slow path below
             # call_valuestack().
             args = frame.make_arguments(nargs)
diff --git a/pypy/interpreter/executioncontext.py 
b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -96,7 +96,7 @@
 
     def _c_call_return_trace(self, frame, w_func, args, event):
         if self.profilefunc is None:
-            frame.is_being_profiled = False
+            frame.getorcreatedebug().is_being_profiled = False
         else:
             # undo the effect of the CALL_METHOD bytecode, which would be
             # that even on a built-in method call like '[].append()',
@@ -114,7 +114,7 @@
     def c_exception_trace(self, frame, w_exc):
         "Profile function called upon OperationError."
         if self.profilefunc is None:
-            frame.is_being_profiled = False
+            frame.getorcreatedebug().is_being_profiled = False
         else:
             self._trace(frame, 'c_exception', w_exc)
 
@@ -123,7 +123,7 @@
         if self.gettrace() is not None or self.profilefunc is not None:
             self._trace(frame, 'call', self.space.w_None)
             if self.profilefunc:
-                frame.is_being_profiled = True
+                frame.getorcreatedebug().is_being_profiled = True
 
     def return_trace(self, frame, w_retval):
         "Trace the return from a function"
@@ -145,7 +145,7 @@
         Like bytecode_trace() but doesn't invoke any other events besides the
         trace function.
         """
-        if (frame.w_f_trace is None or self.is_tracing or
+        if (frame.get_w_f_trace() is None or self.is_tracing or
             self.gettrace() is None):
             return
         self.run_trace_func(frame)
@@ -154,8 +154,9 @@
     @jit.unroll_safe
     def run_trace_func(self, frame):
         code = frame.pycode
-        if frame.instr_lb <= frame.last_instr < frame.instr_ub:
-            if frame.last_instr < frame.instr_prev_plus_one:
+        d = frame.getorcreatedebug()
+        if d.instr_lb <= frame.last_instr < d.instr_ub:
+            if frame.last_instr < d.instr_prev_plus_one:
                 # We jumped backwards in the same line.
                 self._trace(frame, 'line', self.space.w_None)
         else:
@@ -170,7 +171,7 @@
                     break
                 addr += c
                 if c:
-                    frame.instr_lb = addr
+                    d.instr_lb = addr
 
                 line += ord(lineno[p + 1])
                 p += 2
@@ -185,15 +186,15 @@
                     if ord(lineno[p + 1]):
                         break
                     p += 2
-                frame.instr_ub = addr
+                d.instr_ub = addr
             else:
-                frame.instr_ub = sys.maxint
+                d.instr_ub = sys.maxint
 
-            if frame.instr_lb == frame.last_instr: # At start of line!
-                frame.f_lineno = line
+            if d.instr_lb == frame.last_instr: # At start of line!
+                d.f_lineno = line
                 self._trace(frame, 'line', self.space.w_None)
 
-        frame.instr_prev_plus_one = frame.last_instr + 1
+        d.instr_prev_plus_one = frame.last_instr + 1
 
     def bytecode_trace_after_exception(self, frame):
         "Like bytecode_trace(), but without increasing the ticker."
@@ -288,7 +289,7 @@
         frame = self.gettopframe_nohidden()
         while frame:
             if is_being_profiled:
-                frame.is_being_profiled = True
+                frame.getorcreatedebug().is_being_profiled = True
             frame = self.getnextframe_nohidden(frame)
 
     def call_tracing(self, w_func, w_args):
@@ -309,7 +310,7 @@
         if event == 'call':
             w_callback = self.gettrace()
         else:
-            w_callback = frame.w_f_trace
+            w_callback = frame.get_w_f_trace()
 
         if w_callback is not None and event != "leaveframe":
             if operr is not None:
@@ -320,15 +321,16 @@
             frame.fast2locals()
             self.is_tracing += 1
             try:
+                d = frame.getorcreatedebug()
                 try:
                     w_result = space.call_function(w_callback, 
space.wrap(frame), space.wrap(event), w_arg)
                     if space.is_w(w_result, space.w_None):
-                        frame.w_f_trace = None
+                        d.w_f_trace = None
                     else:
-                        frame.w_f_trace = w_result
+                        d.w_f_trace = w_result
                 except:
                     self.settrace(space.w_None)
-                    frame.w_f_trace = None
+                    d.w_f_trace = None
                     raise
             finally:
                 self.is_tracing -= 1
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -105,7 +105,7 @@
                                                    self)
                 for i in funccallunrolling:
                     if i < nargs:
-                        new_frame.locals_stack_w[i] = args_w[i]
+                        new_frame.locals_cells_stack_w[i] = args_w[i]
                 return new_frame.run()
         elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1:
             assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
@@ -171,7 +171,7 @@
                                                    self)
         for i in xrange(nargs):
             w_arg = frame.peekvalue(nargs-1-i)
-            new_frame.locals_stack_w[i] = w_arg
+            new_frame.locals_cells_stack_w[i] = w_arg
 
         return new_frame.run()
 
@@ -182,13 +182,13 @@
                                                    self)
         for i in xrange(nargs):
             w_arg = frame.peekvalue(nargs-1-i)
-            new_frame.locals_stack_w[i] = w_arg
+            new_frame.locals_cells_stack_w[i] = w_arg
 
         ndefs = len(self.defs_w)
         start = ndefs - defs_to_load
         i = nargs
         for j in xrange(start, ndefs):
-            new_frame.locals_stack_w[i] = self.defs_w[j]
+            new_frame.locals_cells_stack_w[i] = self.defs_w[j]
             i += 1
         return new_frame.run()
 
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -209,7 +209,7 @@
         # speed hack
         fresh_frame = jit.hint(frame, access_directly=True,
                                       fresh_virtualizable=True)
-        args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name,
+        args.parse_into_scope(None, fresh_frame.locals_cells_stack_w, 
func.name,
                               sig, func.defs_w)
         fresh_frame.init_cells()
         return frame.run()
@@ -221,7 +221,7 @@
         # speed hack
         fresh_frame = jit.hint(frame, access_directly=True,
                                       fresh_virtualizable=True)
-        args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name,
+        args.parse_into_scope(w_obj, fresh_frame.locals_cells_stack_w, 
func.name,
                               sig, func.defs_w)
         fresh_frame.init_cells()
         return frame.run()
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -23,6 +23,19 @@
     globals()[op] = stdlib_opcode.opmap[op]
 HAVE_ARGUMENT = stdlib_opcode.HAVE_ARGUMENT
 
+class FrameDebugData(object):
+    """ A small object that holds debug data for tracing
+    """
+    w_f_trace                = None
+    instr_lb                 = 0
+    instr_ub                 = 0
+    instr_prev_plus_one      = 0
+    f_lineno                 = 0      # current lineno for tracing
+    is_being_profiled        = False
+    w_locals                 = None
+
+    def __init__(self, pycode):
+        self.f_lineno = pycode.co_firstlineno
 
 class PyFrame(W_Root):
     """Represents a frame for a regular Python function
@@ -31,7 +44,8 @@
     Public fields:
      * 'space' is the object space this frame is running in
      * 'code' is the PyCode object this frame runs
-     * 'w_locals' is the locals dictionary to use
+     * 'w_locals' is the locals dictionary to use, if needed, stored on a
+       debug object
      * 'w_globals' is the attached globals dictionary
      * 'builtin' is the attached built-in module
      * 'valuestack_w', 'blockstack', control the interpretation
@@ -49,29 +63,20 @@
     last_instr               = -1
     last_exception           = None
     f_backref                = jit.vref_None
-    # For tracing
-    w_f_trace                = None
-    instr_lb                 = 0
-    instr_ub                 = 0
-    instr_prev_plus_one      = 0
-    # end of tracing
     
-    is_being_profiled        = False
     escaped                  = False  # see mark_as_escaped()
+    debugdata                = None
 
     w_globals = None
-    w_locals = None # dict containing locals, if forced or necessary
     pycode = None # code object executed by that frame
-    locals_stack_w = None # the list of all locals and valuestack
+    locals_cells_stack_w = None # the list of all locals, cells and the 
valuestack
     valuestackdepth = 0 # number of items on valuestack
     lastblock = None
-    # default to False
-    f_lineno = 0 # current lineno
-    cells = None # cells
 
     # other fields:
     
-    # builtin - builtin cache, only if honor__builtins__ is True,
+    # builtin - builtin cache, only if honor__builtins__ is True
+    # defaults to False
 
     # there is also self.space which is removed by the annotator
 
@@ -87,9 +92,14 @@
         self.space = space
         self.w_globals = w_globals
         self.pycode = code
-        self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize)
-        self.valuestackdepth = code.co_nlocals
-        make_sure_not_resized(self.locals_stack_w)
+        ncellvars = len(code.co_cellvars)
+        nfreevars = len(code.co_freevars)
+        size = code.co_nlocals + ncellvars + nfreevars + code.co_stacksize
+        # the layout of this list is as follows:
+        # | local vars | cells | stack |
+        self.locals_cells_stack_w = [None] * size
+        self.valuestackdepth = code.co_nlocals + ncellvars + nfreevars
+        make_sure_not_resized(self.locals_cells_stack_w)
         check_nonneg(self.valuestackdepth)
         #
         if space.config.objspace.honor__builtins__:
@@ -97,7 +107,32 @@
         # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
         # class bodies only have CO_NEWLOCALS.
         self.initialize_frame_scopes(outer_func, code)
-        self.f_lineno = code.co_firstlineno
+
+    def getdebug(self):
+        return self.debugdata
+
+    def getorcreatedebug(self):
+        if self.debugdata is None:
+            self.debugdata = FrameDebugData(self.pycode)
+        return self.debugdata
+
+    def get_w_f_trace(self):
+        d = self.getdebug()
+        if d is None:
+            return None
+        return d.w_f_trace
+
+    def get_is_being_profiled(self):
+        d = self.getdebug()
+        if d is None:
+            return False
+        return d.is_being_profiled
+
+    def get_w_locals(self):
+        d = self.getdebug()
+        if d is None:
+            return None
+        return d.w_locals
 
     def __repr__(self):
         # NOT_RPYTHON: useful in tracebacks
@@ -105,6 +140,11 @@
             self.__class__.__module__, self.__class__.__name__,
             self.pycode, self.get_last_lineno())
 
+    def _getcell(self, varindex):
+        cell = self.locals_cells_stack_w[varindex + self.pycode.co_nlocals]
+        assert isinstance(cell, Cell)
+        return cell
+
     def mark_as_escaped(self):
         """
         Must be called on frames that are exposed to applevel, e.g. by
@@ -150,8 +190,6 @@
         else:
             return self.space.builtin
 
-    _NO_CELLS = []
-
     @jit.unroll_safe
     def initialize_frame_scopes(self, outer_func, code):
         # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
@@ -161,17 +199,16 @@
         flags = code.co_flags
         if not (flags & pycode.CO_OPTIMIZED):
             if flags & pycode.CO_NEWLOCALS:
-                self.w_locals = self.space.newdict(module=True)
+                self.getorcreatedebug().w_locals = 
self.space.newdict(module=True)
             else:
                 assert self.w_globals is not None
-                self.w_locals = self.w_globals
+                self.getorcreatedebug().w_locals = self.w_globals
 
         ncellvars = len(code.co_cellvars)
         nfreevars = len(code.co_freevars)
         if not nfreevars:
             if not ncellvars:
-                self.cells = self._NO_CELLS
-                return            # no self.cells needed - fast path
+                return            # no cells needed - fast path
         elif outer_func is None:
             space = self.space
             raise OperationError(space.w_TypeError,
@@ -184,11 +221,13 @@
         if closure_size != nfreevars:
             raise ValueError("code object received a closure with "
                                  "an unexpected number of free variables")
-        self.cells = [None] * (ncellvars + nfreevars)
+        index = code.co_nlocals
         for i in range(ncellvars):
-            self.cells[i] = Cell()
+            self.locals_cells_stack_w[index] = Cell()
+            index += 1
         for i in range(nfreevars):
-            self.cells[i + ncellvars] = outer_func.closure[i]
+            self.locals_cells_stack_w[index] = outer_func.closure[i]
+            index += 1
 
     def run(self):
         """Start this frame's execution."""
@@ -252,14 +291,24 @@
     # stack manipulation helpers
     def pushvalue(self, w_object):
         depth = self.valuestackdepth
-        self.locals_stack_w[depth] = w_object
+        self.locals_cells_stack_w[depth] = w_object
         self.valuestackdepth = depth + 1
 
+    def _check_stack_index(self, index):
+        # will be completely removed by the optimizer if only used in an assert
+        # and if asserts are disabled
+        code = self.pycode
+        ncellvars = len(code.co_cellvars)
+        nfreevars = len(code.co_freevars)
+        stackstart = code.co_nlocals + ncellvars + nfreevars
+        return index >= stackstart
+
     def popvalue(self):
         depth = self.valuestackdepth - 1
-        assert depth >= self.pycode.co_nlocals, "pop from empty value stack"
-        w_object = self.locals_stack_w[depth]
-        self.locals_stack_w[depth] = None
+        assert self._check_stack_index(depth)
+        assert depth >= 0
+        w_object = self.locals_cells_stack_w[depth]
+        self.locals_cells_stack_w[depth] = None
         self.valuestackdepth = depth
         return w_object
 
@@ -285,25 +334,26 @@
     def peekvalues(self, n):
         values_w = [None] * n
         base = self.valuestackdepth - n
-        assert base >= self.pycode.co_nlocals
+        assert self._check_stack_index(base)
+        assert base >= 0
         while True:
             n -= 1
             if n < 0:
                 break
-            values_w[n] = self.locals_stack_w[base+n]
+            values_w[n] = self.locals_cells_stack_w[base+n]
         return values_w
 
     @jit.unroll_safe
     def dropvalues(self, n):
         n = hint(n, promote=True)
         finaldepth = self.valuestackdepth - n
-        assert finaldepth >= self.pycode.co_nlocals, (
-            "stack underflow in dropvalues()")
+        assert self._check_stack_index(finaldepth)
+        assert finaldepth >= 0
         while True:
             n -= 1
             if n < 0:
                 break
-            self.locals_stack_w[finaldepth+n] = None
+            self.locals_cells_stack_w[finaldepth+n] = None
         self.valuestackdepth = finaldepth
 
     @jit.unroll_safe
@@ -330,34 +380,27 @@
         # Contrast this with CPython where it's PEEK(-1).
         index_from_top = hint(index_from_top, promote=True)
         index = self.valuestackdepth + ~index_from_top
-        assert index >= self.pycode.co_nlocals, (
-            "peek past the bottom of the stack")
-        return self.locals_stack_w[index]
+        assert self._check_stack_index(index)
+        assert index >= 0
+        return self.locals_cells_stack_w[index]
 
     def settopvalue(self, w_object, index_from_top=0):
         index_from_top = hint(index_from_top, promote=True)
         index = self.valuestackdepth + ~index_from_top
-        assert index >= self.pycode.co_nlocals, (
-            "settop past the bottom of the stack")
-        self.locals_stack_w[index] = w_object
+        assert self._check_stack_index(index)
+        assert index >= 0
+        self.locals_cells_stack_w[index] = w_object
 
     @jit.unroll_safe
     def dropvaluesuntil(self, finaldepth):
         depth = self.valuestackdepth - 1
         finaldepth = hint(finaldepth, promote=True)
+        assert finaldepth >= 0
         while depth >= finaldepth:
-            self.locals_stack_w[depth] = None
+            self.locals_cells_stack_w[depth] = None
             depth -= 1
         self.valuestackdepth = finaldepth
 
-    def save_locals_stack(self):
-        return self.locals_stack_w[:self.valuestackdepth]
-
-    def restore_locals_stack(self, items_w):
-        self.locals_stack_w[:len(items_w)] = items_w
-        self.init_cells()
-        self.dropvaluesuntil(len(items_w))
-
     def make_arguments(self, nargs):
         return Arguments(self.space, self.peekvalues(nargs))
 
@@ -380,24 +423,16 @@
         w = space.wrap
         nt = space.newtuple
 
-        cells = self.cells
-        if cells is None:
-            w_cells = space.w_None
-        else:
-            w_cells = space.newlist([space.wrap(cell) for cell in cells])
-
-        if self.w_f_trace is None:
+        if self.get_w_f_trace() is None:
             f_lineno = self.get_last_lineno()
         else:
-            f_lineno = self.f_lineno
+            f_lineno = self.getorcreatedebug().f_lineno
 
         nlocals = self.pycode.co_nlocals
-        values_w = self.locals_stack_w[nlocals:self.valuestackdepth]
-        w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w)
+        values_w = self.locals_cells_stack_w
+        w_locals_cells_stack = maker.slp_into_tuple_with_nulls(space, values_w)
 
         w_blockstack = nt([block._get_state_(space) for block in 
self.get_blocklist()])
-        w_fastlocals = maker.slp_into_tuple_with_nulls(
-            space, self.locals_stack_w[:nlocals])
         if self.last_exception is None:
             w_exc_value = space.w_None
             w_tb = space.w_None
@@ -405,11 +440,12 @@
             w_exc_value = self.last_exception.get_w_value(space)
             w_tb = w(self.last_exception.get_traceback())
 
+        d = self.getorcreatedebug()
         tup_state = [
             w(self.f_backref()),
             w(self.get_builtin()),
             w(self.pycode),
-            w_valuestack,
+            w_locals_cells_stack,
             w_blockstack,
             w_exc_value, # last_exception
             w_tb,        #
@@ -417,16 +453,15 @@
             w(self.last_instr),
             w(self.frame_finished_execution),
             w(f_lineno),
-            w_fastlocals,
             space.w_None,           #XXX placeholder for f_locals
 
             #f_restricted requires no additional data!
-            space.w_None, ## self.w_f_trace,  ignore for now
+            space.w_None,
 
-            w(self.instr_lb), #do we need these three (that are for tracing)
-            w(self.instr_ub),
-            w(self.instr_prev_plus_one),
-            w_cells,
+            w(d.instr_lb),
+            w(d.instr_ub),
+            w(d.instr_prev_plus_one),
+            w(self.valuestackdepth),
             ]
         return nt(tup_state)
 
@@ -435,24 +470,20 @@
         from pypy.module._pickle_support import maker # helper fns
         from pypy.interpreter.pycode import PyCode
         from pypy.interpreter.module import Module
-        args_w = space.unpackiterable(w_args, 18)
-        w_f_back, w_builtin, w_pycode, w_valuestack, w_blockstack, 
w_exc_value, w_tb,\
-            w_globals, w_last_instr, w_finished, w_f_lineno, w_fastlocals, 
w_f_locals, \
-            w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev_plus_one, w_cells 
= args_w
+        args_w = space.unpackiterable(w_args, 17)
+        w_f_back, w_builtin, w_pycode, w_locals_cells_stack, w_blockstack, 
w_exc_value, w_tb,\
+            w_globals, w_last_instr, w_finished, w_f_lineno, w_f_locals, \
+            w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev_plus_one, 
w_stackdepth = args_w
 
         new_frame = self
         pycode = space.interp_w(PyCode, w_pycode)
 
-        if space.is_w(w_cells, space.w_None):
-            closure = None
-            cellvars = []
-        else:
-            from pypy.interpreter.nestedscope import Cell
-            cells_w = space.unpackiterable(w_cells)
-            cells = [space.interp_w(Cell, w_cell) for w_cell in cells_w]
-            ncellvars = len(pycode.co_cellvars)
-            cellvars = cells[:ncellvars]
-            closure = cells[ncellvars:]
+        values_w = maker.slp_from_tuple_with_nulls(space, w_locals_cells_stack)
+        nfreevars = len(pycode.co_freevars)
+        closure = None
+        if nfreevars:
+            base = pycode.co_nlocals + len(pycode.co_cellvars)
+            closure = values_w[base: base + nfreevars]
 
         # do not use the instance's __init__ but the base's, because we set
         # everything like cells from here
@@ -470,9 +501,12 @@
             assert space.interp_w(Module, w_builtin) is space.builtin
         new_frame.set_blocklist([unpickle_block(space, w_blk)
                                  for w_blk in 
space.unpackiterable(w_blockstack)])
-        values_w = maker.slp_from_tuple_with_nulls(space, w_valuestack)
-        for w_value in values_w:
-            new_frame.pushvalue(w_value)
+        self.locals_cells_stack_w = values_w[:]
+        valuestackdepth = space.int_w(w_stackdepth)
+        if not self._check_stack_index(valuestackdepth):
+            raise OperationError(space.w_ValueError, space.wrap("invalid 
stackdepth"))
+        assert valuestackdepth >= 0
+        self.valuestackdepth = valuestackdepth
         if space.is_w(w_exc_value, space.w_None):
             new_frame.last_exception = None
         else:
@@ -483,20 +517,17 @@
                                                       )
         new_frame.last_instr = space.int_w(w_last_instr)
         new_frame.frame_finished_execution = space.is_true(w_finished)
-        new_frame.f_lineno = space.int_w(w_f_lineno)
-        fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals)
-        new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w
+        d = new_frame.getorcreatedebug()
+        d.f_lineno = space.int_w(w_f_lineno)
 
         if space.is_w(w_f_trace, space.w_None):
-            new_frame.w_f_trace = None
+            d.w_f_trace = None
         else:
-            new_frame.w_f_trace = w_f_trace
+            d.w_f_trace = w_f_trace
 
-        new_frame.instr_lb = space.int_w(w_instr_lb)   #the three for tracing
-        new_frame.instr_ub = space.int_w(w_instr_ub)
-        new_frame.instr_prev_plus_one = space.int_w(w_instr_prev_plus_one)
-
-        self._setcellvars(cellvars)
+        d.instr_lb = space.int_w(w_instr_lb)   #the three for tracing
+        d.instr_ub = space.int_w(w_instr_ub)
+        d.instr_prev_plus_one = space.int_w(w_instr_prev_plus_one)
 
     def hide(self):
         return self.pycode.hidden_applevel
@@ -511,10 +542,10 @@
         scope_len = len(scope_w)
         if scope_len > self.pycode.co_nlocals:
             raise ValueError, "new fastscope is longer than the allocated area"
-        # don't assign directly to 'locals_stack_w[:scope_len]' to be
+        # don't assign directly to 'locals_cells_stack_w[:scope_len]' to be
         # virtualizable-friendly
         for i in range(scope_len):
-            self.locals_stack_w[i] = scope_w[i]
+            self.locals_cells_stack_w[i] = scope_w[i]
         self.init_cells()
 
     def getdictscope(self):
@@ -522,30 +553,31 @@
         Get the locals as a dictionary
         """
         self.fast2locals()
-        return self.w_locals
+        return self.debugdata.w_locals
 
     def setdictscope(self, w_locals):
         """
         Initialize the locals from a dictionary.
         """
-        self.w_locals = w_locals
+        self.getorcreatedebug().w_locals = w_locals
         self.locals2fast()
 
     @jit.unroll_safe
     def fast2locals(self):
         # Copy values from the fastlocals to self.w_locals
-        if self.w_locals is None:
-            self.w_locals = self.space.newdict()
+        d = self.getorcreatedebug()
+        if d.w_locals is None:
+            d.w_locals = self.space.newdict()
         varnames = self.getcode().getvarnames()
         for i in range(min(len(varnames), self.getcode().co_nlocals)):
             name = varnames[i]
-            w_value = self.locals_stack_w[i]
+            w_value = self.locals_cells_stack_w[i]
             if w_value is not None:
-                self.space.setitem_str(self.w_locals, name, w_value)
+                self.space.setitem_str(d.w_locals, name, w_value)
             else:
                 w_name = self.space.wrap(name)
                 try:
-                    self.space.delitem(self.w_locals, w_name)
+                    self.space.delitem(d.w_locals, w_name)
                 except OperationError as e:
                     if not e.match(self.space, self.space.w_KeyError):
                         raise
@@ -558,19 +590,20 @@
             freevarnames = freevarnames + self.pycode.co_freevars
         for i in range(len(freevarnames)):
             name = freevarnames[i]
-            cell = self.cells[i]
+            cell = self._getcell(i)
             try:
                 w_value = cell.get()
             except ValueError:
                 pass
             else:
-                self.space.setitem_str(self.w_locals, name, w_value)
+                self.space.setitem_str(d.w_locals, name, w_value)
 
 
     @jit.unroll_safe
     def locals2fast(self):
         # Copy values from self.w_locals to the fastlocals
-        assert self.w_locals is not None
+        w_locals = self.getorcreatedebug().w_locals
+        assert w_locals is not None
         varnames = self.getcode().getvarnames()
         numlocals = self.getcode().co_nlocals
 
@@ -578,7 +611,7 @@
 
         for i in range(min(len(varnames), numlocals)):
             name = varnames[i]
-            w_value = self.space.finditem_str(self.w_locals, name)
+            w_value = self.space.finditem_str(w_locals, name)
             if w_value is not None:
                 new_fastlocals_w[i] = w_value
 
@@ -596,32 +629,29 @@
             # into the locals dict used by the class.
         for i in range(len(freevarnames)):
             name = freevarnames[i]
-            cell = self.cells[i]
-            w_value = self.space.finditem_str(self.w_locals, name)
+            cell = self._getcell(i)
+            w_value = self.space.finditem_str(w_locals, name)
             if w_value is not None:
                 cell.set(w_value)
 
     @jit.unroll_safe
     def init_cells(self):
         """
-        Initialize cellvars from self.locals_stack_w.
+        Initialize cellvars from self.locals_cells_stack_w.
         """
         args_to_copy = self.pycode._args_as_cellvars
+        index = self.pycode.co_nlocals
         for i in range(len(args_to_copy)):
             argnum = args_to_copy[i]
             if argnum >= 0:
-                self.cells[i].set(self.locals_stack_w[argnum])
+                cell = self.locals_cells_stack_w[index]
+                assert isinstance(cell, Cell)
+                cell.set(self.locals_cells_stack_w[argnum])
+            index += 1
 
     def getclosure(self):
         return None
 
-    def _setcellvars(self, cellvars):
-        ncellvars = len(self.pycode.co_cellvars)
-        if len(cellvars) != ncellvars:
-            raise OperationError(self.space.w_TypeError,
-                                 self.space.wrap("bad cellvars"))
-        self.cells[:ncellvars] = cellvars
-
     def fget_code(self, space):
         return space.wrap(self.getcode())
 
@@ -632,10 +662,10 @@
 
     def fget_f_lineno(self, space):
         "Returns the line number of the instruction currently being executed."
-        if self.w_f_trace is None:
+        if self.get_w_f_trace() is None:
             return space.wrap(self.get_last_lineno())
         else:
-            return space.wrap(self.f_lineno)
+            return space.wrap(self.getorcreatedebug().f_lineno)
 
     def fset_f_lineno(self, space, w_new_lineno):
         "Returns the line number of the instruction currently being executed."
@@ -645,7 +675,7 @@
             raise OperationError(space.w_ValueError,
                                  space.wrap("lineno must be an integer"))
 
-        if self.w_f_trace is None:
+        if self.get_w_f_trace() is None:
             raise OperationError(space.w_ValueError,
                   space.wrap("f_lineno can only be set by a trace function."))
 
@@ -764,7 +794,7 @@
             block.cleanup(self)
             f_iblock -= 1
 
-        self.f_lineno = new_lineno
+        self.getorcreatedebug().f_lineno = new_lineno
         self.last_instr = new_lasti
 
     def get_last_lineno(self):
@@ -782,17 +812,18 @@
         return self.space.wrap(self.last_instr)
 
     def fget_f_trace(self, space):
-        return self.w_f_trace
+        return self.get_w_f_trace()
 
     def fset_f_trace(self, space, w_trace):
         if space.is_w(w_trace, space.w_None):
-            self.w_f_trace = None
+            self.getorcreatedebug().w_f_trace = None
         else:
-            self.w_f_trace = w_trace
-            self.f_lineno = self.get_last_lineno()
+            d = self.getorcreatedebug()
+            d.w_f_trace = w_trace
+            d.f_lineno = self.get_last_lineno()
 
     def fdel_f_trace(self, space):
-        self.w_f_trace = None
+        self.getorcreatedebug().w_f_trace = None
 
     def fget_f_exc_type(self, space):
         if self.last_exception is not None:
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -109,14 +109,14 @@
                 # dispatch_bytecode(), causing the real exception to be
                 # raised after the exception handler block was popped.
                 try:
-                    trace = self.w_f_trace
+                    trace = self.get_w_f_trace()
                     if trace is not None:
-                        self.w_f_trace = None
+                        self.getorcreatedebug().w_f_trace = None
                     try:
                         ec.bytecode_trace_after_exception(self)
                     finally:
                         if trace is not None:
-                            self.w_f_trace = trace
+                            self.getorcreatedebug().w_f_trace = trace
                 except OperationError, e:
                     operr = e
             pytraceback.record_application_traceback(
@@ -485,7 +485,7 @@
 
     def LOAD_FAST(self, varindex, next_instr):
         # access a local variable directly
-        w_value = self.locals_stack_w[varindex]
+        w_value = self.locals_cells_stack_w[varindex]
         if w_value is None:
             self._load_fast_failed(varindex)
         self.pushvalue(w_value)
@@ -505,7 +505,7 @@
     def STORE_FAST(self, varindex, next_instr):
         w_newvalue = self.popvalue()
         assert w_newvalue is not None
-        self.locals_stack_w[varindex] = w_newvalue
+        self.locals_cells_stack_w[varindex] = w_newvalue
 
     def getfreevarname(self, index):
         freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
@@ -517,7 +517,7 @@
 
     def LOAD_DEREF(self, varindex, next_instr):
         # nested scopes: access a variable through its cell object
-        cell = self.cells[varindex]
+        cell = self._getcell(varindex)
         try:
             w_value = cell.get()
         except ValueError:
@@ -536,12 +536,12 @@
     def STORE_DEREF(self, varindex, next_instr):
         # nested scopes: access a variable through its cell object
         w_newvalue = self.popvalue()
-        cell = self.cells[varindex]
+        cell = self._getcell(varindex)
         cell.set(w_newvalue)
 
     def LOAD_CLOSURE(self, varindex, next_instr):
         # nested scopes: access the cell object
-        cell = self.cells[varindex]
+        cell = self._getcell(varindex)
         w_value = self.space.wrap(cell)
         self.pushvalue(w_value)
 
@@ -773,7 +773,7 @@
             raise RaiseWithExplicitTraceback(operror)
 
     def LOAD_LOCALS(self, oparg, next_instr):
-        self.pushvalue(self.w_locals)
+        self.pushvalue(self.getorcreatedebug().w_locals)
 
     def EXEC_STMT(self, oparg, next_instr):
         w_locals = self.popvalue()
@@ -789,8 +789,8 @@
                                      self.space.gettypeobject(PyCode.typedef))
         w_prog, w_globals, w_locals = self.space.fixedview(w_resulttuple, 3)
 
-        plain = (self.w_locals is not None and
-                 self.space.is_w(w_locals, self.w_locals))
+        plain = (self.get_w_locals() is not None and
+                 self.space.is_w(w_locals, self.get_w_locals()))
         if plain:
             w_locals = self.getdictscope()
         co = self.space.interp_w(eval.Code, w_prog)
@@ -840,12 +840,13 @@
     def STORE_NAME(self, varindex, next_instr):
         varname = self.getname_u(varindex)
         w_newvalue = self.popvalue()
-        self.space.setitem_str(self.w_locals, varname, w_newvalue)
+        self.space.setitem_str(self.getorcreatedebug().w_locals, varname,
+                               w_newvalue)
 
     def DELETE_NAME(self, varindex, next_instr):
         w_varname = self.getname_w(varindex)
         try:
-            self.space.delitem(self.w_locals, w_varname)
+            self.space.delitem(self.getorcreatedebug().w_locals, w_varname)
         except OperationError, e:
             # catch KeyErrors and turn them into NameErrors
             if not e.match(self.space, self.space.w_KeyError):
@@ -881,9 +882,10 @@
         self.space.delitem(self.w_globals, w_varname)
 
     def LOAD_NAME(self, nameindex, next_instr):
-        if self.w_locals is not self.w_globals:
+        if self.getorcreatedebug().w_locals is not self.w_globals:
             varname = self.getname_u(nameindex)
-            w_value = self.space.finditem_str(self.w_locals, varname)
+            w_value = self.space.finditem_str(self.getorcreatedebug().w_locals,
+                                              varname)
             if w_value is not None:
                 self.pushvalue(w_value)
                 return
@@ -909,12 +911,12 @@
     LOAD_GLOBAL._always_inline_ = True
 
     def DELETE_FAST(self, varindex, next_instr):
-        if self.locals_stack_w[varindex] is None:
+        if self.locals_cells_stack_w[varindex] is None:
             varname = self.getlocalvarname(varindex)
             raise oefmt(self.space.w_UnboundLocalError,
                         "local variable '%s' referenced before assignment",
                         varname)
-        self.locals_stack_w[varindex] = None
+        self.locals_cells_stack_w[varindex] = None
 
     def BUILD_TUPLE(self, itemcount, next_instr):
         items = self.popvalues(itemcount)
@@ -1013,7 +1015,11 @@
         if w_import is None:
             raise OperationError(space.w_ImportError,
                                  space.wrap("__import__ not found"))
-        w_locals = self.w_locals
+        d = self.getdebug()
+        if d is None:
+            w_locals = None
+        else:
+            w_locals = d.w_locals
         if w_locals is None:            # CPython does this
             w_locals = space.w_None
         w_modulename = space.wrap(modulename)
@@ -1185,7 +1191,7 @@
         args = self.argument_factory(arguments, keywords, keywords_w, w_star,
                                      w_starstar)
         w_function  = self.popvalue()
-        if self.is_being_profiled and function.is_builtin_code(w_function):
+        if self.get_is_being_profiled() and 
function.is_builtin_code(w_function):
             w_result = self.space.call_args_and_c_profile(self, w_function,
                                                           args)
         else:
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/interpreter/test/test_pyframe.py 
b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -64,6 +64,8 @@
                 f.f_lineno += 1
             return x
 
+        open    # force fetching of this name now
+
         def function():
             xyz
             with open(self.tempfile1, 'w') as f:
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -536,7 +536,7 @@
     __objclass__ = GetSetProperty(GetSetProperty.descr_get_objclass),
     __doc__ = interp_attrproperty('doc', cls=GetSetProperty),
     )
-GetSetProperty.typedef.acceptable_as_base_class = False
+assert not GetSetProperty.typedef.acceptable_as_base_class  # no __new__
 
 
 class Member(W_Root):
@@ -590,7 +590,7 @@
     __name__ = interp_attrproperty('name', cls=Member),
     __objclass__ = interp_attrproperty_w('w_cls', cls=Member),
     )
-Member.typedef.acceptable_as_base_class = False
+assert not Member.typedef.acceptable_as_base_class  # no __new__
 
 # ____________________________________________________________
 
@@ -706,7 +706,7 @@
     co_flags = GetSetProperty(fget_co_flags, cls=Code),
     co_consts = GetSetProperty(fget_co_consts, cls=Code),
     )
-Code.typedef.acceptable_as_base_class = False
+assert not Code.typedef.acceptable_as_base_class  # no __new__
 
 BuiltinCode.typedef = TypeDef('builtin-code',
     __reduce__   = interp2app(BuiltinCode.descr__reduce__),
@@ -716,7 +716,7 @@
     co_flags = GetSetProperty(fget_co_flags, cls=BuiltinCode),
     co_consts = GetSetProperty(fget_co_consts, cls=BuiltinCode),
     )
-BuiltinCode.typedef.acceptable_as_base_class = False
+assert not BuiltinCode.typedef.acceptable_as_base_class  # no __new__
 
 
 PyCode.typedef = TypeDef('code',
@@ -761,7 +761,7 @@
     f_locals = GetSetProperty(PyFrame.fget_getdictscope),
     f_globals = interp_attrproperty_w('w_globals', cls=PyFrame),
 )
-PyFrame.typedef.acceptable_as_base_class = False
+assert not PyFrame.typedef.acceptable_as_base_class  # no __new__
 
 Module.typedef = TypeDef("module",
     __new__ = interp2app(Module.descr_module__new__.im_func),
@@ -907,7 +907,7 @@
     tb_lineno = GetSetProperty(PyTraceback.descr_tb_lineno),
     tb_next = interp_attrproperty('next', cls=PyTraceback),
     )
-PyTraceback.typedef.acceptable_as_base_class = False
+assert not PyTraceback.typedef.acceptable_as_base_class  # no __new__
 
 GeneratorIterator.typedef = TypeDef("generator",
     __repr__   = interp2app(GeneratorIterator.descr__repr__),
@@ -929,7 +929,7 @@
     __name__   = GetSetProperty(GeneratorIterator.descr__name__),
     __weakref__ = make_weakref_descr(GeneratorIterator),
 )
-GeneratorIterator.typedef.acceptable_as_base_class = False
+assert not GeneratorIterator.typedef.acceptable_as_base_class  # no __new__
 
 Cell.typedef = TypeDef("cell",
     __cmp__      = interp2app(Cell.descr__cmp__),
@@ -939,17 +939,17 @@
     __setstate__ = interp2app(Cell.descr__setstate__),
     cell_contents= GetSetProperty(Cell.descr__cell_contents, cls=Cell),
 )
-Cell.typedef.acceptable_as_base_class = False
+assert not Cell.typedef.acceptable_as_base_class  # no __new__
 
 Ellipsis.typedef = TypeDef("Ellipsis",
     __repr__ = interp2app(Ellipsis.descr__repr__),
 )
-Ellipsis.typedef.acceptable_as_base_class = False
+assert not Ellipsis.typedef.acceptable_as_base_class  # no __new__
 
 NotImplemented.typedef = TypeDef("NotImplemented",
     __repr__ = interp2app(NotImplemented.descr__repr__),
 )
-NotImplemented.typedef.acceptable_as_base_class = False
+assert not NotImplemented.typedef.acceptable_as_base_class  # no __new__
 
 SuspendedUnroller.typedef = TypeDef("SuspendedUnroller")
-SuspendedUnroller.typedef.acceptable_as_base_class = False
+assert not SuspendedUnroller.typedef.acceptable_as_base_class  # no __new__
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.
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to