[pypy-commit] pypy arm-backend-2: merge default

bivab noreply at buildbot.pypy.org
Sat Jul 16 17:12:56 CEST 2011


Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r45670:57c5578f3895
Date: 2011-07-15 15:02 +0200
http://bitbucket.org/pypy/pypy/changeset/57c5578f3895/

Log:	merge default

diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py
--- a/pypy/interpreter/astcompiler/misc.py
+++ b/pypy/interpreter/astcompiler/misc.py
@@ -27,9 +27,10 @@
     _emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset)
 
 
-def parse_future(tree):
+def parse_future(tree, feature_flags):
     future_lineno = 0
     future_column = 0
+    flags = 0
     have_docstring = False
     body = None
     if isinstance(tree, ast.Module):
@@ -37,7 +38,7 @@
     elif isinstance(tree, ast.Interactive):
         body = tree.body
     if body is None:
-        return 0, 0
+        return 0, 0, 0
     for stmt in body:
         if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str):
             if have_docstring:
@@ -48,11 +49,16 @@
             if stmt.module == "__future__":
                 future_lineno = stmt.lineno
                 future_column = stmt.col_offset
+                for alias in stmt.names:
+                    assert isinstance(alias, ast.alias)
+                    # If this is an invalid flag, it will be caught later in
+                    # codegen.py.
+                    flags |= feature_flags.get(alias.name, 0)
             else:
                 break
         else:
             break
-    return future_lineno, future_column
+    return flags, future_lineno, future_column
 
 
 class ForbiddenNameAssignment(Exception):
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -130,6 +130,9 @@
         raise operationerrfmt(space.w_TypeError,
             "cannot create weak reference to '%s' object", typename)
 
+    def delweakref(self):
+        pass
+
     def clear_all_weakrefs(self):
         """Call this at the beginning of interp-level __del__() methods
         in subclasses.  It ensures that weakrefs (if any) are cleared
@@ -143,29 +146,28 @@
             # app-level, e.g. a user-defined __del__(), and this code
             # tries to use weakrefs again, it won't reuse the broken
             # (already-cleared) weakrefs from this lifeline.
-            self.setweakref(lifeline.space, None)
+            self.delweakref()
             lifeline.clear_all_weakrefs()
 
-    __already_enqueued_for_destruction = False
+    __already_enqueued_for_destruction = ()
 
-    def _enqueue_for_destruction(self, space, call_user_del=True):
+    def enqueue_for_destruction(self, space, callback, descrname):
         """Put the object in the destructor queue of the space.
-        At a later, safe point in time, UserDelAction will use
-        space.userdel() to call the object's app-level __del__ method.
+        At a later, safe point in time, UserDelAction will call
+        callback(self).  If that raises OperationError, prints it
+        to stderr with the descrname string.
+
+        Note that 'callback' will usually need to start with:
+            assert isinstance(self, W_SpecificClass)
         """
         # this function always resurect the object, so when
         # running on top of CPython we must manually ensure that
         # we enqueue it only once
         if not we_are_translated():
-            if self.__already_enqueued_for_destruction:
+            if callback in self.__already_enqueued_for_destruction:
                 return
-            self.__already_enqueued_for_destruction = True
-        self.clear_all_weakrefs()
-        if call_user_del:
-            space.user_del_action.register_dying_object(self)
-
-    def _call_builtin_destructor(self):
-        pass     # method overridden in typedef.py
+            self.__already_enqueued_for_destruction += (callback,)
+        space.user_del_action.register_callback(self, callback, descrname)
 
     # hooks that the mapdict implementations needs:
     def _get_mapdict_map(self):
@@ -925,6 +927,9 @@
                 return self.w_True
         return self.w_False
 
+    def issequence_w(self, w_obj):
+        return (self.findattr(w_obj, self.wrap("__getitem__")) is not None)
+
     def isinstance_w(self, w_obj, w_type):
         return self.is_true(self.isinstance(w_obj, w_type))
 
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -484,44 +484,31 @@
 
     def __init__(self, space):
         AsyncAction.__init__(self, space)
-        self.dying_objects_w = []
-        self.weakrefs_w = []
+        self.dying_objects = []
         self.finalizers_lock_count = 0
 
-    def register_dying_object(self, w_obj):
-        self.dying_objects_w.append(w_obj)
-        self.fire()
-
-    def register_weakref_callback(self, w_ref):
-        self.weakrefs_w.append(w_ref)
+    def register_callback(self, w_obj, callback, descrname):
+        self.dying_objects.append((w_obj, callback, descrname))
         self.fire()
 
     def perform(self, executioncontext, frame):
         if self.finalizers_lock_count > 0:
             return
-        # Each call to perform() first grabs the self.dying_objects_w
+        # Each call to perform() first grabs the self.dying_objects
         # and replaces it with an empty list.  We do this to try to
         # avoid too deep recursions of the kind of __del__ being called
         # while in the middle of another __del__ call.
-        pending_w = self.dying_objects_w
-        self.dying_objects_w = []
+        pending = self.dying_objects
+        self.dying_objects = []
         space = self.space
-        for i in range(len(pending_w)):
-            w_obj = pending_w[i]
-            pending_w[i] = None
+        for i in range(len(pending)):
+            w_obj, callback, descrname = pending[i]
+            pending[i] = (None, None, None)
             try:
-                space.userdel(w_obj)
+                callback(w_obj)
             except OperationError, e:
-                e.write_unraisable(space, 'method __del__ of ', w_obj)
+                e.write_unraisable(space, descrname, w_obj)
                 e.clear(space)   # break up reference cycles
-            # finally, this calls the interp-level destructor for the
-            # cases where there is both an app-level and a built-in __del__.
-            w_obj._call_builtin_destructor()
-        pending_w = self.weakrefs_w
-        self.weakrefs_w = []
-        for i in range(len(pending_w)):
-            w_ref = pending_w[i]
-            w_ref.activate_callback()
 
 class FrameTraceAction(AsyncAction):
     """An action that calls the local trace functions (w_f_trace)."""
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -114,6 +114,7 @@
  
     def descr_close(self):
         """x.close(arg) -> raise GeneratorExit inside generator."""
+        assert isinstance(self, GeneratorIterator)
         space = self.space
         try:
             w_retval = self.throw(space.w_GeneratorExit, space.w_None,
@@ -141,22 +142,16 @@
         code_name = self.pycode.co_name
         return space.wrap(code_name)
 
-    def descr__del__(self):        
-        """
-        applevel __del__, which is called at a safe point after the
-        interp-level __del__ enqueued the object for destruction
-        """
-        self.descr_close()
-
     def __del__(self):
         # Only bother enqueuing self to raise an exception if the frame is
         # still not finished and finally or except blocks are present.
-        must_call_close = False
+        self.clear_all_weakrefs()
         if self.frame is not None:
             block = self.frame.lastblock
             while block is not None:
                 if not isinstance(block, LoopBlock):
-                    must_call_close = True
+                    self.enqueue_for_destruction(self.space,
+                                                 GeneratorIterator.descr_close,
+                                                 "interrupting generator of ")
                     break
                 block = block.previous
-        self._enqueue_for_destruction(self.space, must_call_close)
diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py
--- a/pypy/interpreter/pycompiler.py
+++ b/pypy/interpreter/pycompiler.py
@@ -119,7 +119,10 @@
             raise OperationError(self.space.w_TypeError, self.space.wrap(
                 "invalid node type"))
 
-        future_pos = misc.parse_future(node)
+        fut = misc.parse_future(node, self.future_flags.compiler_features)
+        f_flags, f_lineno, f_col = fut
+        future_pos = f_lineno, f_col
+        flags |= f_flags
         info = pyparse.CompileInfo(filename, mode, flags, future_pos)
         return self._compile_ast(node, info)
 
diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py
--- a/pypy/interpreter/test/test_typedef.py
+++ b/pypy/interpreter/test/test_typedef.py
@@ -1,3 +1,4 @@
+import gc
 from pypy.interpreter import typedef
 from pypy.tool.udir import udir
 from pypy.interpreter.baseobjspace import Wrappable
@@ -180,6 +181,85 @@
             assert err.value.message == "'some_type' objects are unhashable"
             """)
 
+    def test_destructor(self):
+        space = self.space
+        class W_Level1(Wrappable):
+            def __init__(self, space1):
+                assert space1 is space
+            def __del__(self):
+                space.call_method(w_seen, 'append', space.wrap(1))
+        class W_Level2(Wrappable):
+            def __init__(self, space1):
+                assert space1 is space
+            def __del__(self):
+                self.enqueue_for_destruction(space, W_Level2.destructormeth,
+                                             'FOO ')
+            def destructormeth(self):
+                space.call_method(w_seen, 'append', space.wrap(2))
+        W_Level1.typedef = typedef.TypeDef(
+            'level1',
+            __new__ = typedef.generic_new_descr(W_Level1))
+        W_Level2.typedef = typedef.TypeDef(
+            'level2',
+            __new__ = typedef.generic_new_descr(W_Level2))
+        #
+        w_seen = space.newlist([])
+        W_Level1(space)
+        gc.collect(); gc.collect()
+        assert space.unwrap(w_seen) == [1]
+        #
+        w_seen = space.newlist([])
+        W_Level2(space)
+        gc.collect(); gc.collect()
+        assert space.str_w(space.repr(w_seen)) == "[]"  # not called yet
+        ec = space.getexecutioncontext()
+        self.space.user_del_action.perform(ec, None)
+        assert space.unwrap(w_seen) == [2]
+        #
+        w_seen = space.newlist([])
+        self.space.appexec([self.space.gettypeobject(W_Level1.typedef)],
+        """(level1):
+            class A3(level1):
+                pass
+            A3()
+        """)
+        gc.collect(); gc.collect()
+        assert space.unwrap(w_seen) == [1]
+        #
+        w_seen = space.newlist([])
+        self.space.appexec([self.space.gettypeobject(W_Level1.typedef),
+                            w_seen],
+        """(level1, seen):
+            class A4(level1):
+                def __del__(self):
+                    seen.append(4)
+            A4()
+        """)
+        gc.collect(); gc.collect()
+        assert space.unwrap(w_seen) == [4, 1]
+        #
+        w_seen = space.newlist([])
+        self.space.appexec([self.space.gettypeobject(W_Level2.typedef)],
+        """(level2):
+            class A5(level2):
+                pass
+            A5()
+        """)
+        gc.collect(); gc.collect()
+        assert space.unwrap(w_seen) == [2]
+        #
+        w_seen = space.newlist([])
+        self.space.appexec([self.space.gettypeobject(W_Level2.typedef),
+                            w_seen],
+        """(level2, seen):
+            class A6(level2):
+                def __del__(self):
+                    seen.append(6)
+            A6()
+        """)
+        gc.collect(); gc.collect()
+        assert space.unwrap(w_seen) == [6, 2]
+
 
 class AppTestTypeDef:
 
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -228,21 +228,26 @@
                 return self._lifeline_
             def setweakref(self, space, weakreflifeline):
                 self._lifeline_ = weakreflifeline
+            def delweakref(self):
+                self._lifeline_ = None
         add(Proto)
 
     if "del" in features:
+        parent_destructor = getattr(supercls, '__del__', None)
+        def call_parent_del(self):
+            assert isinstance(self, subcls)
+            parent_destructor(self)
+        def call_applevel_del(self):
+            assert isinstance(self, subcls)
+            self.space.userdel(self)
         class Proto(object):
             def __del__(self):
-                self._enqueue_for_destruction(self.space)
-        # if the base class needs its own interp-level __del__,
-        # we override the _call_builtin_destructor() method to invoke it
-        # after the app-level destructor.
-        parent_destructor = getattr(supercls, '__del__', None)
-        if parent_destructor is not None:
-            def _call_builtin_destructor(self):
-                parent_destructor(self)
-            Proto._call_builtin_destructor = _call_builtin_destructor
-
+                self.clear_all_weakrefs()
+                self.enqueue_for_destruction(self.space, call_applevel_del,
+                                             'method __del__ of ')
+                if parent_destructor is not None:
+                    self.enqueue_for_destruction(self.space, call_parent_del,
+                                                 'internal destructor of ')
         add(Proto)
 
     if "slots" in features:
@@ -630,9 +635,12 @@
         return self._lifeline_
     def setweakref(self, space, weakreflifeline):
         self._lifeline_ = weakreflifeline
+    def delweakref(self):
+        self._lifeline_ = None
     cls._lifeline_ = None
     cls.getweakref = getweakref
     cls.setweakref = setweakref
+    cls.delweakref = delweakref
     return weakref_descr
 
 
@@ -858,8 +866,6 @@
                             descrmismatch='close'),
     __iter__   = interp2app(GeneratorIterator.descr__iter__,
                             descrmismatch='__iter__'),
-    __del__    = interp2app(GeneratorIterator.descr__del__,
-                            descrmismatch='__del__'),
     gi_running = interp_attrproperty('running', cls=GeneratorIterator),
     gi_frame   = GetSetProperty(GeneratorIterator.descr_gi_frame),
     gi_code    = GetSetProperty(GeneratorIterator.descr_gi_code),
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
@@ -482,7 +482,7 @@
         #
         rawstart = self.materialize_loop(original_loop_token)
         debug_start("jit-backend-addr")
-        debug_print("Bridge out of Guard %d has address %x to %x" %
+        debug_print("bridge out of Guard %d has address %x to %x" %
                     (descr_number, rawstart, rawstart + codeendpos))
         debug_stop("jit-backend-addr")
         self._patch_stackadjust(rawstart + stackadjustpos,
diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py
--- a/pypy/jit/backend/x86/test/test_regloc.py
+++ b/pypy/jit/backend/x86/test/test_regloc.py
@@ -24,9 +24,14 @@
     assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8')  # 11 011 000
     assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3')  # 11 000 011
     assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9')
-    # XXX: What we are testing for here is actually not the most compact
-    # encoding.
-    assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30')
+    assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30')
+    # for the next case we don't pick the most efficient encoding, but well
+    expected = '\x66\x40\xC7\xC1\xC7\xCF'  # could be '\x66\xB9\xC7\xCF'
+    assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected)
+    assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30')
+    # for the next case we don't pick the most efficient encoding, but well
+    expected = '\x66\x41\xC7\xC1\xC7\xCF'  # could be '\x66\x41\xB9\xC7\xCF'
+    assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected)
     assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30')
 
 def test_cmp_16():
@@ -44,7 +49,7 @@
 def test_relocation():
     from pypy.rpython.lltypesystem import lltype, rffi
     from pypy.jit.backend.x86 import codebuf
-    for target in [0x01020304, 0x0102030405060708]:
+    for target in [0x01020304, -0x05060708, 0x0102030405060708]:
         if target > sys.maxint:
             continue
         mc = codebuf.MachineCodeBlockWrapper()
@@ -58,10 +63,15 @@
             expected = "\xE8" + struct.pack('<i', target - (rawstart + 5))
         elif IS_X86_64:
             assert mc.relocations == []
-            if target <= 0x7fffffff:
+            if 0 <= target <= 0xffffffff:
+                assert length == 9
+                expected = (
+                    "\x41\xBB\x04\x03\x02\x01"      # MOV %r11, target
+                    "\x41\xFF\xD3")                 # CALL *%r11
+            elif -0x80000000 <= target < 0:
                 assert length == 10
                 expected = (
-                    "\x49\xC7\xC3\x04\x03\x02\x01"  # MOV %r11, target
+                    "\x49\xC7\xC3\xF8\xF8\xF9\xFA"  # MOV %r11, target
                     "\x41\xFF\xD3")                 # CALL *%r11
             else:
                 assert length == 13
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -765,13 +765,65 @@
             raise NotImplementedError("cast_ptr_to_int")
 
     def rewrite_op_force_cast(self, op):
-        from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof
+        assert not self._is_gc(op.args[0])
+        fromll = longlong.is_longlong(op.args[0].concretetype)
+        toll   = longlong.is_longlong(op.result.concretetype)
+        if fromll and toll:
+            return
+        if fromll:
+            args = op.args
+            opname = 'truncate_longlong_to_int'
+            RESULT = lltype.Signed
+            v = varoftype(RESULT)
+            op1 = SpaceOperation(opname, args, v)
+            op2 = self.rewrite_operation(op1)
+            oplist = self.force_cast_without_longlong(op2.result, op.result)
+            if oplist:
+                return [op2] + oplist
+            #
+            # force a renaming to put the correct result in place, even though
+            # it might be slightly mistyped (e.g. Signed versus Unsigned)
+            assert op2.result is v
+            op2.result = op.result
+            return op2
+        elif toll:
+            from pypy.rpython.lltypesystem import rffi
+            size, unsigned = rffi.size_and_sign(op.args[0].concretetype)
+            if unsigned:
+                INTERMEDIATE = lltype.Unsigned
+            else:
+                INTERMEDIATE = lltype.Signed
+            v = varoftype(INTERMEDIATE)
+            oplist = self.force_cast_without_longlong(op.args[0], v)
+            if not oplist:
+                v = op.args[0]
+                oplist = []
+            if unsigned:
+                opname = 'cast_uint_to_longlong'
+            else:
+                opname = 'cast_int_to_longlong'
+            op1 = SpaceOperation(opname, [v], op.result)
+            op2 = self.rewrite_operation(op1)
+            return oplist + [op2]
+        else:
+            return self.force_cast_without_longlong(op.args[0], op.result)
+
+    def force_cast_without_longlong(self, v_arg, v_result):
+        from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT
         from pypy.rlib.rarithmetic import intmask
-        assert not self._is_gc(op.args[0])
-        size2, unsigned2 = size_and_sign(op.result.concretetype)
-        if size2 >= sizeof(lltype.Signed):
+        #
+        if (v_result.concretetype in (FLOAT, lltype.Float) or
+            v_arg.concretetype in (FLOAT, lltype.Float)):
+            assert (v_result.concretetype == lltype.Float and
+                    v_arg.concretetype == lltype.Float), "xxx unsupported cast"
+            return
+        #
+        size2, unsigned2 = size_and_sign(v_result.concretetype)
+        assert size2 <= sizeof(lltype.Signed)
+        if size2 == sizeof(lltype.Signed):
             return     # the target type is LONG or ULONG
-        size1, unsigned1 = size_and_sign(op.args[0].concretetype)
+        size1, unsigned1 = size_and_sign(v_arg.concretetype)
+        assert size1 <= sizeof(lltype.Signed)
         #
         def bounds(size, unsigned):
             if unsigned:
@@ -784,20 +836,19 @@
             return     # the target type includes the source range
         #
         result = []
-        v1 = op.args[0]
         if min2:
             c_min2 = Constant(min2, lltype.Signed)
-            v2 = Variable(); v2.concretetype = lltype.Signed
-            result.append(SpaceOperation('int_sub', [v1, c_min2], v2))
+            v2 = varoftype(lltype.Signed)
+            result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2))
         else:
-            v2 = v1
+            v2 = v_arg
         c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed)
-        v3 = Variable(); v3.concretetype = lltype.Signed
+        v3 = varoftype(lltype.Signed)
         result.append(SpaceOperation('int_and', [v2, c_mask], v3))
         if min2:
-            result.append(SpaceOperation('int_add', [v3, c_min2], op.result))
+            result.append(SpaceOperation('int_add', [v3, c_min2], v_result))
         else:
-            result[-1].result = op.result
+            result[-1].result = v_result
         return result
 
     def rewrite_op_direct_ptradd(self, op):
@@ -890,30 +941,7 @@
     rewrite_op_ullong_is_true = rewrite_op_llong_is_true
 
     def rewrite_op_cast_primitive(self, op):
-        fromll = longlong.is_longlong(op.args[0].concretetype)
-        toll   = longlong.is_longlong(op.result.concretetype)
-        if fromll != toll:
-            args = op.args
-            if fromll:
-                opname = 'truncate_longlong_to_int'
-                RESULT = lltype.Signed
-            else:
-                from pypy.rpython.lltypesystem import rffi
-                if rffi.cast(op.args[0].concretetype, -1) < 0:
-                    opname = 'cast_int_to_longlong'
-                else:
-                    opname = 'cast_uint_to_longlong'
-                RESULT = lltype.SignedLongLong
-            v = varoftype(RESULT)
-            op1 = SpaceOperation(opname, args, v)
-            op2 = self.rewrite_operation(op1)
-            #
-            # force a renaming to put the correct result in place, even though
-            # it might be slightly mistyped (e.g. Signed versus Unsigned)
-            assert op2.result is v
-            op2.result = op.result
-            #
-            return op2
+        return self.rewrite_op_force_cast(op)
 
     # ----------
     # Renames, from the _old opname to the _new one.
@@ -1247,7 +1275,7 @@
         calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
                                                   extraeffect)
         if extraeffect is not None:
-            assert (type(calldescr) is str      # for tests
+            assert (is_test_calldescr(calldescr)      # for tests
                     or calldescr.get_extra_info().extraeffect == extraeffect)
         if isinstance(op.args[0].value, str):
             pass  # for tests only
@@ -1408,6 +1436,9 @@
         return "using virtualizable array in illegal way in %r" % (
             self.args[0],)
 
+def is_test_calldescr(calldescr):
+    return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False)
+
 def _with_prefix(prefix):
     result = {}
     for name in dir(Transformer):
diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py
--- a/pypy/jit/codewriter/regalloc.py
+++ b/pypy/jit/codewriter/regalloc.py
@@ -96,6 +96,7 @@
 
     def _try_coalesce(self, v, w):
         if isinstance(v, Variable) and getkind(v.concretetype) == self.kind:
+            assert getkind(w.concretetype) == self.kind
             dg = self._depgraph
             uf = self._unionfind
             v0 = uf.find_rep(v)
diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py
--- a/pypy/jit/codewriter/test/test_flatten.py
+++ b/pypy/jit/codewriter/test/test_flatten.py
@@ -3,6 +3,7 @@
 from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list
 from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register
 from pypy.jit.codewriter.format import assert_format
+from pypy.jit.codewriter import longlong
 from pypy.jit.metainterp.history import AbstractDescr
 from pypy.rpython.lltypesystem import lltype, rclass, rstr
 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
@@ -30,6 +31,9 @@
             'float': FakeRegAlloc()}
 
 class FakeDescr(AbstractDescr):
+    _for_tests_only = True
+    def __init__(self, oopspecindex=None):
+        self.oopspecindex = oopspecindex
     def __repr__(self):
         return '<Descr>'
     def as_vtable_size_descr(self):
@@ -55,19 +59,24 @@
     def arraydescrof(self, ARRAY):
         return FakeDescr()
 
+class FakeCallInfoCollection:
+    def add(self, *args):
+        pass
+
 class FakeCallControl:
     _descr_cannot_raise = FakeDescr()
+    callinfocollection = FakeCallInfoCollection()
     def guess_call_kind(self, op):
         return 'residual'
-    def getcalldescr(self, op):
+    def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
         try:
             if 'cannot_raise' in op.args[0].value._obj.graph.name:
                 return self._descr_cannot_raise
         except AttributeError:
             pass
-        return FakeDescr()
+        return FakeDescr(oopspecindex)
     def calldescr_canraise(self, calldescr):
-        return calldescr is not self._descr_cannot_raise
+        return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None
     def get_vinfo(self, VTYPEPTR):
         return None
 
@@ -734,7 +743,9 @@
 
     def test_force_cast(self):
         from pypy.rpython.lltypesystem import rffi
-
+        # NB: we don't need to test for INT here, the logic in jtransform is
+        # general enough so that if we have the below cases it should
+        # generalize also to INT
         for FROM, TO, expected in [
             (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""),
             (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"),
@@ -797,14 +808,44 @@
             expected = [s.strip() for s in expected.splitlines()]
             check_force_cast(FROM, TO, expected, 42)
             check_force_cast(FROM, TO, expected, -42)
-            expected.append('int_return %i' + str(len(expected)))
-            expected = '\n'.join(expected)
+            returnvar = "%i" + str(len(expected))
+            expected.append('int_return ' + returnvar)
+            expectedstr = '\n'.join(expected)
             #
             def f(n):
                 return rffi.cast(TO, n)
-            self.encoding_test(f, [rffi.cast(FROM, 42)], expected,
+            self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
                                transform=True)
 
+            if not longlong.is_64_bit:
+                if FROM in (rffi.LONG, rffi.ULONG):
+                    if FROM == rffi.LONG:
+                        FROM = rffi.LONGLONG
+                    else:
+                        FROM = rffi.ULONGLONG
+                    expected.insert(0,
+                        "residual_call_irf_i $<* fn llong_to_int>, <Descr>, I[], R[], F[%f0] -> %i0")
+                    expectedstr = '\n'.join(expected)
+                    self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
+                                       transform=True)
+                elif TO in (rffi.LONG, rffi.ULONG):
+                    if TO == rffi.LONG:
+                        TO = rffi.LONGLONG
+                    else:
+                        TO = rffi.ULONGLONG
+                    if rffi.cast(FROM, -1) < 0:
+                        fnname = "llong_from_int"
+                    else:
+                        fnname = "llong_from_uint"
+                    expected.pop()   # remove int_return
+                    expected.append(
+                        "residual_call_irf_f $<* fn %s>, <Descr>, I[%s], R[], F[] -> %%f0"
+                        % (fnname, returnvar))
+                    expected.append("float_return %f0")
+                    expectedstr = '\n'.join(expected)
+                    self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
+                                       transform=True)
+
     def test_force_cast_pointer(self):
         from pypy.rpython.lltypesystem import rffi
         def h(p):
@@ -813,6 +854,14 @@
             int_return %i0
         """, transform=True)
 
+    def test_force_cast_float(self):
+        from pypy.rpython.lltypesystem import rffi
+        def f(n):
+            return rffi.cast(lltype.Float, n)
+        self.encoding_test(f, [12.456], """
+            float_return %f0
+        """, transform=True)
+
     def test_direct_ptradd(self):
         from pypy.rpython.lltypesystem import rffi
         def f(p, n):
diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py
--- a/pypy/jit/codewriter/test/test_longlong.py
+++ b/pypy/jit/codewriter/test/test_longlong.py
@@ -37,7 +37,7 @@
 
 class TestLongLong:
     def setup_class(cls):
-        if sys.maxint > 2147483647:
+        if longlong.is_64_bit:
             py.test.skip("only for 32-bit platforms")
 
     def do_check(self, opname, oopspecindex, ARGS, RESULT):
@@ -46,6 +46,8 @@
         op = SpaceOperation(opname, vlist, v_result)
         tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
         op1 = tr.rewrite_operation(op)
+        if isinstance(op1, list):
+            [op1] = op1
         #
         def is_llf(TYPE):
             return (TYPE == lltype.SignedLongLong or
@@ -196,6 +198,23 @@
             for T2 in [lltype.Signed, lltype.Unsigned]:
                 self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT,
                               [T1], T2)
+                self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT,
+                              [T1], T2)
+                if T2 == lltype.Signed:
+                    expected = EffectInfo.OS_LLONG_FROM_INT
+                else:
+                    expected = EffectInfo.OS_LLONG_FROM_UINT
+                self.do_check('cast_primitive', expected, [T2], T1)
+                self.do_check('force_cast', expected, [T2], T1)
+        #
+        for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
+            for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
+                vlist = [varoftype(T1)]
+                v_result = varoftype(T2)
+                op = SpaceOperation('force_cast', vlist, v_result)
+                tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+                op1 = tr.rewrite_operation(op)
+                assert op1 is None
 
     def test_constants(self):
         for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py
--- a/pypy/jit/metainterp/optimizeopt/util.py
+++ b/pypy/jit/metainterp/optimizeopt/util.py
@@ -21,7 +21,7 @@
             continue
         if hasattr(Class, name_prefix + name):
             opclass = resoperation.opclasses[getattr(rop, name)]
-            print value, name, opclass
+            assert name in opclass.__name__
             result.append((value, opclass, getattr(Class, name_prefix + name)))
     return unrolling_iterable(result)
 
diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py
--- a/pypy/module/_ast/test/test_ast.py
+++ b/pypy/module/_ast/test/test_ast.py
@@ -186,6 +186,11 @@
         mod = self.get_ast("from __future__ import with_statement; import y; " \
                                "from __future__ import nested_scopes")
         raises(SyntaxError, compile, mod, "<test>", "exec")
+        mod = self.get_ast("from __future__ import division\nx = 1/2")
+        co = compile(mod, "<test>", "exec")
+        ns = {}
+        exec co in ns
+        assert ns["x"] == .5
 
     def test_field_attr_writable(self):
         import _ast as ast
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -43,11 +43,17 @@
         # assume that the file and stream objects are only visible in the
         # thread that runs __del__, so no race condition should be possible
         self.clear_all_weakrefs()
+        if self.stream is not None:
+            self.enqueue_for_destruction(self.space, W_File.destructor,
+                                         'close() method of ')
+
+    def destructor(self):
+        assert isinstance(self, W_File)
         try:
             self.direct_close()
         except StreamErrors, e:
             operr = wrap_streamerror(self.space, e, self.w_name)
-            operr.write_unraisable(self.space, '__del__ of ', self)
+            raise operr
 
     def fdopenstream(self, stream, fd, mode, w_name=None):
         self.fd = fd
diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py
--- a/pypy/module/_io/interp_iobase.py
+++ b/pypy/module/_io/interp_iobase.py
@@ -57,6 +57,11 @@
 
     def __del__(self):
         self.clear_all_weakrefs()
+        self.enqueue_for_destruction(self.space, W_IOBase.destructor,
+                                     'internal __del__ of ')
+
+    def destructor(self):
+        assert isinstance(self, W_IOBase)
         space = self.space
         w_closed = space.findattr(self, space.wrap('closed'))
         try:
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -10,7 +10,7 @@
 
 class WeakrefLifeline(W_Root):
     def __init__(self, space):
-        self.space = space       # this is here for W_Root.clear_all_weakrefs()
+        self.space = space
         self.refs_weak = []
         self.cached_weakref_index = -1
         self.cached_proxy_index = -1
@@ -23,8 +23,10 @@
         """
         for i in range(len(self.refs_weak) - 1, -1, -1):
             w_ref = self.refs_weak[i]()
-            if w_ref is not None:
-                self.space.user_del_action.register_weakref_callback(w_ref)
+            if w_ref is not None and w_ref.w_callable is not None:
+                w_ref.enqueue_for_destruction(self.space,
+                                              W_WeakrefBase.activate_callback,
+                                              'weakref callback of ')
 
     def clear_all_weakrefs(self):
         """Clear all weakrefs.  This is called when an app-level object has
@@ -118,11 +120,8 @@
         self.w_obj_weak = dead_ref
 
     def activate_callback(w_self):
-        if not w_self.w_callable is None:
-            try:
-                w_self.space.call_function(w_self.w_callable, w_self)
-            except OperationError, e:
-                e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable)
+        assert isinstance(w_self, W_WeakrefBase)
+        w_self.space.call_function(w_self.w_callable, w_self)
 
     def descr__repr__(self, space):
         w_obj = self.dereference()
diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py
--- a/pypy/module/bz2/test/test_bz2_file.py
+++ b/pypy/module/bz2/test/test_bz2_file.py
@@ -133,6 +133,7 @@
         
         bz2f.seek(0)
         assert bz2f.tell() == 0
+        del bz2f   # delete from this frame, which is captured in the traceback
 
     def test_open_close_del(self):
         from bz2 import BZ2File
@@ -246,11 +247,18 @@
         assert text_read == self.TEXT
         bz2f.close()
 
+    def test_silently_closes(self):
+        from bz2 import BZ2File
+        self.create_broken_temp_file()
+        BZ2File(self.temppath)
+        # check that no C-level malloc is left behind
+
     def test_read_broken_file(self):
         from bz2 import BZ2File
         self.create_broken_temp_file()
         bz2f = BZ2File(self.temppath)
         raises(EOFError, bz2f.read)
+        del bz2f   # delete from this frame, which is captured in the traceback
 
     def test_subsequent_read_broken_file(self):
         from bz2 import BZ2File
@@ -264,6 +272,7 @@
                 raise Exception("should generate EOFError earlier")
         except EOFError:
             pass
+        del bz2f   # delete from this frame, which is captured in the traceback
 
     def test_read_chunk10(self):
         from bz2 import BZ2File
@@ -416,6 +425,7 @@
         bz2f.close()
         bz2f = BZ2File(self.temppath, 'r')
         assert bz2f.read() == self.random_data
+        del bz2f   # delete from this frame, which is captured in the traceback
 
     def test_context_manager(self):
         from bz2 import BZ2File
diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,7 +29,7 @@
 #define PY_VERSION		"2.7.1"
 
 /* PyPy version as a string */
-#define PYPY_VERSION "1.5.0"
+#define PYPY_VERSION "1.6.0"
 
 /* Subversion Revision number of this file (not of the repository) */
 #define PY_PATCHLEVEL_REVISION  "$Revision: 77872 $"
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -22,7 +22,7 @@
 def PySequence_Check(space, w_obj):
     """Return 1 if the object provides sequence protocol, and 0 otherwise.
     This function always succeeds."""
-    return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None)
+    return int(space.issequence_w(w_obj))
 
 @cpython_api([PyObject], Py_ssize_t, error=-1)
 def PySequence_Size(space, w_obj):
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -1,5 +1,5 @@
 from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable
-from pypy.interpreter.error import operationerrfmt, OperationError
+from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.rlib import jit
@@ -7,7 +7,6 @@
 from pypy.tool.sourcetools import func_with_new_name
 import math
 
-
 def dummy1(v):
     assert isinstance(v, float)
     return v
@@ -88,23 +87,15 @@
     def _binop_impl(function):
         signature = Signature()
         def impl(self, space, w_other):
+            w_other = convert_to_array(space, w_other)
             new_sig = self.signature.transition(signature)
-            if isinstance(w_other, BaseArray):
-                res = Call2(
-                    function,
-                    self,
-                    w_other,
-                    new_sig.transition(w_other.signature)
-                )
-                w_other.invalidates.append(res)
-            else:
-                w_other = FloatWrapper(space.float_w(w_other))
-                res = Call2(
-                    function,
-                    self,
-                    w_other,
-                    new_sig.transition(w_other.signature)
-                )
+            res = Call2(
+                function,
+                self,
+                w_other,
+                new_sig.transition(w_other.signature)
+            )
+            w_other.invalidates.append(res)
             self.invalidates.append(res)
             return space.wrap(res)
         return func_with_new_name(impl, "binop_%s_impl" % function.__name__)
@@ -272,6 +263,16 @@
     def descr_mean(self, space):
         return space.wrap(space.float_w(self.descr_sum(space))/self.find_size())
 
+def convert_to_array (space, w_obj):
+    if isinstance(w_obj, BaseArray):
+        return w_obj
+    elif space.issequence_w(w_obj):
+        # Convert to array.
+        return new_numarray(space, w_obj)
+    else:
+        # If it's a scalar
+        return FloatWrapper(space.float_w(w_obj))
+
 class FloatWrapper(BaseArray):
     """
     Intermediate class representing a float literal.
@@ -478,14 +479,17 @@
     def __del__(self):
         lltype.free(self.storage, flavor='raw')
 
-def descr_new_numarray(space, w_type, w_size_or_iterable):
+def new_numarray(space, w_size_or_iterable):
     l = space.listview(w_size_or_iterable)
     arr = SingleDimArray(len(l))
     i = 0
     for w_elem in l:
         arr.storage[i] = space.float_w(space.float(w_elem))
         i += 1
-    return space.wrap(arr)
+    return arr
+
+def descr_new_numarray(space, w_type, w_size_or_iterable):
+    return space.wrap(new_numarray(space, w_size_or_iterable))
 
 @unwrap_spec(size=int)
 def zeros(space, size):
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -1,31 +1,35 @@
 import math
 
 from pypy.interpreter.gateway import unwrap_spec
-from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature
+from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array
 from pypy.rlib import rfloat
 from pypy.tool.sourcetools import func_with_new_name
 
-
 def ufunc(func):
     signature = Signature()
     def impl(space, w_obj):
-        if isinstance(w_obj, BaseArray):
-            w_res = Call1(func, w_obj, w_obj.signature.transition(signature))
-            w_obj.invalidates.append(w_res)
+        if space.issequence_w(w_obj):
+            w_obj_arr = convert_to_array(space, w_obj)
+            w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature))
+            w_obj_arr.invalidates.append(w_res)
             return w_res
-        return space.wrap(func(space.float_w(w_obj)))
+        else:
+            return space.wrap(func(space.float_w(w_obj)))
     return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
 
 def ufunc2(func):
     signature = Signature()
     def impl(space, w_lhs, w_rhs):
-        if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray):
-            new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature)
-            w_res = Call2(func, w_lhs, w_rhs, new_sig)
-            w_lhs.invalidates.append(w_res)
-            w_rhs.invalidates.append(w_res)
+        if space.issequence_w(w_lhs) or space.issequence_w(w_rhs):
+            w_lhs_arr = convert_to_array(space, w_lhs)
+            w_rhs_arr = convert_to_array(space, w_rhs)
+            new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature)
+            w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig)
+            w_lhs_arr.invalidates.append(w_res)
+            w_rhs_arr.invalidates.append(w_res)
             return w_res
-        return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs)))
+        else:
+            return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs)))
     return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
 
 @ufunc
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -1,12 +1,10 @@
 from pypy.conftest import gettestobjspace
 from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper
 
-
 class BaseNumpyAppTest(object):
     def setup_class(cls):
         cls.space = gettestobjspace(usemodules=('micronumpy',))
 
-
 class TestSignature(object):
     def test_binop_signature(self, space):
         ar = SingleDimArray(10)
@@ -26,4 +24,4 @@
 
         v3 = ar.descr_add(space, v1)
         v4 = ar.descr_add(space, v2)
-        assert v3.signature is v4.signature
\ No newline at end of file
+        assert v3.signature is v4.signature
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -97,6 +97,15 @@
         for i in range(5):
             assert b[i] == i + 5
 
+    def test_add_list(self):
+        from numpy import array
+        a = array(range(5))
+        b = list(reversed(range(5)))
+        c = a + b
+        assert isinstance(c, array)
+        for i in range(5):
+            assert c[i] == 4
+
     def test_subtract(self):
         from numpy import array
         a = array(range(5))
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -10,6 +10,40 @@
         assert sign(-0.0) == 0.0
         assert minimum(2.0, 3.0) == 2.0
 
+    def test_sequence(self):
+        from numpy import array, negative, minimum
+        a = array(range(3))
+        b = [2.0, 1.0, 0.0]
+        c = 1.0
+        b_neg = negative(b)
+        assert isinstance(b_neg, array)
+        for i in range(3):
+            assert b_neg[i] == -b[i]
+        min_a_b = minimum(a, b)
+        assert isinstance(min_a_b, array)
+        for i in range(3):
+            assert min_a_b[i] == min(a[i], b[i])
+        min_b_a = minimum(b, a)
+        assert isinstance(min_b_a, array)
+        for i in range(3):
+            assert min_b_a[i] == min(a[i], b[i])
+        min_a_c = minimum(a, c)
+        assert isinstance(min_a_c, array)
+        for i in range(3):
+            assert min_a_c[i] == min(a[i], c)
+        min_c_a = minimum(c, a)
+        assert isinstance(min_c_a, array)
+        for i in range(3):
+            assert min_c_a[i] == min(a[i], c)
+        min_b_c = minimum(b, c)
+        assert isinstance(min_b_c, array)
+        for i in range(3):
+            assert min_b_c[i] == min(b[i], c)
+        min_c_b = minimum(c, b)
+        assert isinstance(min_c_b, array)
+        for i in range(3):
+            assert min_c_b[i] == min(b[i], c)
+
     def test_negative(self):
         from numpy import array, negative
 
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -8,9 +8,16 @@
 
 class FakeSpace(object):
     w_ValueError = None
+
+    def issequence_w(self, w_obj):
+        return True
+
     @specialize.argtype(1)
-    def wrap(self, v):
-        return v
+    def wrap(self, w_obj):
+        return w_obj
+
+    def float_w(self, w_obj):
+        return float(w_obj)
 
 class TestNumpyJIt(LLJitMixin):
     def setup_class(cls):
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -476,7 +476,7 @@
         assert isinstance(vi[0], int)
         assert isinstance(vi[1], int)
         assert isinstance(vi[2], int)
-        assert vi[3] in ("alpha", "beta", "candidate", "final")
+        assert vi[3] in ("alpha", "beta", "candidate", "dev", "final")
         assert isinstance(vi[4], int)
 
     def test_allattributes(self):
@@ -523,4 +523,4 @@
 
         # If this ever actually becomes a compilation option this test should
         # be changed.
-        assert sys.float_repr_style == "short"
\ No newline at end of file
+        assert sys.float_repr_style == "short"
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -10,7 +10,7 @@
 CPYTHON_VERSION            = (2, 7, 1, "final", 42)   #XXX # sync patchlevel.h
 CPYTHON_API_VERSION        = 1013   #XXX # sync with include/modsupport.h
 
-PYPY_VERSION               = (1, 5, 0, "alpha", 0)    #XXX # sync patchlevel.h
+PYPY_VERSION               = (1, 6, 0, "dev", 1)    #XXX # sync patchlevel.h
 
 if platform.name == 'msvc':
     COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600)
diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py
--- a/pypy/module/thread/ll_thread.py
+++ b/pypy/module/thread/ll_thread.py
@@ -21,6 +21,7 @@
                       'RPyThreadAcquireLock', 'RPyThreadReleaseLock',
                       'RPyThreadYield',
                       'RPyThreadGetStackSize', 'RPyThreadSetStackSize',
+                      'RPyOpaqueDealloc_ThreadLock',
                       'RPyThreadAfterFork']
 )
 
@@ -52,6 +53,9 @@
 
 c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT,
                                 threadsafe=False)   # may add in a global list
+c_thread_lock_dealloc = llexternal('RPyOpaqueDealloc_ThreadLock', [TLOCKP],
+                                  lltype.Void,
+                                  threadsafe=True)
 c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT],
                                   rffi.INT,
                                   threadsafe=True)    # release the GIL
@@ -120,7 +124,7 @@
 
     def __enter__(self):
         self.acquire(True)
-        
+
     def __exit__(self, *args):
         self.release()
 
@@ -156,6 +160,9 @@
     return ll_lock
 
 def free_ll_lock(ll_lock):
+    c_thread_acquirelock(ll_lock, 0)
+    c_thread_releaselock(ll_lock)
+    c_thread_lock_dealloc(ll_lock)
     lltype.free(ll_lock, flavor='raw', track_allocation=False)
 
 def acquire_NOAUTO(ll_lock, flag):
diff --git a/pypy/module/thread/test/test_import_lock.py b/pypy/module/thread/test/test_import_lock.py
--- a/pypy/module/thread/test/test_import_lock.py
+++ b/pypy/module/thread/test/test_import_lock.py
@@ -66,6 +66,9 @@
     def test_lock(self, space, monkeypatch):
         from pypy.module.imp.importing import getimportlock, importhook
 
+        # Force importing the module _file now
+        space.builtin.get('file')
+
         # Monkeypatch the import lock and add a counter
         importlock = getimportlock(space)
         original_acquire = importlock.acquire_lock
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -431,12 +431,17 @@
             return None
         assert isinstance(lifeline, WeakrefLifeline)
         return lifeline
+    getweakref._cannot_really_call_random_things_ = True
 
     def setweakref(self, space, weakreflifeline):
         from pypy.module._weakref.interp__weakref import WeakrefLifeline
-        assert (isinstance(weakreflifeline, WeakrefLifeline) or
-                    weakreflifeline is None)
+        assert isinstance(weakreflifeline, WeakrefLifeline)
         self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline)
+    setweakref._cannot_really_call_random_things_ = True
+
+    def delweakref(self):
+        self._get_mapdict_map().write(self, ("weakref", SPECIAL), None)
+    delweakref._cannot_really_call_random_things_ = True
 
 class ObjectMixin(object):
     _mixin_ = True
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -36,6 +36,8 @@
         return self._lifeline_
     def setweakref(self, space, weakreflifeline):
         self._lifeline_ = weakreflifeline
+    def delweakref(self):
+        self._lifeline_ = None
 
 class W_SetObject(W_BaseSetObject):
     from pypy.objspace.std.settype import set_typedef as typedef
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -171,7 +171,7 @@
     obj = c.instantiate()
     assert obj.getweakref() is None
     obj.setweakref(space, lifeline1)
-    obj.setweakref(space, None)
+    obj.delweakref()
 
 
 
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -532,6 +532,8 @@
         return self._lifeline_
     def setweakref(self, space, weakreflifeline):
         self._lifeline_ = weakreflifeline
+    def delweakref(self):
+        self._lifeline_ = None
 
 # ____________________________________________________________
 # Initialization of type objects
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -482,6 +482,13 @@
                                    key[2:])
             cache[key] = s_value
 
+        # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass)
+        try:
+            graph = self.bookkeeper.position_key[0]
+            graph.func._dont_reach_me_in_del_ = True
+        except (TypeError, AttributeError):
+            pass
+
         return annmodel.s_None
 
     def annotate_hooks(self, **kwds_s):
diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py
--- a/pypy/rlib/test/test_jit.py
+++ b/pypy/rlib/test/test_jit.py
@@ -83,6 +83,9 @@
 
         t, rtyper, fngraph = self.gengraph(fn, [int])
 
+        # added by compute_result_annotation()
+        assert fn._dont_reach_me_in_del_ == True
+
         def getargs(func):
             for graph in t.graphs:
                 if getattr(graph, 'func', None) is func:
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -172,17 +172,6 @@
     assert max_n >= 0
     ITEM = A.OF
     ctypes_item = get_ctypes_type(ITEM, delayed_builders)
-    # Python 2.5 ctypes can raise OverflowError on 64-bit builds
-    for n in [sys.maxint, 2**31]:
-        MAX_SIZE = n/64
-        try:
-            PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item)
-        except OverflowError, e:
-            pass
-        else:
-            break
-    else:
-        raise e
 
     class CArray(ctypes.Structure):
         if not A._hints.get('nolength'):
@@ -191,6 +180,7 @@
         else:
             _fields_ = [('items',  max_n * ctypes_item)]
 
+        @classmethod
         def _malloc(cls, n=None):
             if not isinstance(n, int):
                 raise TypeError, "array length must be an int"
@@ -199,10 +189,29 @@
             if hasattr(bigarray, 'length'):
                 bigarray.length = n
             return bigarray
-        _malloc = classmethod(_malloc)
+
+        _ptrtype = None
+
+        @classmethod
+        def _get_ptrtype(cls):
+            if cls._ptrtype:
+                return cls._ptrtype
+            # ctypes can raise OverflowError on 64-bit builds
+            for n in [sys.maxint, 2**31]:
+                cls.MAX_SIZE = n/64
+                try:
+                    cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item)
+                except OverflowError, e:
+                    pass
+                else:
+                    break
+            else:
+                raise e
+            return cls._ptrtype
 
         def _indexable(self, index):
-            assert index + 1 < MAX_SIZE
+            PtrType = self._get_ptrtype()
+            assert index + 1 < self.MAX_SIZE
             p = ctypes.cast(ctypes.pointer(self.items), PtrType)
             return p.contents
 
diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py
--- a/pypy/rpython/lltypesystem/rclass.py
+++ b/pypy/rpython/lltypesystem/rclass.py
@@ -400,6 +400,7 @@
                 assert len(s_func.descriptions) == 1
                 funcdesc, = s_func.descriptions
                 graph = funcdesc.getuniquegraph()
+                self.check_graph_of_del_does_not_call_too_much(graph)
                 FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
                 destrptr = functionptr(FUNCTYPE, graph.name,
                                        graph=graph,
diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
--- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
@@ -671,7 +671,7 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_arrayofstruct(self):
-        S1 = lltype.Struct('S1', ('x', lltype.Signed))
+        S1 = lltype.Struct('S2', ('x', lltype.Signed))
         A = lltype.Array(S1, hints={'nolength': True})
         a = lltype.malloc(A, 5, flavor='raw')
         a[0].x = 100
diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py
--- a/pypy/rpython/memory/gc/minimark.py
+++ b/pypy/rpython/memory/gc/minimark.py
@@ -34,6 +34,13 @@
                         the GC in very small programs.  Defaults to 8
                         times the nursery.
 
+ PYPY_GC_LOSTCARD       If between two minor collections we see more than
+                        'PYPY_GC_LOSTCARD * length' writes to the same array,
+                        then give up card marking and use the fast write
+                        barrier instead.  Defaults to 0.3333 for now.
+                        Avoid values lower than 0.125: it is the growth
+                        factor of list.append().
+
  PYPY_GC_DEBUG          Enable extra checks around collections that are
                         too slow for normal use.  Values are 0 (off),
                         1 (on major collections) or 2 (also on minor
@@ -198,6 +205,9 @@
         # larger.  A value of 0 disables card marking.
         "card_page_indices": 128,
 
+        # See PYPY_GC_LOSTCARD.
+        "lost_card": 1.0 / 3.0,
+
         # Objects whose total size is at least 'large_object' bytes are
         # allocated out of the nursery immediately, as old objects.  The
         # minimal allocated size of the nursery is 2x the following
@@ -214,6 +224,7 @@
                  major_collection_threshold=2.5,
                  growth_rate_max=2.5,   # for tests
                  card_page_indices=0,
+                 lost_card=0.5,
                  large_object=8*WORD,
                  ArenaCollectionClass=None,
                  **kwds):
@@ -235,6 +246,7 @@
             self.card_page_shift = 0
             while (1 << self.card_page_shift) < self.card_page_indices:
                 self.card_page_shift += 1
+            self.lost_card = lost_card
         #
         # 'large_object' limit how big objects can be in the nursery, so
         # it gives a lower bound on the allowed size of the nursery.
@@ -355,6 +367,10 @@
             else:
                 self.max_delta = 0.125 * env.get_total_memory()
             #
+            lost_card = env.read_float_from_env('PYPY_GC_LOSTCARD')
+            if lost_card > 0.0:
+                self.lost_card = lost_card
+            #
             self.minor_collection()    # to empty the nursery
             llarena.arena_free(self.nursery)
             self.nursery_size = newsize
@@ -649,7 +665,7 @@
                 #
             else:
                 # Reserve N extra words containing card bits before the object.
-                extra_words = self.card_marking_words_for_length(length)
+                extra_words = self.card_marking_words_for_length(length) + 1
                 cardheadersize = WORD * extra_words
                 extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS
                 # note that if 'can_make_young', then card marking will only
@@ -675,11 +691,15 @@
                 raise MemoryError("cannot allocate large object")
             #
             # Reserve the card mark bits as a list of single bytes
-            # (the loop is empty in C).
-            i = 0
-            while i < cardheadersize:
-                llarena.arena_reserve(arena + i, llmemory.sizeof(lltype.Char))
-                i += 1
+            # followed by a Signed (the loop is empty in C).
+            if cardheadersize > 0:
+                i = 0
+                while i < cardheadersize - WORD:
+                    llarena.arena_reserve(arena + i,
+                                          llmemory.sizeof(lltype.Char))
+                    i += 1
+                llarena.arena_reserve(arena + i,
+                                      llmemory.sizeof(lltype.Signed))
             #
             # Reserve the actual object.  (This is also a no-op in C).
             result = arena + cardheadersize
@@ -903,14 +923,11 @@
             length = (obj + offset_to_length).signed[0]
             extra_words = self.card_marking_words_for_length(length)
             #
-            size_gc_header = self.gcheaderbuilder.size_gc_header
-            p = llarena.getfakearenaaddress(obj - size_gc_header)
             i = extra_words * WORD
             while i > 0:
-                p -= 1
-                ll_assert(p.char[0] == '\x00',
+                i -= 1
+                ll_assert(self.get_card(obj, i).char[0] == '\x00',
                           "the card marker bits are not cleared")
-                i -= 1
 
     # ----------
     # Write barrier
@@ -1008,6 +1025,8 @@
                     self.prebuilt_root_objects.append(addr_array)
                 return
             #
+            self.set_cards_flag(addr_array)
+            #
             # 'addr_array' is a raw_malloc'ed array with card markers
             # in front.  Compute the index of the bit to set:
             bitindex = index >> self.card_page_shift
@@ -1025,10 +1044,6 @@
             # it seems more important that remember_young_pointer_from_array2()
             # does not take 3 arguments).
             addr_byte.char[0] = chr(byte | bitmask)
-            #
-            if objhdr.tid & GCFLAG_CARDS_SET == 0:
-                self.objects_with_cards_set.append(addr_array)
-                objhdr.tid |= GCFLAG_CARDS_SET
 
         remember_young_pointer_from_array2._dont_inline_ = True
         assert self.card_page_indices > 0
@@ -1057,6 +1072,8 @@
                 if not self.appears_to_be_young(newvalue):
                     return
                 #
+                self.set_cards_flag(addr_array)
+                #
                 # 'addr_array' is a raw_malloc'ed array with card markers
                 # in front.  Compute the index of the bit to set:
                 bitindex = index >> self.card_page_shift
@@ -1069,10 +1086,6 @@
                 if byte & bitmask:
                     return
                 addr_byte.char[0] = chr(byte | bitmask)
-                #
-                if objhdr.tid & GCFLAG_CARDS_SET == 0:
-                    self.objects_with_cards_set.append(addr_array)
-                    objhdr.tid |= GCFLAG_CARDS_SET
                 return
             #
             # Logic for the no-cards case, put here to minimize the number
@@ -1090,11 +1103,36 @@
         self.remember_young_pointer_from_array3 = (
             remember_young_pointer_from_array3)
 
-    def get_card(self, obj, byteindex):
+    def get_card_counter_addr(self, obj):
         size_gc_header = self.gcheaderbuilder.size_gc_header
         addr_byte = obj - size_gc_header
-        return llarena.getfakearenaaddress(addr_byte) + (~byteindex)
+        return llarena.getfakearenaaddress(addr_byte) - WORD
 
+    def get_card(self, obj, byteindex):
+        return self.get_card_counter_addr(obj) + (~byteindex)
+
+    def set_cards_flag(self, obj):
+        hdr = self.header(obj)
+        if hdr.tid & GCFLAG_CARDS_SET == 0:
+            #
+            # first time we set a card bit in this object
+            self.header(obj).tid |= GCFLAG_CARDS_SET
+            self.objects_with_cards_set.append(obj)
+            #
+            # initialize the counter with the array length and self.lost_card
+            typeid = self.get_type_id(obj)
+            offset_to_length = self.varsize_offset_to_length(typeid)
+            length = (obj + offset_to_length).signed[0]
+            counter = int(length * self.lost_card)
+            self.get_card_counter_addr(obj).signed[0] = counter
+        else:
+            # decrement the counter and if zero is reached, give up on
+            # card marking (up to the next collection).
+            addr = self.get_card_counter_addr(obj)
+            addr.signed[0] -= 1
+            if addr.signed[0] < 0:
+                self.objects_pointing_to_young.append(obj)
+                hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
 
     def assume_young_pointers(self, addr_struct):
         """Called occasionally by the JIT to mean ``assume that 'addr_struct'
@@ -1167,10 +1205,7 @@
             addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte)
             i += 1
         #
-        dest_hdr = self.header(dest_addr)
-        if dest_hdr.tid & GCFLAG_CARDS_SET == 0:
-            self.objects_with_cards_set.append(dest_addr)
-            dest_hdr.tid |= GCFLAG_CARDS_SET
+        self.set_cards_flag(dest_addr)
 
     # ----------
     # Nursery collection
@@ -1264,6 +1299,7 @@
             length = (obj + offset_to_length).signed[0]
             bytes = self.card_marking_bytes_for_length(length)
             p = llarena.getfakearenaaddress(obj - size_gc_header)
+            p -= WORD
             #
             # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it
             # means that it is in 'objects_pointing_to_young' and
@@ -1602,7 +1638,7 @@
                           "GCFLAG_HAS_CARDS but not has_gcptr_in_varsize")
                 offset_to_length = self.varsize_offset_to_length(typeid)
                 length = (obj + offset_to_length).signed[0]
-                extra_words = self.card_marking_words_for_length(length)
+                extra_words = self.card_marking_words_for_length(length) + 1
                 arena -= extra_words * WORD
                 allocsize += extra_words * WORD
             #
diff --git a/pypy/rpython/memory/gc/test/test_direct.py b/pypy/rpython/memory/gc/test/test_direct.py
--- a/pypy/rpython/memory/gc/test/test_direct.py
+++ b/pypy/rpython/memory/gc/test/test_direct.py
@@ -525,6 +525,7 @@
     def test_writebarrier_before_copy(self):
         from pypy.rpython.memory.gc import minimark
         largeobj_size =  self.gc.nonlarge_max + 1
+        self.gc.next_major_collection_threshold = 99999.0
         p_src = self.malloc(VAR, largeobj_size)
         p_dst = self.malloc(VAR, largeobj_size)
         # make them old
@@ -564,6 +565,7 @@
         from pypy.rpython.memory.gc import minimark
         tid = self.get_type_id(VAR)
         largeobj_size =  self.gc.nonlarge_max + 1
+        self.gc.next_major_collection_threshold = 99999.0
         addr_src = self.gc.external_malloc(tid, largeobj_size)
         addr_dst = self.gc.external_malloc(tid, largeobj_size)
         hdr_src = self.gc.header(addr_src)
diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py
--- a/pypy/rpython/rclass.py
+++ b/pypy/rpython/rclass.py
@@ -374,6 +374,43 @@
     def can_ll_be_null(self, s_value):
         return s_value.can_be_none()
 
+    def check_graph_of_del_does_not_call_too_much(self, graph):
+        # RPython-level __del__() methods should not do "too much".
+        # In the PyPy Python interpreter, they usually do simple things
+        # like file.__del__() closing the file descriptor; or if they
+        # want to do more like call an app-level __del__() method, they
+        # enqueue the object instead, and the actual call is done later.
+        #
+        # Here, as a quick way to check "not doing too much", we check
+        # that from no RPython-level __del__() method we can reach a
+        # JitDriver.
+        #
+        # XXX wrong complexity, but good enough because the set of
+        # reachable graphs should be small
+        callgraph = self.rtyper.annotator.translator.callgraph.values()
+        seen = {graph: None}
+        while True:
+            oldlength = len(seen)
+            for caller, callee in callgraph:
+                if caller in seen and callee not in seen:
+                    func = getattr(callee, 'func', None)
+                    if getattr(func, '_dont_reach_me_in_del_', False):
+                        lst = [str(callee)]
+                        g = caller
+                        while g:
+                            lst.append(str(g))
+                            g = seen.get(g)
+                        lst.append('')
+                        raise TyperError("the RPython-level __del__() method "
+                                         "in %r calls:%s" % (
+                            graph, '\n\t'.join(lst[::-1])))
+                    if getattr(func, '_cannot_really_call_random_things_',
+                               False):
+                        continue
+                    seen[callee] = caller
+            if len(seen) == oldlength:
+                break
+
 # ____________________________________________________________
 
 def rtype_new_instance(rtyper, classdef, llops, classcallhop=None):
diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py
--- a/pypy/rpython/test/test_rclass.py
+++ b/pypy/rpython/test/test_rclass.py
@@ -7,6 +7,7 @@
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
 from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY
 from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY
+from pypy.rpython.error import TyperError
 from pypy.objspace.flow.model import summary
 
 class EmptyBase(object):
@@ -1021,7 +1022,25 @@
         assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0]
         assert destrptra is not None
         assert destrptrb is not None
-        
+
+    def test_del_forbidden(self):
+        class A(object):
+            def __del__(self):
+                self.foo()
+            def foo(self):
+                self.bar()
+            def bar(self):
+                pass
+            bar._dont_reach_me_in_del_ = True
+        def f():
+            a = A()
+            a.foo()
+            a.bar()
+        t = TranslationContext()
+        t.buildannotator().build_types(f, [])
+        e = py.test.raises(TyperError, t.buildrtyper().specialize)
+        print e.value
+
     def test_instance_repr(self):
         from pypy.rlib.objectmodel import current_object_addr_as_int
         class FooBar(object):
diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py
--- a/pypy/rpython/test/test_rstr.py
+++ b/pypy/rpython/test/test_rstr.py
@@ -231,7 +231,7 @@
         const = self.const
         def fn(i):
             s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')]
-            return s[i].startswith('o')
+            return s[i].startswith(const('o'))
         for i in range(10):
             res = self.interpret(fn, [i])
             assert res == fn(i)
@@ -251,7 +251,7 @@
         const = self.const
         def fn(i):
             s = [const(''), const('one'), const('two'), const('o'), const('on'), const('ne'), const('e'), const('twos'), const('foobar'), const('fortytwo')]
-            return s[i].endswith('e')
+            return s[i].endswith(const('e'))
         for i in range(10):
             res = self.interpret(fn, [i])
             assert res == fn(i)
diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py
--- a/pypy/tool/jitlogparser/parser.py
+++ b/pypy/tool/jitlogparser/parser.py
@@ -337,8 +337,16 @@
     addrs = {}
     for entry in extract_category(log, 'jit-backend-addr'):
         m = re.search('bootstrap ([\da-f]+)', entry)
-        name = entry[:entry.find('(') - 1]
-        addrs[int(m.group(1), 16)] = name
+        if not m:
+            # a bridge
+            m = re.search('has address ([\da-f]+)', entry)
+            addr = int(m.group(1), 16)
+            entry = entry.lower()
+            m = re.search('guard \d+', entry)
+            addrs[addr] = m.group(0)
+        else:
+            name = entry[:entry.find('(') - 1].lower()
+            addrs[int(m.group(1), 16)] = name
     dumps = {}
     for entry in extract_category(log, 'jit-backend-dump'):
         backend, _, dump, _ = entry.split("\n")
@@ -353,7 +361,12 @@
                            nonstrict=True)
         loop = parser.parse()
         comm = loop.comment
-        name = comm[2:comm.find(':')-1]
+        comm = comm.lower()
+        if comm.startswith('# bridge'):
+            m = re.search('guard \d+', comm)
+            name = m.group(0)
+        else:
+            name = comm[2:comm.find(':')-1]
         if name in dumps:
             bname, start_ofs, dump = dumps[name]
             parser.postprocess(loop, backend_tp=bname, backend_dump=dump,
diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py
--- a/pypy/tool/jitlogparser/test/test_parser.py
+++ b/pypy/tool/jitlogparser/test/test_parser.py
@@ -214,3 +214,10 @@
     _, loops = import_log(str(py.path.local(__file__).join('..',
                                                            'logtest.log')))
     assert 'jge' in loops[0].operations[3].asm
+
+def test_import_log_2():
+    _, loops = import_log(str(py.path.local(__file__).join('..',
+                                                           'logtest2.log')))
+    assert 'cmp' in loops[1].operations[1].asm
+    # bridge
+    assert 'cmp' in loops[3].operations[1].asm
diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs
--- a/pypy/translator/cli/src/pypylib.cs
+++ b/pypy/translator/cli/src/pypylib.cs
@@ -615,10 +615,28 @@
             return s1.StartsWith(s2);
         }
 
+        public static bool ll_startswith_char(string s, char c)
+        {
+            if (s.Length == 0)
+            {
+                return false;
+            }
+            return s[0] == c;
+        }
+
         public static bool ll_endswith(string s1, string s2)
         {
             return s1.EndsWith(s2);
         }
+
+        public static bool ll_endswith_char(string s, char c)
+        {
+            if (s.Length == 0)
+            {
+                return false;
+            }
+            return s[s.Length - 1] == c;
+        }
         
         public static int ll_find(string s1, string s2, int start, int stop)
         {
diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java
--- a/pypy/translator/jvm/src/pypy/PyPy.java
+++ b/pypy/translator/jvm/src/pypy/PyPy.java
@@ -791,6 +791,20 @@
         return str.substring(start,start+cnt);
     }
 
+    public static boolean ll_startswith_char(String str, char c) {
+        if (str.length() == 0) {
+            return false;
+        }
+        return str.charAt(0) == c;
+    }
+
+    public static boolean ll_endswith_char(String str, char c) {
+        if (str.length() == 0) {
+            return false;
+        }
+        return str.charAt(str.length() - 1) == c;
+    }
+
     // ----------------------------------------------------------------------
     // StringBuffer
 


More information about the pypy-commit mailing list