[pypy-commit] pypy default: merged upstream.

alex_gaynor noreply at buildbot.pypy.org
Mon Sep 5 19:03:11 CEST 2011


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r47086:4d04034495ce
Date: 2011-09-05 09:12 -0700
http://bitbucket.org/pypy/pypy/changeset/4d04034495ce/

Log:	merged upstream.

diff --git a/lib_pypy/_elementtree.py b/lib_pypy/_elementtree.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_elementtree.py
@@ -0,0 +1,6 @@
+# Just use ElementTree.
+
+from xml.etree import ElementTree
+
+globals().update(ElementTree.__dict__)
+del __all__
diff --git a/lib_pypy/stackless.py b/lib_pypy/stackless.py
--- a/lib_pypy/stackless.py
+++ b/lib_pypy/stackless.py
@@ -4,121 +4,124 @@
 Please refer to their documentation.
 """
 
-DEBUG = True
-
-def dprint(*args):
-    for arg in args:
-        print arg,
-    print
 
 import traceback
-import sys
+import _continuation
+from functools import partial
+
+class TaskletExit(Exception):
+    pass
+
+CoroutineExit = TaskletExit
+
+class GWrap(_continuation.continulet):
+    """This is just a wrapper around continulet to allow
+       to stick additional attributes to a continulet.
+       To be more concrete, we need a backreference to
+       the coroutine object"""
+
+
+class coroutine(object):
+    "we can't have continulet as a base, because continulets can't be rebound"
+
+    def __init__(self):
+        self._frame = None
+        self.is_zombie = False
+
+    def __getattr__(self, attr):
+        return getattr(self._frame, attr)
+
+    def __del__(self):
+        self.is_zombie = True
+        del self._frame
+        self._frame = None
+
+    def bind(self, func, *argl, **argd):
+        """coro.bind(f, *argl, **argd) -> None.
+           binds function f to coro. f will be called with
+           arguments *argl, **argd
+        """
+        if self._frame is None or not self._frame.is_pending():
+
+            def _func(c, *args, **kwargs):
+                return func(*args, **kwargs)
+            
+            run = partial(_func, *argl, **argd)
+            self._frame = frame = GWrap(run)
+        else:
+            raise ValueError("cannot bind a bound coroutine")
+
+    def switch(self):
+        """coro.switch() -> returnvalue
+           switches to coroutine coro. If the bound function
+           f finishes, the returnvalue is that of f, otherwise
+           None is returned
+        """
+        current = _getcurrent()
+        current._jump_to(self)
+
+    def _jump_to(self, coroutine):
+        _tls.current_coroutine = coroutine
+        self._frame.switch(to=coroutine._frame)
+
+    def kill(self):
+        """coro.kill() : kill coroutine coro"""
+        _tls.current_coroutine = self
+        self._frame.throw(CoroutineExit)
+
+    def _is_alive(self):
+        if self._frame is None:
+            return False
+        return not self._frame.is_pending()
+    is_alive = property(_is_alive)
+    del _is_alive
+
+    def getcurrent():
+        """coroutine.getcurrent() -> the currently running coroutine"""
+        try:
+            return _getcurrent()
+        except AttributeError:
+            return _maincoro
+    getcurrent = staticmethod(getcurrent)
+
+    def __reduce__(self):
+        raise TypeError, 'pickling is not possible based upon continulets'
+
+
+def _getcurrent():
+    "Returns the current coroutine (i.e. the one which called this function)."
+    try:
+        return _tls.current_coroutine
+    except AttributeError:
+        # first call in this thread: current == main
+        _coroutine_create_main()
+        return _tls.current_coroutine
+
 try:
-    # If _stackless can be imported then TaskletExit and CoroutineExit are 
-    # automatically added to the builtins.
-    from _stackless import coroutine, greenlet
-except ImportError: # we are running from CPython
-    from greenlet import greenlet, GreenletExit
-    TaskletExit = CoroutineExit = GreenletExit
-    del GreenletExit
-    try:
-        from functools import partial
-    except ImportError: # we are not running python 2.5
-        class partial(object):
-            # just enough of 'partial' to be usefull
-            def __init__(self, func, *argl, **argd):
-                self.func = func
-                self.argl = argl
-                self.argd = argd
+    from thread import _local
+except ImportError:
+    class _local(object):    # assume no threads
+        pass
 
-            def __call__(self):
-                return self.func(*self.argl, **self.argd)
+_tls = _local()
 
-    class GWrap(greenlet):
-        """This is just a wrapper around greenlets to allow
-           to stick additional attributes to a greenlet.
-           To be more concrete, we need a backreference to
-           the coroutine object"""
+def _coroutine_create_main():
+    # create the main coroutine for this thread
+    _tls.current_coroutine = None
+    main_coroutine = coroutine()
+    main_coroutine.bind(lambda x:x)
+    _tls.main_coroutine = main_coroutine
+    _tls.current_coroutine = main_coroutine
+    return main_coroutine
 
-    class MWrap(object):
-        def __init__(self,something):
-            self.something = something
 
-        def __getattr__(self, attr):
-            return getattr(self.something, attr)
+_maincoro = _coroutine_create_main()
 
-    class coroutine(object):
-        "we can't have greenlet as a base, because greenlets can't be rebound"
-
-        def __init__(self):
-            self._frame = None
-            self.is_zombie = False
-
-        def __getattr__(self, attr):
-            return getattr(self._frame, attr)
-
-        def __del__(self):
-            self.is_zombie = True
-            del self._frame
-            self._frame = None
-
-        def bind(self, func, *argl, **argd):
-            """coro.bind(f, *argl, **argd) -> None.
-               binds function f to coro. f will be called with
-               arguments *argl, **argd
-            """
-            if self._frame is None or self._frame.dead:
-                self._frame = frame = GWrap()
-                frame.coro = self
-            if hasattr(self._frame, 'run') and self._frame.run:
-                raise ValueError("cannot bind a bound coroutine")
-            self._frame.run = partial(func, *argl, **argd)
-
-        def switch(self):
-            """coro.switch() -> returnvalue
-               switches to coroutine coro. If the bound function
-               f finishes, the returnvalue is that of f, otherwise
-               None is returned
-            """
-            try:
-                return greenlet.switch(self._frame)
-            except TypeError, exp: # self._frame is the main coroutine
-                return greenlet.switch(self._frame.something)
-
-        def kill(self):
-            """coro.kill() : kill coroutine coro"""
-            self._frame.throw()
-
-        def _is_alive(self):
-            if self._frame is None:
-                return False
-            return not self._frame.dead
-        is_alive = property(_is_alive)
-        del _is_alive
-
-        def getcurrent():
-            """coroutine.getcurrent() -> the currently running coroutine"""
-            try:
-                return greenlet.getcurrent().coro
-            except AttributeError:
-                return _maincoro
-        getcurrent = staticmethod(getcurrent)
-
-        def __reduce__(self):
-            raise TypeError, 'pickling is not possible based upon greenlets'
-
-    _maincoro = coroutine()
-    maingreenlet = greenlet.getcurrent()
-    _maincoro._frame = frame = MWrap(maingreenlet)
-    frame.coro = _maincoro
-    del frame
-    del maingreenlet
 
 from collections import deque
 
 import operator
-__all__ = 'run getcurrent getmain schedule tasklet channel coroutine \
-                greenlet'.split()
+__all__ = 'run getcurrent getmain schedule tasklet channel coroutine'.split()
 
 _global_task_id = 0
 _squeue = None
@@ -131,7 +134,8 @@
 def _scheduler_remove(value):
     try:
         del _squeue[operator.indexOf(_squeue, value)]
-    except ValueError:pass
+    except ValueError:
+        pass
 
 def _scheduler_append(value, normal=True):
     if normal:
diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -57,11 +57,13 @@
     all_regs              = []
     no_lower_byte_regs    = []
     save_around_call_regs = []
-    
+    frame_reg             = None
+
     def __init__(self, longevity, frame_manager=None, assembler=None):
         self.free_regs = self.all_regs[:]
         self.longevity = longevity
         self.reg_bindings = {}
+        self.bindings_to_frame_reg = {}
         self.position = -1
         self.frame_manager = frame_manager
         self.assembler = assembler
@@ -218,6 +220,10 @@
         self.reg_bindings[v] = loc
         return loc
 
+    def force_allocate_frame_reg(self, v):
+        """ Allocate the new variable v in the frame register."""
+        self.bindings_to_frame_reg[v] = None
+
     def force_spill_var(self, var):
         self._sync_var(var)
         try:
@@ -236,6 +242,8 @@
         try:
             return self.reg_bindings[box]
         except KeyError:
+            if box in self.bindings_to_frame_reg:
+                return self.frame_reg
             return self.frame_manager.loc(box)
 
     def return_constant(self, v, forbidden_vars=[], selected_reg=None):
@@ -264,8 +272,9 @@
         self._check_type(v)
         if isinstance(v, Const):
             return self.return_constant(v, forbidden_vars, selected_reg)
-        
         prev_loc = self.loc(v)
+        if prev_loc is self.frame_reg and selected_reg is None:
+            return prev_loc
         loc = self.force_allocate_reg(v, forbidden_vars, selected_reg,
                                       need_lower_byte=need_lower_byte)
         if prev_loc is not loc:
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -957,6 +957,7 @@
         if (isinstance(from_loc, RegLoc) and from_loc.is_xmm) or (isinstance(to_loc, RegLoc) and to_loc.is_xmm):
             self.mc.MOVSD(to_loc, from_loc)
         else:
+            assert to_loc is not ebp
             self.mc.MOV(to_loc, from_loc)
 
     regalloc_mov = mov # legacy interface
@@ -2510,11 +2511,6 @@
 
     genop_discard_cond_call_gc_wb_array = genop_discard_cond_call_gc_wb
 
-    def genop_force_token(self, op, arglocs, resloc):
-        # RegAlloc.consider_force_token ensures this:
-        assert isinstance(resloc, RegLoc)
-        self.mc.LEA_rb(resloc.value, FORCE_INDEX_OFS)
-
     def not_implemented_op_discard(self, op, arglocs):
         not_implemented("not implemented operation: %s" % op.getopname())
 
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -29,6 +29,7 @@
     all_regs = [eax, ecx, edx, ebx, esi, edi]
     no_lower_byte_regs = [esi, edi]
     save_around_call_regs = [eax, edx, ecx]
+    frame_reg = ebp
 
     REGLOC_TO_GCROOTMAP_REG_INDEX = {
         ebx: 1,
@@ -312,8 +313,11 @@
                     self.fm.frame_bindings[arg] = loc
             else:
                 if isinstance(loc, RegLoc):
-                    self.rm.reg_bindings[arg] = loc
-                    used[loc] = None
+                    if loc is ebp:
+                        self.rm.bindings_to_frame_reg[arg] = None
+                    else:
+                        self.rm.reg_bindings[arg] = loc
+                        used[loc] = None
                 else:
                     self.fm.frame_bindings[arg] = loc
         self.rm.free_regs = []
@@ -1358,8 +1362,8 @@
                                             self.assembler.datablockwrapper)
 
     def consider_force_token(self, op):
-        loc = self.rm.force_allocate_reg(op.result)
-        self.Perform(op, [], loc)
+        # the FORCE_TOKEN operation returns directly 'ebp'
+        self.rm.force_allocate_frame_reg(op.result)
 
     def not_implemented_op(self, op):
         not_implemented("not implemented operation: %s" % op.getopname())
diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -119,7 +119,8 @@
             setitem(index, null)
 
     def get_latest_force_token(self):
-        return self.assembler.fail_ebp + FORCE_INDEX_OFS
+        # the FORCE_TOKEN operation and this helper both return 'ebp'.
+        return self.assembler.fail_ebp
 
     def execute_token(self, executable_token):
         addr = executable_token._x86_bootstrap_code
@@ -153,8 +154,9 @@
                                        flavor='raw', zero=True,
                                        immortal=True)
 
-    def force(self, addr_of_force_index):
+    def force(self, addr_of_force_token):
         TP = rffi.CArrayPtr(lltype.Signed)
+        addr_of_force_index = addr_of_force_token + FORCE_INDEX_OFS
         fail_index = rffi.cast(TP, addr_of_force_index)[0]
         assert fail_index >= 0, "already forced!"
         faildescr = self.get_fail_descr_from_number(fail_index)
@@ -164,7 +166,7 @@
         # start of "no gc operation!" block
         fail_index_2 = self.assembler.grab_frame_values(
             bytecode,
-            addr_of_force_index - FORCE_INDEX_OFS,
+            addr_of_force_token,
             self.all_null_registers)
         self.assembler.leave_jitted_hook()
         # end of "no gc operation!" block
diff --git a/pypy/objspace/std/test/test_methodcache.py b/pypy/objspace/std/test/test_methodcache.py
--- a/pypy/objspace/std/test/test_methodcache.py
+++ b/pypy/objspace/std/test/test_methodcache.py
@@ -88,30 +88,37 @@
   
     def test_many_names(self):
         import __pypy__
-        class A(object):
-            foo = 5
-            bar = 6
-            baz = 7
-            xyz = 8
-            stuff = 9
-            a = 10
-            foobar = 11
+        for j in range(20):
+            class A(object):
+                foo = 5
+                bar = 6
+                baz = 7
+                xyz = 8
+                stuff = 9
+                a = 10
+                foobar = 11
 
-        a = A()
-        names = [name for name in A.__dict__.keys()
-                      if not name.startswith('_')]
-        names.sort()
-        names_repeated = names * 10
-        result = []
-        __pypy__.reset_method_cache_counter()
-        for name in names_repeated:
-            result.append(getattr(a, name))
-        append_counter = __pypy__.method_cache_counter("append")
-        names_counters = [__pypy__.method_cache_counter(name)
-                          for name in names]
-        assert append_counter[0] >= 5 * len(names)
-        for name, count in zip(names, names_counters):
-            assert count[0] >= 5, str((name, count))
+            a = A()
+            names = [name for name in A.__dict__.keys()
+                          if not name.startswith('_')]
+            names.sort()
+            names_repeated = names * 10
+            result = []
+            __pypy__.reset_method_cache_counter()
+            for name in names_repeated:
+                result.append(getattr(a, name))
+            append_counter = __pypy__.method_cache_counter("append")
+            names_counters = [__pypy__.method_cache_counter(name)
+                              for name in names]
+            try:
+                assert append_counter[0] >= 10 * len(names) - 1
+                for name, count in zip(names, names_counters):
+                    assert count == (9, 1), str((name, count))
+                break
+            except AssertionError:
+                pass
+        else:
+            raise
 
     def test_mutating_bases(self):
         class C(object):
diff --git a/pypy/rpython/module/ll_os_stat.py b/pypy/rpython/module/ll_os_stat.py
--- a/pypy/rpython/module/ll_os_stat.py
+++ b/pypy/rpython/module/ll_os_stat.py
@@ -49,19 +49,8 @@
     ]
 N_INDEXABLE_FIELDS = 10
 
-# for now, check the host Python to know which st_xxx fields exist
-STAT_FIELDS = [(_name, _TYPE) for (_name, _TYPE) in ALL_STAT_FIELDS
-                              if hasattr(os.stat_result, _name)]
-
-STAT_FIELD_TYPES = dict(STAT_FIELDS)      # {'st_xxx': TYPE}
-
-STAT_FIELD_NAMES = [_name for (_name, _TYPE) in ALL_STAT_FIELDS
-                          if _name in STAT_FIELD_TYPES]
-
-del _name, _TYPE
-
 # For OO backends, expose only the portable fields (the first 10).
-PORTABLE_STAT_FIELDS = STAT_FIELDS[:N_INDEXABLE_FIELDS]
+PORTABLE_STAT_FIELDS = ALL_STAT_FIELDS[:N_INDEXABLE_FIELDS]
 
 # ____________________________________________________________
 #
@@ -142,17 +131,22 @@
     includes = INCLUDES
 )
 
-if sys.platform != 'win32':
+if TIMESPEC is not None:
+    class CConfig_for_timespec:
+        _compilation_info_ = compilation_info
+        TIMESPEC = TIMESPEC
+    TIMESPEC = lltype.Ptr(
+        platform.configure(CConfig_for_timespec)['TIMESPEC'])
+
+
+def posix_declaration(try_to_add=None):
+    global STAT_STRUCT
 
     LL_STAT_FIELDS = STAT_FIELDS[:]
+    if try_to_add:
+        LL_STAT_FIELDS.append(try_to_add)
 
     if TIMESPEC is not None:
-        class CConfig_for_timespec:
-            _compilation_info_ = compilation_info
-            TIMESPEC = TIMESPEC
-
-        TIMESPEC = lltype.Ptr(
-            platform.configure(CConfig_for_timespec)['TIMESPEC'])
 
         def _expand(lst, originalname, timespecname):
             for i, (_name, _TYPE) in enumerate(lst):
@@ -178,9 +172,34 @@
     class CConfig:
         _compilation_info_ = compilation_info
         STAT_STRUCT = platform.Struct('struct %s' % _name_struct_stat, LL_STAT_FIELDS)
-    config = platform.configure(CConfig)
+    try:
+        config = platform.configure(CConfig)
+    except platform.CompilationError:
+        if try_to_add:
+            return    # failed to add this field, give up
+        raise
 
     STAT_STRUCT = lltype.Ptr(config['STAT_STRUCT'])
+    if try_to_add:
+        STAT_FIELDS.append(try_to_add)
+
+
+# This lists only the fields that have been found on the underlying platform.
+# Initially only the PORTABLE_STAT_FIELDS, but more may be added by the
+# following loop.
+STAT_FIELDS = PORTABLE_STAT_FIELDS[:]
+
+if sys.platform != 'win32':
+    posix_declaration()
+    for _i in range(len(PORTABLE_STAT_FIELDS), len(ALL_STAT_FIELDS)):
+        posix_declaration(ALL_STAT_FIELDS[_i])
+    del _i
+
+# these two global vars only list the fields defined in the underlying platform
+STAT_FIELD_TYPES = dict(STAT_FIELDS)      # {'st_xxx': TYPE}
+STAT_FIELD_NAMES = [_name for (_name, _TYPE) in STAT_FIELDS]
+del _name, _TYPE
+
 
 def build_stat_result(st):
     # only for LL backends
diff --git a/pypy/rpython/module/test/test_ll_os_stat.py b/pypy/rpython/module/test/test_ll_os_stat.py
--- a/pypy/rpython/module/test/test_ll_os_stat.py
+++ b/pypy/rpython/module/test/test_ll_os_stat.py
@@ -2,6 +2,16 @@
 import sys, os
 import py
 
+
+class TestLinuxImplementation:
+    def setup_class(cls):
+        if not sys.platform.startswith('linux'):
+            py.test.skip("linux specific tests")
+
+    def test_has_all_fields(self):
+        assert ll_os_stat.STAT_FIELDS == ll_os_stat.ALL_STAT_FIELDS[:13]
+
+
 class TestWin32Implementation:
     def setup_class(cls):
         if sys.platform != 'win32':


More information about the pypy-commit mailing list