[pypy-commit] pypy remove-set-smm: hg merge default

Manuel Jacob noreply at buildbot.pypy.org
Wed May 15 19:44:50 CEST 2013


Author: Manuel Jacob
Branch: remove-set-smm
Changeset: r64191:ec226759d640
Date: 2013-05-15 19:31 +0200
http://bitbucket.org/pypy/pypy/changeset/ec226759d640/

Log:	hg merge default

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
@@ -8,5 +8,11 @@
 .. branch: numpy-pickle
 Pickling of numpy arrays and dtypes (including record dtypes)
 
+.. branch: remove-array-smm
+Remove multimethods in the arraymodule
+
+.. branch: callback-stacklet
+Fixed bug when switching stacklets from a C callback
 
 .. branch: remove-set-smm
+Remove multi-methods on sets
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -100,11 +100,11 @@
         return space.w_True
     if comp_op == LT or comp_op == LE:
         if arr1.len < arr2.len:
-            return space.w_False
+            return space.w_True
+        return space.w_False
+    if arr1.len > arr2.len:
         return space.w_True
-    if arr1.len > arr2.len:
-        return space.w_False
-    return space.w_True
+    return space.w_False
 
 UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar,
                                         hints={'nolength': True}))
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -552,6 +552,15 @@
                 assert (a >= c) is False
                 assert (c >= a) is True
 
+        a = self.array('i', [-1, 0, 1, 42, 0x7f])
+        assert not a == 2*a
+        assert a != 2*a
+        assert a < 2*a
+        assert a <= 2*a
+        assert not a > 2*a
+        assert not a >= 2*a
+
+
     def test_reduce(self):
         import pickle
         a = self.array('i', [1, 2, 3])
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -14,6 +14,7 @@
 from pypy.module.micronumpy.interp_arrayops import where
 from pypy.module.micronumpy import interp_ufuncs
 from rpython.rlib.objectmodel import specialize, instantiate
+from rpython.rlib.nonconst import NonConstant
 
 
 class BogusBytecode(Exception):
@@ -40,6 +41,10 @@
 TWO_ARG_FUNCTIONS = ["dot", 'take']
 THREE_ARG_FUNCTIONS = ['where']
 
+class W_TypeObject(W_Root):
+    def __init__(self, name):
+        self.name = name
+
 class FakeSpace(object):
     w_ValueError = "ValueError"
     w_TypeError = "TypeError"
@@ -48,17 +53,17 @@
     w_NotImplementedError = "NotImplementedError"
     w_None = None
 
-    w_bool = "bool"
-    w_int = "int"
-    w_float = "float"
-    w_list = "list"
-    w_long = "long"
-    w_tuple = 'tuple'
-    w_slice = "slice"
-    w_str = "str"
-    w_unicode = "unicode"
-    w_complex = "complex"
-    w_dict = "dict"
+    w_bool = W_TypeObject("bool")
+    w_int = W_TypeObject("int")
+    w_float = W_TypeObject("float")
+    w_list = W_TypeObject("list")
+    w_long = W_TypeObject("long")
+    w_tuple = W_TypeObject('tuple')
+    w_slice = W_TypeObject("slice")
+    w_str = W_TypeObject("str")
+    w_unicode = W_TypeObject("unicode")
+    w_complex = W_TypeObject("complex")
+    w_dict = W_TypeObject("dict")
 
     def __init__(self):
         """NOT_RPYTHON"""
@@ -73,6 +78,13 @@
     def issequence_w(self, w_obj):
         return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray)
 
+    def len(self, w_obj):
+        assert isinstance(w_obj, ListObject)
+        return self.wrap(len(w_obj.items))
+
+    def getattr(self, w_obj, w_attr):
+        return StringObject(NonConstant('foo'))
+
     def isinstance_w(self, w_obj, w_tp):
         return w_obj.tp == w_tp
 
diff --git a/pypy/objspace/fake/checkmodule.py b/pypy/objspace/fake/checkmodule.py
--- a/pypy/objspace/fake/checkmodule.py
+++ b/pypy/objspace/fake/checkmodule.py
@@ -5,6 +5,7 @@
 def checkmodule(*modnames):
     config = get_pypy_config(translating=True)
     space = FakeObjSpace(config)
+    space.setup()
     seeobj_w = []
     for modname in modnames:
         mod = __import__('pypy.module.%s' % modname, None, None, ['__doc__'])
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -55,6 +55,10 @@
         from rpython.rlib.rbigint import rbigint
         return rbigint.fromint(NonConstant(42))
 
+class W_MyListObj(W_MyObject):
+    def append(self, w_other):
+        pass
+
 class W_MyType(W_MyObject):
     def __init__(self):
         self.mro_w = [w_some_obj(), w_some_obj()]
@@ -107,6 +111,9 @@
         self._seen_extras = []
         ObjSpace.__init__(self, config=config)
 
+    def _freeze_(self):
+        return True
+
     def float_w(self, w_obj):
         is_root(w_obj)
         return NonConstant(42.5)
@@ -131,7 +138,7 @@
     def newlist(self, list_w):
         for w_x in list_w:
             is_root(w_x)
-        return w_some_obj()
+        return W_MyListObj()
 
     def newslice(self, w_start, w_end, w_step):
         is_root(w_start)
@@ -316,38 +323,36 @@
         t.buildrtyper().specialize()
         t.checkgraphs()
 
+    def setup(space):
+        for name in (ObjSpace.ConstantTable +
+                     ObjSpace.ExceptionTable +
+                     ['int', 'str', 'float', 'long', 'tuple', 'list',
+                      'dict', 'unicode', 'complex', 'slice', 'bool',
+                      'basestring', 'object', 'bytearray']):
+            setattr(space, 'w_' + name, w_some_obj())
+        space.w_type = w_some_type()
+        #
+        for (name, _, arity, _) in ObjSpace.MethodTable:
+            if name == 'type':
+                continue
+            args = ['w_%d' % i for i in range(arity)]
+            params = args[:]
+            d = {'is_root': is_root,
+                 'w_some_obj': w_some_obj}
+            if name in ('get',):
+                params[-1] += '=None'
+            exec compile2("""\
+                def meth(%s):
+                    %s
+                    return w_some_obj()
+            """ % (', '.join(params),
+                   '; '.join(['is_root(%s)' % arg for arg in args]))) in d
+            meth = func_with_new_name(d['meth'], name)
+            setattr(space, name, meth)
+        #
+        for name in ObjSpace.IrregularOpTable:
+            assert hasattr(space, name)    # missing?
 
-def setup():
-    for name in (ObjSpace.ConstantTable +
-                 ObjSpace.ExceptionTable +
-                 ['int', 'str', 'float', 'long', 'tuple', 'list',
-                  'dict', 'unicode', 'complex', 'slice', 'bool',
-                  'basestring', 'object', 'bytearray']):
-        setattr(FakeObjSpace, 'w_' + name, w_some_obj())
-    FakeObjSpace.w_type = w_some_type()
-    #
-    for (name, _, arity, _) in ObjSpace.MethodTable:
-        if name == 'type':
-            continue
-        args = ['w_%d' % i for i in range(arity)]
-        params = args[:]
-        d = {'is_root': is_root,
-             'w_some_obj': w_some_obj}
-        if name in ('get',):
-            params[-1] += '=None'
-        exec compile2("""\
-            def meth(self, %s):
-                %s
-                return w_some_obj()
-        """ % (', '.join(params),
-               '; '.join(['is_root(%s)' % arg for arg in args]))) in d
-        meth = func_with_new_name(d['meth'], name)
-        setattr(FakeObjSpace, name, meth)
-    #
-    for name in ObjSpace.IrregularOpTable:
-        assert hasattr(FakeObjSpace, name)    # missing?
-
-setup()
 
 # ____________________________________________________________
 
diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -333,8 +333,9 @@
             s += ' instance of %s' % self.w__class__
         return '<%s>' % s
 
-    def unwrap(w_self, space):
-        raise UnwrapError, 'cannot unwrap %r' % (w_self,)
+    def unwrap(self, space):
+        raise UnwrapError('cannot unwrap %r' % self)
+
 
 class UnwrapError(Exception):
     pass
@@ -399,7 +400,7 @@
         mm.dispatch_tree = merge(self.dispatch_tree, other.dispatch_tree)
         return mm
 
-NOT_MULTIMETHODS = dict.fromkeys(
+NOT_MULTIMETHODS = set(
     ['delattr', 'delete', 'get', 'id', 'inplace_div', 'inplace_floordiv',
      'inplace_lshift', 'inplace_mod', 'inplace_pow', 'inplace_rshift',
      'inplace_truediv', 'is_', 'set', 'setattr', 'type', 'userdel',
diff --git a/rpython/jit/metainterp/test/test_compile.py b/rpython/jit/metainterp/test/test_compile.py
--- a/rpython/jit/metainterp/test/test_compile.py
+++ b/rpython/jit/metainterp/test/test_compile.py
@@ -1,10 +1,10 @@
 from rpython.config.translationoption import get_combined_translation_config
-from rpython.jit.metainterp.history import TargetToken, ConstInt, History, Stats
-from rpython.jit.metainterp.history import BoxInt, INT
+from rpython.jit.metainterp.history import ConstInt, History, Stats
+from rpython.jit.metainterp.history import INT
 from rpython.jit.metainterp.compile import compile_loop
-from rpython.jit.metainterp.compile import ResumeGuardDescr
 from rpython.jit.metainterp.compile import ResumeGuardCountersInt
 from rpython.jit.metainterp.compile import compile_tmp_callback
+from rpython.jit.metainterp import jitexc
 from rpython.jit.metainterp import jitprof, typesystem, compile
 from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
 from rpython.jit.tool.oparser import parse
@@ -13,7 +13,7 @@
 class FakeCPU(object):
     class tracker:
         pass
-    
+
     ts = typesystem.llhelper
     def __init__(self):
         self.seen = []
@@ -41,7 +41,7 @@
     loopnumbering = 0
 
 class FakeMetaInterpStaticData(object):
-    
+
     logger_noopt = FakeLogger()
     logger_ops = FakeLogger()
     config = get_combined_translation_config(translating=True)
@@ -192,14 +192,13 @@
     assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), got) == llexc
     #
     class FakeMetaInterpSD:
-        class ExitFrameWithExceptionRef(Exception):
-            pass
+        pass
     FakeMetaInterpSD.cpu = cpu
     deadframe = cpu.execute_token(loop_token, -156, -178)
     fail_descr = cpu.get_latest_descr(deadframe)
     try:
         fail_descr.handle_fail(deadframe, FakeMetaInterpSD(), None)
-    except FakeMetaInterpSD.ExitFrameWithExceptionRef, e:
-        assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.args[1]) == llexc
+    except jitexc.ExitFrameWithExceptionRef, e:
+        assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.value) == llexc
     else:
         assert 0, "should have raised"
diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py
--- a/rpython/memory/gctransform/asmgcroot.py
+++ b/rpython/memory/gctransform/asmgcroot.py
@@ -170,12 +170,57 @@
             jit2gc = gctransformer.translator._jit2gc
             self.frame_tid = jit2gc['frame_tid']
         self.gctransformer = gctransformer
+        #
+        # unless overridden in need_thread_support():
+        self.belongs_to_current_thread = lambda framedata: True
 
     def need_stacklet_support(self, gctransformer, getfn):
+        from rpython.annotator import model as annmodel
+        from rpython.rlib import _stacklet_asmgcc
         # stacklet support: BIG HACK for rlib.rstacklet
-        from rpython.rlib import _stacklet_asmgcc
         _stacklet_asmgcc._asmstackrootwalker = self     # as a global! argh
         _stacklet_asmgcc.complete_destrptr(gctransformer)
+        #
+        def gc_detach_callback_pieces():
+            anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
+            result = llmemory.NULL
+            framedata = anchor.address[1]
+            while framedata != anchor:
+                next = framedata.address[1]
+                if self.belongs_to_current_thread(framedata):
+                    # detach it
+                    prev = framedata.address[0]
+                    prev.address[1] = next
+                    next.address[0] = prev
+                    # update the global stack counter
+                    rffi.stackcounter.stacks_counter -= 1
+                    # reattach framedata into the singly-linked list 'result'
+                    framedata.address[0] = rffi.cast(llmemory.Address, -1)
+                    framedata.address[1] = result
+                    result = framedata
+                framedata = next
+            return result
+        #
+        def gc_reattach_callback_pieces(pieces):
+            anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
+            while pieces != llmemory.NULL:
+                framedata = pieces
+                pieces = pieces.address[1]
+                # attach 'framedata' into the normal doubly-linked list
+                following = anchor.address[1]
+                following.address[0] = framedata
+                framedata.address[1] = following
+                anchor.address[1] = framedata
+                framedata.address[0] = anchor
+                # update the global stack counter
+                rffi.stackcounter.stacks_counter += 1
+        #
+        s_addr = annmodel.SomeAddress()
+        s_None = annmodel.s_None
+        self.gc_detach_callback_pieces_ptr = getfn(gc_detach_callback_pieces,
+                                                   [], s_addr)
+        self.gc_reattach_callback_pieces_ptr=getfn(gc_reattach_callback_pieces,
+                                                   [s_addr], s_None)
 
     def need_thread_support(self, gctransformer, getfn):
         # Threads supported "out of the box" by the rest of the code.
@@ -227,6 +272,7 @@
             stack_stop  = llop.stack_current(llmemory.Address)
             return (stack_start <= framedata <= stack_stop or
                     stack_start >= framedata >= stack_stop)
+        self.belongs_to_current_thread = belongs_to_current_thread
 
         def thread_before_fork():
             # before fork(): collect all ASM_FRAMEDATA structures that do
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -800,6 +800,21 @@
     def gct_gc_adr_of_root_stack_top(self, hop):
         self._gc_adr_of_gcdata_attr(hop, 'root_stack_top')
 
+    def gct_gc_detach_callback_pieces(self, hop):
+        op = hop.spaceop
+        assert len(op.args) == 0
+        hop.genop("direct_call",
+                  [self.root_walker.gc_detach_callback_pieces_ptr],
+                  resultvar=op.result)
+
+    def gct_gc_reattach_callback_pieces(self, hop):
+        op = hop.spaceop
+        assert len(op.args) == 1
+        hop.genop("direct_call",
+                  [self.root_walker.gc_reattach_callback_pieces_ptr,
+                   op.args[0]],
+                  resultvar=op.result)
+
     def gct_gc_shadowstackref_new(self, hop):
         op = hop.spaceop
         livevars = self.push_roots(hop)
diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py
--- a/rpython/rlib/_stacklet_asmgcc.py
+++ b/rpython/rlib/_stacklet_asmgcc.py
@@ -32,6 +32,7 @@
             if not p.handle:
                 return False
             self.context = llmemory.cast_ptr_to_adr(p.handle)
+            self.next_callback_piece = p.callback_pieces
             anchor = p.anchor
             del p
             self.curframe = lltype.malloc(WALKFRAME, flavor='raw')
@@ -50,11 +51,19 @@
             retaddraddr = self.translateptr(retaddraddr)
             curframe.frame_address = retaddraddr.address[0]
 
-        def teardown(self):
-            lltype.free(self.curframe, flavor='raw')
-            lltype.free(self.otherframe, flavor='raw')
-            self.context = llmemory.NULL
-            return llmemory.NULL
+        def fetch_next_stack_piece(self):
+            if self.next_callback_piece == llmemory.NULL:
+                lltype.free(self.curframe, flavor='raw')
+                lltype.free(self.otherframe, flavor='raw')
+                self.context = llmemory.NULL
+                return False
+            else:
+                anchor = self.next_callback_piece
+                nextaddr = anchor + sizeofaddr
+                nextaddr = self.translateptr(nextaddr)
+                self.next_callback_piece = nextaddr.address[0]
+                self.fill_initial_frame(self.curframe, anchor)
+                return True
 
         def next(self, obj, prev):
             #
@@ -117,7 +126,10 @@
                                                               location)
                 # ^^^ non-translated
                 if caller.frame_address == llmemory.NULL:
-                    return self.teardown()    # completely done with this stack
+                    # completely done with this piece of stack
+                    if not self.fetch_next_stack_piece():
+                        return llmemory.NULL
+                    continue
                 #
                 self.otherframe = callee
                 self.curframe = caller
@@ -154,6 +166,7 @@
 SUSPSTACK = lltype.GcStruct('SuspStack',
                             ('handle', _c.handle),
                             ('anchor', llmemory.Address),
+                            ('callback_pieces', llmemory.Address),
                             rtti=True)
 NULL_SUSPSTACK = lltype.nullptr(SUSPSTACK)
 CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address],
@@ -185,6 +198,7 @@
     # stacklet with stacklet_new().  If this call fails, then we
     # are just returning NULL.
     _stack_just_closed()
+    #
     return _c.new(gcrootfinder.newthrd, llhelper(_c.run_fn, _new_runfn),
                   llmemory.NULL)
 
@@ -252,14 +266,36 @@
         newsuspstack.handle = _c.null_handle
         self.suspstack = newsuspstack
         # Invoke '_new_callback' by closing the stack
+        #
+        callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address)
+        newsuspstack.callback_pieces = callback_pieces
+        #
         h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _new_callback),
                                 alternateanchor)
+        #
+        llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces)
         return self.get_result_suspstack(h)
 
     def switch(self, suspstack):
+        # Immediately before the switch, 'suspstack' describes the suspended
+        # state of the *target* of the switch.  Then it is theoretically
+        # freed.  In fact what occurs is that we reuse the same 'suspstack'
+        # object in the target, just after the switch, to store the
+        # description of where we came from.  Then that "other" 'suspstack'
+        # object is returned.
         self.suspstack = suspstack
+        #
+        callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address)
+        old_callback_pieces = suspstack.callback_pieces
+        suspstack.callback_pieces = callback_pieces
+        #
         h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _switch_callback),
                                 alternateanchor)
+        #
+        llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces)
+        if not h:
+            self.suspstack.callback_pieces = old_callback_pieces
+        #
         return self.get_result_suspstack(h)
 
     def attach_handle_on_suspstack(self, handle):
diff --git a/rpython/rlib/rsre/rpy.py b/rpython/rlib/rsre/rpy.py
--- a/rpython/rlib/rsre/rpy.py
+++ b/rpython/rlib/rsre/rpy.py
@@ -8,11 +8,12 @@
     module is a custom module that has _sre.compile == my_compile
     and CODESIZE == rsre_char.CODESIZE.
     """
-    import sre_compile, __builtin__, new
+    import sre_compile, sre_constants, __builtin__, new
     sre_hacked = new.module("_sre_hacked")
     sre_hacked.compile = my_compile
     sre_hacked.MAGIC = sre_compile.MAGIC
     sre_hacked.CODESIZE = rsre_char.CODESIZE
+    sre_hacked.MAXREPEAT = sre_constants.MAX_REPEAT
     sre_hacked.getlower = rsre_char.getlower
     def my_import(name, *args):
         if name == '_sre':
diff --git a/rpython/rlib/rsre/rsre_re.py b/rpython/rlib/rsre/rsre_re.py
--- a/rpython/rlib/rsre/rsre_re.py
+++ b/rpython/rlib/rsre/rsre_re.py
@@ -4,7 +4,7 @@
 """
 import re, sys
 from rpython.rlib.rsre import rsre_core, rsre_char
-from rpython.rlib.rsre.test.test_match import get_code as _get_code
+from rpython.rlib.rsre.rpy import get_code as _get_code
 from rpython.rlib.unicodedata import unicodedb
 from rpython.rlib.objectmodel import specialize
 rsre_char.set_unicode_db(unicodedb)
@@ -176,7 +176,7 @@
     def span(self, groupnum=0):
 #        if not isinstance(groupnum, (int, long)):
 #            groupnum = self.re.groupindex[groupnum]
- 
+
         return self._ctx.span(groupnum)
 
     def start(self, groupnum=0):
diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py
--- a/rpython/rlib/test/test_rstacklet.py
+++ b/rpython/rlib/test/test_rstacklet.py
@@ -82,6 +82,29 @@
                 return True
         return False
 
+    @here_is_a_test
+    def test_c_callback(self):
+        #
+        self.steps = [0]
+        self.main_h = self.sthread.new(cb_stacklet_callback, llmemory.NULL)
+        self.steps.append(2)
+        call_qsort_rec(10)
+        self.steps.append(9)
+        assert not self.sthread.is_empty_handle(self.main_h)
+        self.main_h = self.sthread.switch(self.main_h)
+        assert self.sthread.is_empty_handle(self.main_h)
+        #
+        # check that self.steps == [0,1,2, 3,4,5,6, 3,4,5,6, 3,4,5,6,..., 9]
+        print self.steps
+        expected = 0
+        assert self.steps[-1] == 9
+        for i in range(len(self.steps)-1):
+            if expected == 7:
+                expected = 3
+            assert self.steps[i] == expected
+            expected += 1
+        assert expected == 7
+
 
 class FooObj:
     def __init__(self, n, d, next=None):
@@ -211,6 +234,43 @@
     print "LEAVING %d to go to %d" % (self.n, n)
     return h
 
+QSORT_CALLBACK_PTR = lltype.Ptr(lltype.FuncType(
+    [llmemory.Address, llmemory.Address], rffi.INT))
+qsort = rffi.llexternal('qsort',
+                        [llmemory.Address, rffi.SIZE_T, rffi.SIZE_T,
+                         QSORT_CALLBACK_PTR],
+                        lltype.Void)
+def cb_compare_callback(a, b):
+    runner.steps.append(3)
+    assert not runner.sthread.is_empty_handle(runner.main_h)
+    runner.main_h = runner.sthread.switch(runner.main_h)
+    assert not runner.sthread.is_empty_handle(runner.main_h)
+    runner.steps.append(6)
+    return rffi.cast(rffi.INT, 1)
+def cb_stacklet_callback(h, arg):
+    runner.steps.append(1)
+    while True:
+        assert not runner.sthread.is_empty_handle(h)
+        h = runner.sthread.switch(h)
+        assert not runner.sthread.is_empty_handle(h)
+        if runner.steps[-1] == 9:
+            return h
+        runner.steps.append(4)
+        rgc.collect()
+        runner.steps.append(5)
+class GcObject(object):
+    num = 1234
+def call_qsort_rec(r):
+    if r > 0:
+        g = GcObject()
+        g.num += r
+        call_qsort_rec(r - 1)
+        assert g.num == 1234 + r
+    else:
+        raw = llmemory.raw_malloc(5)
+        qsort(raw, 5, 1, cb_compare_callback)
+        llmemory.raw_free(raw)
+
 
 def entry_point(argv):
     seed = 0
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -886,6 +886,11 @@
     def op_gc_stack_bottom(self):
         pass       # marker for trackgcroot.py
 
+    def op_gc_detach_callback_pieces(self):
+        raise NotImplementedError("gc_detach_callback_pieces")
+    def op_gc_reattach_callback_pieces(self):
+        raise NotImplementedError("gc_reattach_callback_pieces")
+
     def op_gc_shadowstackref_new(self):   # stacklet+shadowstack
         raise NotImplementedError("gc_shadowstackref_new")
     def op_gc_shadowstackref_context(self):
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -516,6 +516,10 @@
     'gc_asmgcroot_static':  LLOp(sideeffects=False),
     'gc_stack_bottom':      LLOp(canrun=True),
 
+    # for stacklet+asmgcroot support
+    'gc_detach_callback_pieces': LLOp(),
+    'gc_reattach_callback_pieces': LLOp(),
+
     # for stacklet+shadowstack support
     'gc_shadowstackref_new':      LLOp(canmallocgc=True),
     'gc_shadowstackref_context':  LLOp(),
diff --git a/rpython/tool/sourcetools.py b/rpython/tool/sourcetools.py
--- a/rpython/tool/sourcetools.py
+++ b/rpython/tool/sourcetools.py
@@ -169,14 +169,14 @@
     try:
         co = compile2_cache[key]
         #print "***** duplicate code ******* "
-        #print source 
-    except KeyError: 
-        #if DEBUG: 
-        co = py.code.compile(source, filename, mode, flags) 
-        #else: 
-        #    co = compile(source, filename, mode, flags) 
-        compile2_cache[key] = co 
-    return co 
+        #print source
+    except KeyError:
+        #if DEBUG:
+        co = py.code.compile(source, filename, mode, flags)
+        #else:
+        #    co = compile(source, filename, mode, flags)
+        compile2_cache[key] = co
+    return co
 
 compile2_cache = {}
 
@@ -203,7 +203,7 @@
         localnames = locals.keys()
         localnames.sort()
     values = [locals[key] for key in localnames]
-    
+
     source = source.putaround(
         before = "def container(%s):" % (', '.join(localnames),),
         after  = "# no unindent\n    return %s" % resultname)
@@ -305,7 +305,7 @@
         items = [_convert_const_maybe(item, encoding) for item in x]
         return tuple(items)
     return x
-    
+
 def with_unicode_literals(fn=None, **kwds):
     """Decorator that replace all string literals with unicode literals.
     Similar to 'from __future__ import string literals' at function level.
diff --git a/rpython/translator/c/test/test_standalone.py b/rpython/translator/c/test/test_standalone.py
--- a/rpython/translator/c/test/test_standalone.py
+++ b/rpython/translator/c/test/test_standalone.py
@@ -1186,7 +1186,7 @@
         config = get_combined_translation_config(translating=True)
         self.config = config
 
-        @entrypoint('test', [lltype.Signed], relax=True, c_name='foo')
+        @entrypoint('test', [lltype.Signed], c_name='foo')
         def f(a):
             return a + 3
 


More information about the pypy-commit mailing list