[pypy-svn] pypy jit-unroll-loops: hg merge default

hakanardo commits-noreply at bitbucket.org
Wed Dec 22 07:33:42 CET 2010


Author: Hakan Ardo <hakan at debian.org>
Branch: jit-unroll-loops
Changeset: r40171:d506820f0901
Date: 2010-12-22 07:24 +0100
http://bitbucket.org/pypy/pypy/changeset/d506820f0901/

Log:	hg merge default


diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -105,14 +105,11 @@
         make_sure_not_resized(self.arguments_w)
         if w_stararg is not None:
             self._combine_starargs_wrapped(w_stararg)
-        if w_starstararg is not None:
-            self._combine_starstarargs_wrapped(w_starstararg)
-            # if we have a call where **args are used at the callsite
-            # we shouldn't let the JIT see the argument matching
-            self._dont_jit = True
-        else:
-            self._dont_jit = False
-        
+        # if we have a call where **args are used at the callsite
+        # we shouldn't let the JIT see the argument matching
+        self._dont_jit = (w_starstararg is not None and
+                          self._combine_starstarargs_wrapped(w_starstararg))
+
     def __repr__(self):
         """ NOT_RPYTHON """
         name = self.__class__.__name__
@@ -160,10 +157,20 @@
             raise OperationError(space.w_TypeError,
                                  space.wrap("argument after ** must be "
                                             "a dictionary"))
-        keywords_w = [None] * space.int_w(space.len(w_starstararg))
-        keywords = [None] * space.int_w(space.len(w_starstararg))
+        if space.is_true(w_starstararg):
+            self._do_combine_starstarargs_wrapped(w_starstararg)
+            return True
+        else:
+            return False    # empty dict; don't disable the JIT
+
+    def _do_combine_starstarargs_wrapped(self, w_starstararg):
+        space = self.space
+        keys_w = space.unpackiterable(w_starstararg)
+        length = len(keys_w)
+        keywords_w = [None] * length
+        keywords = [None] * length
         i = 0
-        for w_key in space.unpackiterable(w_starstararg):
+        for w_key in keys_w:
             try:
                 key = space.str_w(w_key)
             except OperationError, e:

diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -78,7 +78,13 @@
     old_dir = os.getcwd()
     try:
         os.chdir(str(builddir))
-        os.system("strip -x " + str(archive_pypy_c))    # ignore errors
+        #
+        # 'strip' fun: see https://codespeak.net/issue/pypy-dev/issue587
+        if sys.platform == 'darwin':
+            os.system("strip -x " + str(archive_pypy_c))    # ignore errors
+        else:
+            os.system("strip " + str(archive_pypy_c))    # ignore errors
+        #
         if USE_TARFILE_MODULE:
             import tarfile
             tf = tarfile.open(str(builddir.join(name + '.tar.bz2')), 'w:bz2')

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -320,6 +320,11 @@
     'PyCObject_GetDesc', 'PyCObject_Import', 'PyCObject_SetVoidPtr',
     'PyCObject_Type', 'init_pycobject',
 
+    'PyCapsule_New', 'PyCapsule_IsValid', 'PyCapsule_GetPointer',
+    'PyCapsule_GetName', 'PyCapsule_GetDestructor', 'PyCapsule_GetContext',
+    'PyCapsule_SetPointer', 'PyCapsule_SetName', 'PyCapsule_SetDestructor',
+    'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', 'init_capsule',
+
     'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer',
 
     'PyStructSequence_InitType', 'PyStructSequence_New',
@@ -564,9 +569,11 @@
 def setup_init_functions(eci):
     init_buffer = rffi.llexternal('init_bufferobject', [], lltype.Void, compilation_info=eci)
     init_pycobject = rffi.llexternal('init_pycobject', [], lltype.Void, compilation_info=eci)
+    init_capsule = rffi.llexternal('init_capsule', [], lltype.Void, compilation_info=eci)
     INIT_FUNCTIONS.extend([
         lambda space: init_buffer(),
         lambda space: init_pycobject(),
+        lambda space: init_capsule(),
     ])
 
 def init_function(func):
@@ -657,6 +664,8 @@
     import ctypes
     bridge = ctypes.CDLL(str(modulename), mode=ctypes.RTLD_GLOBAL)
 
+    space.fromcache(State).install_dll(eci)
+
     # populate static data
     for name, (typ, expr) in GLOBALS.iteritems():
         from pypy.module import cpyext
@@ -836,6 +845,25 @@
             structs.append('%s %s = NULL;' % (typ, name))
     struct_source = '\n'.join(structs)
 
+    separate_module_sources = [code, struct_source]
+
+    if sys.platform == 'win32':
+        get_pythonapi_source = '''
+        #include <windows.h>
+        HANDLE pypy_get_pythonapi_handle() {
+            MEMORY_BASIC_INFORMATION  mi;
+            memset(&mi, 0, sizeof(mi));
+
+            if( !VirtualQueryEx(GetCurrentProcess(), &pypy_get_pythonapi_handle,
+                                &mi, sizeof(mi)) )
+                return 0;
+
+            return (HMODULE)mi.AllocationBase;
+        }
+        '''
+        separate_module_sources.append(get_pythonapi_source)
+        export_symbols_eci.append('pypy_get_pythonapi_handle')
+
     eci = ExternalCompilationInfo(
         include_dirs=include_dirs,
         separate_module_files=[source_dir / "varargwrapper.c",
@@ -849,12 +877,14 @@
                                source_dir / "object.c",
                                source_dir / "cobject.c",
                                source_dir / "structseq.c",
+                               source_dir / "capsule.c",
                                ],
-        separate_module_sources = [code, struct_source],
+        separate_module_sources=separate_module_sources,
         export_symbols=export_symbols_eci,
         compile_extra=compile_extra,
         **kwds
         )
+
     return eci
 
 
@@ -873,6 +903,8 @@
 
     eci = build_eci(False, export_symbols, code)
 
+    space.fromcache(State).install_dll(eci)
+
     run_bootstrap_functions(space)
     setup_va_functions(eci)
 
@@ -907,7 +939,9 @@
     if os.sep not in path:
         path = os.curdir + os.sep + path      # force a '/' in the path
     state = space.fromcache(State)
-    state.package_context = name
+    if state.find_extension(name, path) is not None:
+        return
+    state.package_context = name, path
     try:
         from pypy.rlib import rdynload
         try:
@@ -932,7 +966,8 @@
         generic_cpy_call(space, initfunc)
         state.check_and_raise_exception()
     finally:
-        state.package_context = None
+        state.package_context = None, None
+    state.fixup_extension(name, path)
 
 @specialize.ll()
 def generic_cpy_call(space, func, *args):

diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -328,18 +328,6 @@
     used as the positional and keyword parameters to the object's constructor."""
     raise NotImplementedError
 
- at cpython_api([PyObject], rffi.VOIDP_real, error=lltype.nullptr(rffi.VOIDP.TO))
-def PyCObject_GetDesc(space, self):
-    """Return the description void * that the PyCObject self was
-    created with."""
-    raise NotImplementedError
-
- at cpython_api([PyObject, rffi.VOIDP_real], rffi.INT_real, error=0)
-def PyCObject_SetVoidPtr(space, self, cobj):
-    """Set the void pointer inside self to cobj. The PyCObject must not
-    have an associated destructor. Return true on success, false on failure."""
-    raise NotImplementedError
-
 @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
 def PyCode_Check(space, co):
     """Return true if co is a code object"""

diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -2,7 +2,8 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import lltype
-
+from pypy.rlib.rdynload import DLLHANDLE
+import sys
 
 class State:
     def __init__(self, space):
@@ -15,14 +16,19 @@
         self.operror = None
         self.new_method_def = lltype.nullptr(PyMethodDef)
 
-        # When importing a package, use this to keep track of its name.  This is
+        # When importing a package, use this to keep track
+        # of its name and path (as a 2-tuple).  This is
         # necessary because an extension module in a package might not supply
         # its own fully qualified name to Py_InitModule.  If it doesn't, we need
         # to be able to figure out what module is being initialized.  Recursive
         # imports will clobber this value, which might be confusing, but it
         # doesn't hurt anything because the code that cares about it will have
         # already read it by that time.
-        self.package_context = None
+        self.package_context = None, None
+
+        # A mapping {filename: copy-of-the-w_dict}, similar to CPython's
+        # variable 'extensions' in Python/import.c.
+        self.extensions = {}
 
     def set_exception(self, operror):
         self.clear_exception()
@@ -43,6 +49,46 @@
             raise OperationError(self.space.w_SystemError, self.space.wrap(
                 "Function returned an error result without setting an exception"))
 
+    def build_api(self, space):
+        """NOT_RPYTHON
+        This function is called when at object space creation,
+        and drives the compilation of the cpyext library
+        """
+        from pypy.module.cpyext import api
+        state = self.space.fromcache(State)
+        if not self.space.config.translating:
+            state.api_lib = str(api.build_bridge(self.space))
+        else:
+            api.setup_library(self.space)
+
+    def install_dll(self, eci):
+        """NOT_RPYTHON
+        Called when the dll has been compiled"""
+        if sys.platform == 'win32':
+            self.get_pythonapi_handle = rffi.llexternal(
+                'pypy_get_pythonapi_handle', [], DLLHANDLE,
+                compilation_info=eci)
+
+    def startup(self, space):
+        "This function is called when the program really starts"
+
+        from pypy.module.cpyext.typeobject import setup_new_method_def
+        from pypy.module.cpyext.pyobject import RefcountState
+        from pypy.module.cpyext.api import INIT_FUNCTIONS
+
+        setup_new_method_def(space)
+        if not we_are_translated():
+            space.setattr(space.wrap(self),
+                          space.wrap('api_lib'),
+                          space.wrap(self.api_lib))
+        else:
+            refcountstate = space.fromcache(RefcountState)
+            refcountstate.init_r2w_from_w2r()
+
+        for func in INIT_FUNCTIONS:
+            func(space)
+            self.check_and_raise_exception()
+
     def get_programname(self):
         if not self.programname:
             space = self.space
@@ -55,3 +101,29 @@
             self.programname = rffi.str2charp(progname)
             lltype.render_immortal(self.programname)
         return self.programname
+
+    def find_extension(self, name, path):
+        from pypy.module.cpyext.modsupport import PyImport_AddModule
+        from pypy.interpreter.module import Module
+        try:
+            w_dict = self.extensions[path]
+        except KeyError:
+            return None
+        w_mod = PyImport_AddModule(self.space, name)
+        assert isinstance(w_mod, Module)
+        w_mdict = w_mod.getdict()
+        self.space.call_method(w_mdict, 'update', w_dict)
+        return w_mod
+
+    def fixup_extension(self, name, path):
+        from pypy.interpreter.module import Module
+        space = self.space
+        w_modules = space.sys.get('modules')
+        w_mod = space.finditem_str(w_modules, name)
+        if not isinstance(w_mod, Module):
+            msg = "fixup_extension: module '%s' not loaded" % name
+            raise OperationError(space.w_SystemError,
+                                 space.wrap(msg))
+        w_dict = w_mod.getdict()
+        w_copy = space.call_method(w_dict, 'copy')
+        self.extensions[path] = w_copy

diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -112,6 +112,7 @@
 #include "eval.h"
 #include "pymem.h"
 #include "pycobject.h"
+#include "pycapsule.h"
 #include "bufferobject.h"
 #include "sliceobject.h"
 #include "datetime.h"

diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -125,6 +125,9 @@
     def visit_bufferstr(self, el, app_sig):
         self.checked_space_method(el, app_sig)
 
+    def visit_str_or_None(self, el, app_sig):
+        self.checked_space_method(el, app_sig)
+
     def visit_nonnegint(self, el, app_sig):
         self.checked_space_method(el, app_sig)
 
@@ -238,6 +241,9 @@
     def visit_bufferstr(self, typ):
         self.run_args.append("space.bufferstr_w(%s)" % (self.scopenext(),))
 
+    def visit_str_or_None(self, typ):
+        self.run_args.append("space.str_or_None_w(%s)" % (self.scopenext(),))
+
     def visit_nonnegint(self, typ):
         self.run_args.append("space.nonnegint_w(%s)" % (self.scopenext(),))
 
@@ -365,6 +371,9 @@
     def visit_bufferstr(self, typ):
         self.unwrap.append("space.bufferstr_w(%s)" % (self.nextarg(),))
 
+    def visit_str_or_None(self, typ):
+        self.unwrap.append("space.str_or_None_w(%s)" % (self.nextarg(),))
+
     def visit_nonnegint(self, typ):
         self.unwrap.append("space.nonnegint_w(%s)" % (self.nextarg(),))
 

diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -778,6 +778,12 @@
         # CPython 2.5 adds an extra argument consumed by this opcode
         if self.pycode.magic >= 0xa0df294:
             w_flag = self.popvalue()
+            try:
+                if space.int_w(w_flag) == -1:
+                    w_flag = None
+            except OperationError, e:
+                if e.async(space):
+                    raise
         else:
             w_flag = None
 

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -555,6 +555,9 @@
 
     def setup_builtin_modules(self):
         "NOT_RPYTHON: only for initializing the space."
+        if self.config.objspace.usemodules.cpyext:
+            from pypy.module.cpyext.state import State
+            self.fromcache(State).build_api(self)
         self.getbuiltinmodule('sys')
         self.getbuiltinmodule('imp')
         self.getbuiltinmodule('__builtin__')
@@ -1123,6 +1126,11 @@
             buffer = self.buffer_w(w_obj)
             return buffer.as_str()
 
+    def str_or_None_w(self, w_obj):
+        if self.is_w(w_obj, self.w_None):
+            return None
+        return self.str_w(w_obj)
+
     def realstr_w(self, w_obj):
         # Like str_w, but only works if w_obj is really of type 'str'.
         if not self.is_true(self.isinstance(w_obj, self.w_str)):

diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -35,7 +35,7 @@
 
 class AppTestApi:
     def setup_class(cls):
-        cls.space = gettestobjspace(usemodules=['cpyext', 'thread'])
+        cls.space = gettestobjspace(usemodules=['cpyext', 'thread', '_rawffi'])
         from pypy.rlib.libffi import get_libc_name
         cls.w_libc = cls.space.wrap(get_libc_name())
 
@@ -44,6 +44,17 @@
         raises(ImportError, cpyext.load_module, "missing.file", "foo")
         raises(ImportError, cpyext.load_module, self.libc, "invalid.function")
 
+    def test_dllhandle(self):
+        import sys
+        if sys.version_info < (2, 6):
+            skip("Python >= 2.6 only")
+        assert sys.dllhandle
+        assert sys.dllhandle.getaddressindll('PyPyErr_NewException')
+        import ctypes # slow
+        PyUnicode_GetDefaultEncoding = ctypes.pythonapi.PyPyUnicode_GetDefaultEncoding
+        PyUnicode_GetDefaultEncoding.restype = ctypes.c_char_p
+        assert PyUnicode_GetDefaultEncoding() == 'ascii'
+
 def compile_module(space, modname, **kwds):
     """
     Build an extension module and return the filename of the resulting native
@@ -147,7 +158,7 @@
 
 class AppTestCpythonExtensionBase(LeakCheckingTest):
     def setup_class(cls):
-        cls.space = gettestobjspace(usemodules=['cpyext', 'thread'])
+        cls.space = gettestobjspace(usemodules=['cpyext', 'thread', '_rawffi'])
         cls.space.getbuiltinmodule("cpyext")
         from pypy.module.imp.importing import importhook
         importhook(cls.space, "os") # warm up reference counts
@@ -211,6 +222,12 @@
         else:
             return os.path.dirname(mod)
 
+    def reimport_module(self, mod, name):
+        api.load_extension_module(self.space, mod, name)
+        return self.space.getitem(
+            self.space.sys.get('modules'),
+            self.space.wrap(name))
+
     def import_extension(self, modname, functions, prologue=""):
         methods_table = []
         codes = []
@@ -250,6 +267,7 @@
         self.imported_module_names = []
 
         self.w_import_module = self.space.wrap(self.import_module)
+        self.w_reimport_module = self.space.wrap(self.reimport_module)
         self.w_import_extension = self.space.wrap(self.import_extension)
         self.w_compile_module = self.space.wrap(self.compile_module)
         self.w_record_imported_module = self.space.wrap(
@@ -698,3 +716,43 @@
         p = mod.get_programname()
         print p
         assert 'py' in p
+
+    def test_no_double_imports(self):
+        import sys, os
+        try:
+            init = """
+            static int _imported_already = 0;
+            FILE *f = fopen("_imported_already", "w");
+            fprintf(f, "imported_already: %d\\n", _imported_already);
+            fclose(f);
+            _imported_already = 1;
+            if (Py_IsInitialized()) {
+                Py_InitModule("foo", NULL);
+            }
+            """
+            self.import_module(name='foo', init=init)
+            assert 'foo' in sys.modules
+
+            f = open('_imported_already')
+            data = f.read()
+            f.close()
+            assert data == 'imported_already: 0\n'
+
+            f = open('_imported_already', 'w')
+            f.write('not again!\n')
+            f.close()
+            m1 = sys.modules['foo']
+            m2 = self.reimport_module(m1.__file__, name='foo')
+            assert m1 is m2
+            assert m1 is sys.modules['foo']
+
+            f = open('_imported_already')
+            data = f.read()
+            f.close()
+            assert data == 'not again!\n'
+
+        finally:
+            try:
+                os.unlink('_imported_already')
+            except OSError:
+                pass

diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -95,6 +95,22 @@
         assert obj.char_member == "a"
         raises(TypeError, "obj.char_member = 'spam'")
         raises(TypeError, "obj.char_member = 42")
+        #
+        import sys
+        bignum = sys.maxint - 42
+        obj.short_member = -12345;     assert obj.short_member == -12345
+        obj.long_member = -bignum;     assert obj.long_member == -bignum
+        obj.ushort_member = 45678;     assert obj.ushort_member == 45678
+        obj.uint_member = 3000000000;  assert obj.uint_member == 3000000000
+        obj.ulong_member = 2*bignum;   assert obj.ulong_member == 2*bignum
+        obj.byte_member = -99;         assert obj.byte_member == -99
+        obj.ubyte_member = 199;        assert obj.ubyte_member == 199
+        obj.bool_member = True;        assert obj.bool_member is True
+        obj.float_member = 9.25;       assert obj.float_member == 9.25
+        obj.double_member = 9.25;      assert obj.double_member == 9.25
+        obj.longlong_member = -2**59;  assert obj.longlong_member == -2**59
+        obj.ulonglong_member = 2**63;  assert obj.ulonglong_member == 2**63
+        #
         self.cleanup_references()
 
     def test_staticmethod(self):

diff --git a/pypy/tool/release/make_release.py b/pypy/tool/release/make_release.py
--- a/pypy/tool/release/make_release.py
+++ b/pypy/tool/release/make_release.py
@@ -4,7 +4,8 @@
 into release packages. Note: you must run apropriate buildbots first and
 make sure there are no failures. Use force-builds.py from the same directory.
 
-Usage: make_release.py release/<release name> release_version
+Usage: make_release.py  <branchname>  <version>
+ e.g.: make_release.py  release-1.4.1  1.4.1
 """
 
 import autopath
@@ -20,6 +21,7 @@
 import shutil
 
 BASEURL = 'http://buildbot.pypy.org/nightly/'
+PAUSE = False
 
 def browse_nightly(branch,
                    baseurl=BASEURL,
@@ -32,12 +34,12 @@
     dom = minidom.parseString(xml)
     refs = [node.getAttribute('href') for node in dom.getElementsByTagName('a')
             if 'pypy' in node.getAttribute('href')]
-    # all refs are of form: pypy-{type}-{revision}-{platform}.tar.bz2
-    r = re.compile('pypy-c-([\w\d]+)-(\d+)-([\w\d]+).tar.bz2$')
+    # all refs are of form: pypy-c-{type}-{revnum}-{hghash}-{platform}.tar.bz2
+    r = re.compile('pypy-c-([\w\d]+)-(\d+)-([0-9a-f]+)-([\w\d]+).tar.bz2$')
     d = {}
     for ref in refs:
-        kind, rev, platform = r.match(ref).groups()
-        rev = int(rev)
+        kind, revnum, hghash, platform = r.match(ref).groups()
+        rev = int(revnum)
         try:
             lastrev, _ = d[(kind, platform)]
         except KeyError:
@@ -51,8 +53,10 @@
     tmpdir = udir.join('download')
     tmpdir.ensure(dir=True)
     alltars = []
+    olddir = os.getcwd()
     try:
         os.chdir(str(tmpdir))
+        print 'Using tmpdir', str(tmpdir)
         for (kind, platform), (rev, name) in to_download.iteritems():
             if platform == 'win32':
                 print 'Ignoring %s, windows unsupported' % name
@@ -64,20 +68,23 @@
                 t = tarfile.open(str(tmpdir.join(name)))
                 dirname = t.getmembers()[0].name
                 t.extractall(path=str(tmpdir))
-                os.system('mv %s %s' % (str(tmpdir.join(dirname)),
-                                        str(tmpdir.join('pypy-%s' % release))))
                 if kind == 'jit':
                     kind = ''
                 else:
                     kind = '-' + kind
-                olddir = os.getcwd()
-                name = 'pypy-%s-%s%s.tar.bz2' % (release, platform, kind)
+                topdirname = 'pypy-%s-%s%s' % (release, platform, kind)
+                os.system('mv %s %s' % (str(tmpdir.join(dirname)),
+                                        str(tmpdir.join(topdirname))))
+                if PAUSE:
+                    print 'Pausing, press Enter...'
+                    raw_input()
+                name = '%s.tar.bz2' % topdirname
                 print "Building %s" % name
                 t = tarfile.open(name, 'w:bz2')
-                t.add('pypy-%s' % release)
+                t.add(topdirname)
                 alltars.append(name)
                 t.close()
-                shutil.rmtree(str(tmpdir.join('pypy-' + release)))
+                shutil.rmtree(str(tmpdir.join(topdirname)))
         for name in alltars:
             print "Uploading %s" % name
             os.system('scp %s codespeak.net:/www/pypy.org/htdocs/download' % name)

diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py
--- a/pypy/interpreter/test/test_gateway.py
+++ b/pypy/interpreter/test/test_gateway.py
@@ -267,10 +267,12 @@
         space = self.space
         w = space.wrap
         def g3_ss(space, s0, s1):
+            if s1 is None:
+                return space.wrap(42)
             return space.wrap(s0+s1)       
         app_g3_ss = gateway.interp2app_temp(g3_ss,
                                          unwrap_spec=[gateway.ObjSpace,
-                                                      str,str])
+                                                      str, 'str_or_None'])
         w_app_g3_ss = space.wrap(app_g3_ss) 
         assert self.space.eq_w(
             space.call(w_app_g3_ss, 
@@ -280,6 +282,11 @@
         assert self.space.eq_w(
             space.call_function(w_app_g3_ss, w('foo'), w('bar')),
             w('foobar'))
+        assert self.space.eq_w(
+            space.call_function(w_app_g3_ss, w('foo'), space.w_None),
+            w(42))
+        space.raises_w(space.w_TypeError, space.call_function,
+                       w_app_g3_ss, space.w_None, w('bar'))
 
     def test_interp2app_unwrap_spec_int_float(self):
         space = self.space

diff --git a/pypy/jit/metainterp/memmgr.py b/pypy/jit/metainterp/memmgr.py
--- a/pypy/jit/metainterp/memmgr.py
+++ b/pypy/jit/metainterp/memmgr.py
@@ -32,6 +32,9 @@
         # enough.  But in this day and age, you'd still never have the
         # patience of waiting for a slowly-increasing 64-bit number to
         # overflow :-)
+
+        # According to my estimates it's about 5e9 years given 1000 loops
+        # per second
         self.current_generation = r_int64(1)
         self.next_check = r_int64(-1)
         self.alive_loops = {}


More information about the Pypy-commit mailing list