[pypy-commit] pypy missing-ndarray-attributes: merge default into branch

mattip noreply at buildbot.pypy.org
Fri Jan 18 01:17:01 CET 2013


Author: mattip <matti.picus at gmail.com>
Branch: missing-ndarray-attributes
Changeset: r60163:9a095c7af768
Date: 2013-01-18 02:15 +0200
http://bitbucket.org/pypy/pypy/changeset/9a095c7af768/

Log:	merge default into branch

diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py
--- a/pypy/doc/test/test_whatsnew.py
+++ b/pypy/doc/test/test_whatsnew.py
@@ -29,7 +29,7 @@
                       merge() and \
                       branch(default)) and \
               not branch(default)' % (startrev, endrev)
-    cmd = r"hg log -R '%s' -r '%s' --template '{branches}\n'" % (path, revset)
+    cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset)
     out = getoutput(cmd)
     branches = set(map(str.strip, out.splitlines()))
     return branches
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
@@ -15,6 +15,9 @@
 
 .. branch: numpypy-longdouble
 Long double support for numpypy
+.. branch: numpypy-real-as-view
+Convert real, imag from ufuncs to views. This involves the beginning of 
+view() functionality
 
 .. branch: signatures
 Improved RPython typing
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -178,6 +178,11 @@
             else:
                 oparg = 0
 
+            # note: the structure of the code here is such that it makes
+            # (after translation) a big "if/elif" chain, which is then
+            # turned into a switch().  It starts here: even if the first
+            # one is not an "if" but a "while" the effect is the same.
+
             while opcode == self.opcodedesc.EXTENDED_ARG.index:
                 opcode = ord(co_code[next_instr])
                 if opcode < self.HAVE_ARGUMENT:
@@ -226,6 +231,8 @@
                         'END_FINALLY', 'JUMP_ABSOLUTE'):
                         continue   # opcodes implemented above
 
+                    # the following "if" is part of the big switch described
+                    # above.
                     if opcode == opdesc.index:
                         # dispatch to the opcode method
                         meth = getattr(self, opdesc.methodname)
diff --git a/pypy/jit/backend/test/calling_convention_test.py b/pypy/jit/backend/test/calling_convention_test.py
--- a/pypy/jit/backend/test/calling_convention_test.py
+++ b/pypy/jit/backend/test/calling_convention_test.py
@@ -105,11 +105,13 @@
             ops = '[%s]\n' % arguments
             ops += '%s\n' % spill_ops
             ops += 'f99 = call(ConstClass(func_ptr), %s, descr=calldescr)\n' % arguments
-            ops += 'finish(f99, %s)\n' % arguments
+            ops += 'i99 = same_as(0)\n'
+            ops += 'guard_true(i99) [f99, %s]\n' % arguments
+            ops += 'finish()\n'
 
             loop = parse(ops, namespace=locals())
             looptoken = JitCellToken()
-            done_number = self.cpu.get_fail_descr_number(loop.operations[-1].getdescr())
+            done_number = self.cpu.get_fail_descr_number(loop.operations[-2].getdescr())
             self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
             argvals, expected_result = self._prepare_args(args, floats, ints)
 
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -1192,7 +1192,8 @@
                     values.append(longlong.getfloatstorage(r.random()))
             #
             looptoken = JitCellToken()
-            faildescr = BasicFailDescr(42)
+            guarddescr = BasicFailDescr(42)
+            faildescr = BasicFailDescr(43)
             operations = []
             retboxes = []
             retvalues = []
@@ -1221,9 +1222,13 @@
                 retboxes.insert(kk, newbox)
                 retvalues.insert(kk, y)
             #
-            operations.append(
-                ResOperation(rop.FINISH, retboxes, None, descr=faildescr)
-                )
+            zero = BoxInt()
+            operations.extend([
+                ResOperation(rop.SAME_AS, [ConstInt(0)], zero),
+                ResOperation(rop.GUARD_TRUE, [zero], None, descr=guarddescr),
+                ResOperation(rop.FINISH, [], None, descr=faildescr)
+                ])
+            operations[-2].setfailargs(retboxes)
             print inputargs
             for op in operations:
                 print op
@@ -1344,12 +1349,15 @@
         targettoken = TargetToken()
         faildescr1 = BasicFailDescr(1)
         faildescr2 = BasicFailDescr(2)
+        faildescr3 = BasicFailDescr(3)
         operations = [
             ResOperation(rop.LABEL, fboxes, None, descr=targettoken),
             ResOperation(rop.FLOAT_LE, [fboxes[0], constfloat(9.2)], i2),
             ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1),
-            ResOperation(rop.FINISH, fboxes, None, descr=faildescr2),
+            ResOperation(rop.GUARD_FALSE, [i2], None, descr=faildescr2),
+            ResOperation(rop.FINISH, [], None, descr=faildescr3),
             ]
+        operations[-3].setfailargs(fboxes)
         operations[-2].setfailargs(fboxes)
         looptoken = JitCellToken()
         self.cpu.compile_loop(fboxes, operations, looptoken)
@@ -1382,6 +1390,7 @@
             py.test.skip("requires floats")
         fboxes = [BoxFloat() for i in range(3)]
         faildescr1 = BasicFailDescr(100)
+        faildescr2 = BasicFailDescr(102)
         loopops = """
         [i0,f1, f2]
         f3 = float_add(f1, f2)
@@ -1406,9 +1415,13 @@
         assert longlong.getrealfloat(f2) == 0.75
         assert longlong.getrealfloat(f3) == 133.0
 
+        zero = BoxInt()
         bridgeops = [
-            ResOperation(rop.FINISH, fboxes, None, descr=faildescr1),
+            ResOperation(rop.SAME_AS, [ConstInt(0)], zero),
+            ResOperation(rop.GUARD_TRUE, [zero], None, descr=faildescr1),
+            ResOperation(rop.FINISH, [], None, descr=faildescr2),
             ]
+        bridgeops[-2].setfailargs(fboxes[:])
         self.cpu.compile_bridge(loop.operations[-2].getdescr(), fboxes,
                                                         bridgeops, looptoken)
         args = [1,
@@ -2002,7 +2015,7 @@
         i1 = same_as(1)
         call(ConstClass(fptr), i0, descr=calldescr)
         p0 = guard_exception(ConstClass(xtp)) [i1]
-        finish(0, p0)
+        finish(p0)
         '''
         FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
         fptr = llhelper(FPTR, func)
@@ -2023,8 +2036,7 @@
         looptoken = JitCellToken()
         self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
         deadframe = self.cpu.execute_token(looptoken, 1)
-        assert self.cpu.get_latest_value_int(deadframe, 0) == 0
-        assert self.cpu.get_latest_value_ref(deadframe, 1) == xptr
+        assert self.cpu.get_latest_value_ref(deadframe, 0) == xptr
         excvalue = self.cpu.grab_exc_value(deadframe)
         assert not excvalue
         deadframe = self.cpu.execute_token(looptoken, 0)
diff --git a/pypy/jit/backend/test/test_random.py b/pypy/jit/backend/test/test_random.py
--- a/pypy/jit/backend/test/test_random.py
+++ b/pypy/jit/backend/test/test_random.py
@@ -26,6 +26,8 @@
 class OperationBuilder(object):
     def __init__(self, cpu, loop, vars):
         self.cpu = cpu
+        if not hasattr(cpu, '_faildescr_keepalive'):
+            cpu._faildescr_keepalive = []
         self.fakemetainterp = FakeMetaInterp()
         self.loop = loop
         self.intvars = [box for box in vars if isinstance(box, BoxInt)]
@@ -206,6 +208,11 @@
         if pytest.config.option.output:
             s.close()
 
+    def getfaildescr(self):
+        descr = BasicFailDescr()
+        self.cpu._faildescr_keepalive.append(descr)
+        return descr
+
 class CannotProduceOperation(Exception):
     pass
 
@@ -287,7 +294,7 @@
             builder.intvars[:] = original_intvars
         else:
             op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None)
-        op.setdescr(BasicFailDescr())
+        op.setdescr(builder.getfaildescr())
         op.setfailargs(fail_subset)
         builder.loop.operations.append(op)
 
@@ -357,7 +364,7 @@
     def produce_into(self, builder, r):
         op, passing = self.gen_guard(builder, r)
         builder.loop.operations.append(op)
-        op.setdescr(BasicFailDescr())
+        op.setdescr(builder.getfaildescr())
         op.setfailargs(builder.subset_of_intvars(r))
         if not passing:
             builder.should_fail_by = op
@@ -618,8 +625,9 @@
             if v not in used_later:
                 endvars.append(v)
         r.shuffle(endvars)
+        endvars = endvars[:1]
         loop.operations.append(ResOperation(rop.FINISH, endvars, None,
-                                            descr=BasicFailDescr()))
+                                            descr=builder.getfaildescr()))
         if builder.should_fail_by:
             self.should_fail_by = builder.should_fail_by
             self.guard_op = builder.guard_op
@@ -712,7 +720,7 @@
             else:
                 op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box],
                                   BoxPtr())
-            op.setdescr(BasicFailDescr())
+            op.setdescr(self.builder.getfaildescr())
             op.setfailargs([])
             return op
 
diff --git a/pypy/jit/backend/x86/test/test_recompilation.py b/pypy/jit/backend/x86/test/test_recompilation.py
--- a/pypy/jit/backend/x86/test/test_recompilation.py
+++ b/pypy/jit/backend/x86/test/test_recompilation.py
@@ -45,7 +45,8 @@
         force_spill(i5)
         i8 = int_add(i7, 1)
         i9 = int_add(i8, 1)
-        finish(i3, i4, i5, i6, i7, i8, i9, descr=fdescr2)
+        guard_false(i3, descr=fdescr2) [i3, i4, i5, i6, i7, i8, i9]
+        finish()
         '''
         bridge = self.attach_bridge(ops, loop, -2)
         descr = loop.operations[3].getdescr()
diff --git a/pypy/jit/backend/x86/test/test_regalloc.py b/pypy/jit/backend/x86/test/test_regalloc.py
--- a/pypy/jit/backend/x86/test/test_regalloc.py
+++ b/pypy/jit/backend/x86/test/test_regalloc.py
@@ -327,7 +327,7 @@
         assert self.getint(0) == 0
         bridge_ops = '''
         [i0, i1]
-        finish(1, 2)
+        finish(2)
         '''
         self.attach_bridge(bridge_ops, loop, 0)
         self.run(loop, 0, 1)
@@ -428,7 +428,7 @@
         ops = '''
         [i0, i1, i2, i3, i4, i5, i6, i7]
         guard_value(i6, i1) [i0, i2, i3, i4, i5, i6]
-        finish(i0, i2, i3, i4, i5, i6)
+        finish(i0)
         '''
         self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0])
         assert self.getint(0) == 0
@@ -438,14 +438,15 @@
         [i0, i1, i2, i3, i4, i5, i6, i7, i8]
         i9 = same_as(0)
         guard_true(i0) [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8]
-        finish(1, i0, i1, i2, i3, i4, i5, i6, i7, i8)
+        finish(1)
         '''
         loop = self.interpret(ops, [0, 1, 2, 3, 4, 5, 6, 7, 8])
         assert self.getint(0) == 0
         bridge_ops = '''
         [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8]
         call(ConstClass(raising_fptr), 0, descr=raising_calldescr)
-        finish(i0, i1, i2, i3, i4, i5, i6, i7, i8)
+        guard_true(i9) [i0, i1, i2, i3, i4, i5, i6, i7, i8]
+        finish()
         '''
         self.attach_bridge(bridge_ops, loop, 1)
         self.run(loop, 0, 1, 2, 3, 4, 5, 6, 7, 8)
@@ -474,7 +475,8 @@
         i1 = same_as(1)
         i2 = int_lt(i0, 100)
         guard_true(i3) [i1, i2]
-        finish(0, i2)
+        i4 = int_neg(i2)
+        finish(0)
         '''
         self.interpret(ops, [0, 1])
         assert self.getint(0) == 0
@@ -503,7 +505,8 @@
         i15 = int_is_true(i5)
         i16 = int_is_true(i6)
         i17 = int_is_true(i7)
-        finish(i10, i11, i12, i13, i14, i15, i16, i17)
+        guard_true(i0) [i10, i11, i12, i13, i14, i15, i16, i17]
+        finish()
         '''
         self.interpret(ops, [0, 42, 12, 0, 13, 0, 0, 3333])
         assert self.getints(8) == [0, 1, 1, 0, 1, 0, 0, 1]
@@ -517,7 +520,8 @@
         i13 = int_eq(i5, i6)
         i14 = int_gt(i6, i2)
         i15 = int_ne(i2, i6)
-        finish(i10, i11, i12, i13, i14, i15)
+        guard_true(i0) [i10, i11, i12, i13, i14, i15]
+        finish()
         '''
         self.interpret(ops, [0, 1, 2, 3, 4, 5, 6])
         assert self.getints(6) == [1, 1, 0, 0, 1, 1]
@@ -574,7 +578,9 @@
         ops = '''
         [f0, f1]
         f2 = float_add(f0, f1)
-        finish(f2, f0, f1)
+        i0 = same_as(0)
+        guard_true(i0) [f2, f0, f1]
+        finish()
         '''
         self.interpret(ops, [3.0, 1.5])
         assert self.getfloats(3) == [4.5, 3.0, 1.5]
@@ -584,7 +590,9 @@
         [f0, f1, f2, f3, f4, f5, f6, f7, f8]
         f9 = float_add(f0, f1)
         f10 = float_add(f8, 3.5)
-        finish(f9, f10, f2, f3, f4, f5, f6, f7, f8)
+        i0 = same_as(0)
+        guard_true(i0) [f9, f10, f2, f3, f4, f5, f6, f7, f8]
+        finish()
         '''
         self.interpret(ops, [0.1, .2, .3, .4, .5, .6, .7, .8, .9])
         assert self.getfloats(9) == [.1+.2, .9+3.5, .3, .4, .5, .6, .7, .8, .9]
@@ -613,7 +621,8 @@
         i7 = float_ne(f7, 0.0)
         i8 = float_ne(f8, 0.0)
         i9 = float_ne(f9, 0.0)
-        finish(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9)
+        guard_true(i0) [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9]
+        finish()
         '''
         loop = self.interpret(ops, [0.0, .1, .2, .3, .4, .5, .6, .7, .8, .9])
         assert self.getints(9) == [0, 1, 1, 1, 1, 1, 1, 1, 1]
diff --git a/pypy/jit/backend/x86/test/test_regalloc2.py b/pypy/jit/backend/x86/test/test_regalloc2.py
--- a/pypy/jit/backend/x86/test/test_regalloc2.py
+++ b/pypy/jit/backend/x86/test/test_regalloc2.py
@@ -11,13 +11,17 @@
     v2 = BoxInt()
     v3 = BoxInt()
     v4 = BoxInt()
+    zero = BoxInt()
     inputargs = [v1]
     operations = [
         ResOperation(rop.INT_ADD, [v1, v1], v2),
         ResOperation(rop.INT_INVERT, [v2], v3),
         ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4),
-        ResOperation(rop.FINISH, [v4, v3], None, descr=BasicFailDescr()),
+        ResOperation(rop.SAME_AS, [ConstInt(0)], zero),
+        ResOperation(rop.GUARD_TRUE, [zero], None, descr=BasicFailDescr()),
+        ResOperation(rop.FINISH, [], None, descr=BasicFailDescr())
         ]
+    operations[-2].setfailargs([v4, v3])
     cpu = CPU(None, None)
     cpu.setup_once()
     looptoken = JitCellToken()
@@ -31,6 +35,7 @@
     v2 = BoxInt()
     v3 = BoxInt()
     v4 = BoxInt()
+    zero = BoxInt()
     tmp5 = BoxInt()
     inputargs = [v1]
     operations = [
@@ -38,8 +43,11 @@
         ResOperation(rop.INT_MUL, [v2, v1], v3),
         ResOperation(rop.INT_IS_TRUE, [v2], tmp5),
         ResOperation(rop.INT_IS_ZERO, [tmp5], v4),
-        ResOperation(rop.FINISH, [v4, v3, tmp5], None, descr=BasicFailDescr()),
+        ResOperation(rop.SAME_AS, [ConstInt(0)], zero),
+        ResOperation(rop.GUARD_TRUE, [zero], None, descr=BasicFailDescr()),
+        ResOperation(rop.FINISH, [], None, descr=BasicFailDescr())
             ]
+    operations[-2].setfailargs([v4, v3, tmp5])
     cpu = CPU(None, None)
     cpu.setup_once()
     looptoken = JitCellToken()
@@ -90,6 +98,7 @@
     v38 = BoxInt()
     v39 = BoxInt()
     v40 = BoxInt()
+    zero = BoxInt()
     tmp41 = BoxInt()
     tmp42 = BoxInt()
     tmp43 = BoxInt()
@@ -134,8 +143,12 @@
         ResOperation(rop.UINT_GT, [v33, ConstInt(-11)], v38),
         ResOperation(rop.INT_NEG, [v7], v39),
         ResOperation(rop.INT_GT, [v24, v32], v40),
-        ResOperation(rop.FINISH, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()),
+        ResOperation(rop.SAME_AS, [ConstInt(0)], zero),
+        ResOperation(rop.GUARD_TRUE, [zero], None, descr=BasicFailDescr()),
+        ResOperation(rop.FINISH, [], None, descr=BasicFailDescr())
             ]
+    operations[-2].setfailargs([v40, v36, v37, v31, v16, v34, v35, v23,
+                                v22, v29, v14, v39, v30, v38])
     cpu = CPU(None, None)
     cpu.setup_once()
     looptoken = JitCellToken()
@@ -198,6 +211,7 @@
     v38 = BoxInt()
     v39 = BoxInt()
     v40 = BoxInt()
+    zero = BoxInt()
     tmp41 = BoxInt()
     tmp42 = BoxInt()
     tmp43 = BoxInt()
@@ -240,8 +254,13 @@
         ResOperation(rop.INT_GT, [v4, v11], v38),
         ResOperation(rop.INT_LT, [v27, v22], v39),
         ResOperation(rop.INT_NEG, [v27], v40),
-        ResOperation(rop.FINISH, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()),
+        ResOperation(rop.SAME_AS, [ConstInt(0)], zero),
+        ResOperation(rop.GUARD_TRUE, [zero], None, descr=BasicFailDescr()),
+        ResOperation(rop.FINISH, [], None, descr=BasicFailDescr())
             ]
+    operations[-2].setfailargs([v40, v10, v36, v26, v13, v30, v21, v33,
+                                v18, v25, v31, v32, v28, v29, v35, v38,
+                                v20, v39, v34, v23, v37])
     cpu = CPU(None, None)
     cpu.setup_once()
     looptoken = JitCellToken()
diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py
--- a/pypy/jit/backend/x86/test/test_runner.py
+++ b/pypy/jit/backend/x86/test/test_runner.py
@@ -499,9 +499,12 @@
                          i6, descr=calldescr),
             ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
 
-            ResOperation(rop.FINISH, [i3, i4, i5, i6], None,
-                         descr=BasicFailDescr(0))
+            ResOperation(rop.GUARD_FALSE, [i3], None,
+                         descr=BasicFailDescr(0)),
+            ResOperation(rop.FINISH, [], None,
+                         descr=BasicFailDescr(1))
             ]
+            ops[-2].setfailargs([i3, i4, i5, i6])
             ops[1].setfailargs([])
             ops[3].setfailargs([])
             ops[5].setfailargs([])
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -10,7 +10,7 @@
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.translator.simplify import get_funcobj
 from pypy.translator.unsimplify import split_block
-from pypy.objspace.flow.model import Constant
+from pypy.objspace.flow.model import Variable, Constant
 from pypy.translator.translator import TranslationContext
 from pypy.annotation.policy import AnnotatorPolicy
 from pypy.annotation import model as annmodel
@@ -59,6 +59,45 @@
     rtyper = annotate(func, values)
     return rtyper.annotator.translator.graphs[0]
 
+def autodetect_jit_markers_redvars(graph):
+    # the idea is to find all the jit_merge_point and
+    # add all the variables across the links to the reds.
+    for block, op in graph.iterblockops():
+        if op.opname == 'jit_marker':
+            jitdriver = op.args[1].value
+            if not jitdriver.autoreds:
+                continue
+            # if we want to support also can_enter_jit, we should find a
+            # way to detect a consistent set of red vars to pass *both* to
+            # jit_merge_point and can_enter_jit. The current simple
+            # solution doesn't work because can_enter_jit might be in
+            # another block, so the set of alive_v will be different.
+            methname = op.args[0].value
+            assert methname == 'jit_merge_point', (
+                "reds='auto' is supported only for jit drivers which " 
+                "calls only jit_merge_point. Found a call to %s" % methname)
+            #
+            # compute the set of live variables across the jit_marker
+            alive_v = set()
+            for link in block.exits:
+                alive_v.update(link.args)
+                alive_v.difference_update(link.getextravars())
+            for op1 in block.operations[::-1]:
+                if op1 is op:
+                    break # stop when the meet the jit_marker
+                alive_v.discard(op1.result)
+                alive_v.update(op1.args)
+            greens_v = op.args[2:]
+            reds_v = alive_v - set(greens_v)
+            reds_v = [v for v in reds_v if isinstance(v, Variable) and
+                                           v.concretetype is not lltype.Void]
+            reds_v = sort_vars(reds_v)
+            op.args.extend(reds_v)
+            if jitdriver.numreds is None:
+                jitdriver.numreds = len(reds_v)
+            else:
+                assert jitdriver.numreds == len(reds_v), 'inconsistent number of reds_v'
+
 def split_before_jit_merge_point(graph, portalblock, portalopindex):
     """Split the block just before the 'jit_merge_point',
     making sure the input args are in the canonical order.
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -5,7 +5,7 @@
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
 from pypy.rlib import rstack
-from pypy.rlib.jit import JitDebugInfo, Counters
+from pypy.rlib.jit import JitDebugInfo, Counters, dont_look_inside
 from pypy.conftest import option
 from pypy.tool.sourcetools import func_with_new_name
 
@@ -685,6 +685,7 @@
         assert 0, "unreachable"
 
     @staticmethod
+    @dont_look_inside
     def force_now(cpu, token):
         # Called during a residual call from the assembler, if the code
         # actually needs to force one of the virtualrefs or the virtualizable.
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -353,6 +353,9 @@
 
     def initarglist(self, args):
         self._args = args
+        if not we_are_translated() and \
+               self.__class__.__name__.startswith('FINISH'):   # XXX remove me
+            assert len(args) <= 1      # FINISH operations take 0 or 1 arg now
 
     def getarglist(self):
         return self._args
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -105,7 +105,7 @@
 
 
 class TestFfiCall(FfiCallTests, LLJitMixin):
-    def test_jit_fii_vref(self):
+    def test_jit_ffi_vref(self):
         from pypy.rlib import clibffi
         from pypy.rlib.jit_libffi import jit_ffi_prep_cif, jit_ffi_call
 
@@ -136,9 +136,10 @@
             res = exb[3]
             lltype.free(exb, flavor='raw')
             #
-            lltype.free(atypes, flavor='raw')
             return res
             #
         res = self.interp_operations(f, [])
         lltype.free(cd, flavor='raw')
         assert res == math.sin(1.23)
+
+        lltype.free(atypes, flavor='raw')
diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -1,6 +1,6 @@
 import py
 from pypy.jit.metainterp.warmspot import get_stats
-from pypy.rlib.jit import JitDriver, set_param, unroll_safe
+from pypy.rlib.jit import JitDriver, set_param, unroll_safe, jit_callback
 from pypy.jit.backend.llgraph import runner
 
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
@@ -383,6 +383,23 @@
         assert res == expected
         self.check_resops(int_sub=2, int_mul=0, int_add=2)
 
+    def test_loop_automatic_reds_not_too_many_redvars(self):
+        myjitdriver = JitDriver(greens = ['m'], reds = 'auto')
+        def one():
+            return 1
+        def f(n, m):
+            res = 0
+            while n > 0:
+                n -= one()
+                myjitdriver.jit_merge_point(m=m)
+                res += m*2
+            return res
+        expected = f(21, 5)
+        res = self.meta_interp(f, [21, 5])
+        assert res == expected
+        oplabel = get_stats().loops[0].operations[0]
+        assert len(oplabel.getarglist()) == 2     # 'n', 'res' in some order
+
     def test_inline_jit_merge_point(self):
         # test that the machinery to inline jit_merge_points in callers
         # works. The final user does not need to mess manually with the
@@ -520,41 +537,21 @@
 
 
     def test_callback_jit_merge_point(self):
-        from pypy.rlib.objectmodel import register_around_callback_hook
-        from pypy.rpython.lltypesystem import lltype, rffi
-        from pypy.translator.tool.cbuild import ExternalCompilationInfo
-        
-        callback_jit_driver = JitDriver(greens = ['name'], reds = 'auto')
-        
-        def callback_merge_point(name):
-            callback_jit_driver.jit_merge_point(name=name)
-    
-        @callback_jit_driver.inline(callback_merge_point)
-        def callback_hook(name):
-            pass
-
+        @jit_callback("testing")
         def callback(a, b):
             if a > b:
                 return 1
             return -1
 
-        CB_TP = rffi.CCallback([lltype.Signed, lltype.Signed], lltype.Signed)
-        eci = ExternalCompilationInfo(includes=['stdlib.h'])
-        qsort = rffi.llexternal('qsort',
-                                [rffi.VOIDP, lltype.Signed, lltype.Signed,
-                                 CB_TP], lltype.Void, compilation_info=eci)
-        ARR = rffi.CArray(lltype.Signed)
+        def main():
+            total = 0
+            for i in range(10):
+                total += callback(i, 2)
+            return total
 
-        def main():
-            register_around_callback_hook(callback_hook)
-            raw = lltype.malloc(ARR, 10, flavor='raw')
-            for i in range(10):
-                raw[i] = 10 - i
-            qsort(raw, 10, rffi.sizeof(lltype.Signed), callback)
-            lltype.free(raw, flavor='raw')
-
-        self.meta_interp(main, [])
-        self.check_trace_count(1)
+        res = self.meta_interp(main, [])
+        assert res == 7 - 3
+        self.check_trace_count(2)
 
 
 class TestLLWarmspot(WarmspotTests, LLJitMixin):
diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py
--- a/pypy/jit/metainterp/virtualref.py
+++ b/pypy/jit/metainterp/virtualref.py
@@ -169,4 +169,3 @@
             # token == TOKEN_NONE and the vref was not forced: it's invalid
             raise InvalidVirtualRef
         return vref.forced
-    force_virtual._dont_inline_ = True
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -347,62 +347,20 @@
         self.jitdrivers_sd = []
         graphs = self.translator.graphs
         for graph, block, pos in find_jit_merge_points(graphs):
-            self.autodetect_jit_markers_redvars(graph)
+            support.autodetect_jit_markers_redvars(graph)
             self.split_graph_and_record_jitdriver(graph, block, pos)
         #
         assert (len(set([jd.jitdriver for jd in self.jitdrivers_sd])) ==
                 len(self.jitdrivers_sd)), \
                 "there are multiple jit_merge_points with the same jitdriver"
 
-    def autodetect_jit_markers_redvars(self, graph):
-        # the idea is to find all the jit_merge_point and can_enter_jit and
-        # add all the variables across the links to the reds.
-        for block, op in graph.iterblockops():
-            if op.opname == 'jit_marker':
-                jitdriver = op.args[1].value
-                if not jitdriver.autoreds:
-                    continue
-                # if we want to support also can_enter_jit, we should find a
-                # way to detect a consistent set of red vars to pass *both* to
-                # jit_merge_point and can_enter_jit. The current simple
-                # solution doesn't work because can_enter_jit might be in
-                # another block, so the set of alive_v will be different.
-                methname = op.args[0].value
-                assert methname == 'jit_merge_point', (
-                    "reds='auto' is supported only for jit drivers which " 
-                    "calls only jit_merge_point. Found a call to %s" % methname)
-                #
-                # compute the set of live variables before the jit_marker
-                alive_v = set(block.inputargs)
-                for op1 in block.operations:
-                    if op1 is op:
-                        break # stop when the meet the jit_marker
-                    if op1.result.concretetype != lltype.Void:
-                        alive_v.add(op1.result)
-                greens_v = op.args[2:]
-                reds_v = alive_v - set(greens_v)
-                reds_v = [v for v in reds_v if v.concretetype is not lltype.Void]
-                reds_v = support.sort_vars(reds_v)
-                op.args.extend(reds_v)
-                if jitdriver.numreds is None:
-                    jitdriver.numreds = len(reds_v)
-                else:
-                    assert jitdriver.numreds == len(reds_v), 'inconsistent number of reds_v'
-
-
     def split_graph_and_record_jitdriver(self, graph, block, pos):
         op = block.operations[pos]
         jd = JitDriverStaticData()
         jd._jit_merge_point_in = graph
         args = op.args[2:]
         s_binding = self.translator.annotator.binding
-        if op.args[1].value.autoreds:
-            # _portal_args_s is used only by _make_hook_graph, but for now we
-            # declare the various set_jitcell_at, get_printable_location,
-            # etc. as incompatible with autoreds
-            jd._portal_args_s = None
-        else:
-            jd._portal_args_s = [s_binding(v) for v in args]
+        jd._portal_args_s = [s_binding(v) for v in args]
         graph = copygraph(graph)
         [jmpp] = find_jit_merge_points([graph])
         graph.startblock = support.split_before_jit_merge_point(*jmpp)
@@ -650,9 +608,10 @@
         if func is None:
             return None
         #
-        assert not jitdriver_sd.jitdriver.autoreds, (
-            "reds='auto' is not compatible with JitDriver hooks such as "
-            "{get,set}_jitcell_at, get_printable_location, confirm_enter_jit, etc.")
+        if not onlygreens:
+            assert not jitdriver_sd.jitdriver.autoreds, (
+                "reds='auto' is not compatible with JitDriver hooks such as "
+                "confirm_enter_jit")
         extra_args_s = []
         if s_first_arg is not None:
             extra_args_s.append(s_first_arg)
@@ -717,6 +676,9 @@
             jitdriver = op.args[1].value
             assert jitdriver in sublists, \
                    "can_enter_jit with no matching jit_merge_point"
+            assert not jitdriver.autoreds, (
+                   "can_enter_jit not supported with a jitdriver that "
+                   "has reds='auto'")
             jd, sublist = sublists[jitdriver]
             origportalgraph = jd._jit_merge_point_in
             if graph is not origportalgraph:
diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -152,6 +152,7 @@
 
 STDERR = 2
 
+ at jit.jit_callback("CFFI")
 def invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata):
     """ Callback specification.
     ffi_cif - something ffi specific, don't care
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
--- a/pypy/module/micronumpy/arrayimpl/concrete.py
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -11,7 +11,7 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rlib import jit
 from pypy.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\
-     raw_storage_setitem
+     raw_storage_setitem, RAW_STORAGE
 from pypy.module.micronumpy.arrayimpl.sort import argsort_array
 from pypy.rlib.debug import make_sure_not_resized
 
@@ -275,18 +275,19 @@
     def get_buffer(self, space):
         return ArrayBuffer(self)
 
-class ConcreteArray(BaseConcreteArray):
-    def __init__(self, shape, dtype, order, strides, backstrides):
+class ConcreteArrayNotOwning(BaseConcreteArray):
+    def __init__(self, shape, dtype, order, strides, backstrides, storage):
+
         make_sure_not_resized(shape)
         make_sure_not_resized(strides)
         make_sure_not_resized(backstrides)
         self.shape = shape
         self.size = support.product(shape) * dtype.get_size()
-        self.storage = dtype.itemtype.malloc(self.size)
         self.order = order
         self.dtype = dtype
         self.strides = strides
         self.backstrides = backstrides
+        self.storage = storage
 
     def create_iter(self, shape=None):
         if shape is None or shape == self.get_shape():
@@ -299,9 +300,6 @@
     def fill(self, box):
         self.dtype.fill(self.storage, box, 0, self.size)
 
-    def __del__(self):
-        free_raw_storage(self.storage, track_allocation=False)
-
     def set_shape(self, space, orig_array, new_shape):
         strides, backstrides = support.calc_strides(new_shape, self.dtype,
                                                     self.order)
@@ -319,6 +317,21 @@
     def base(self):
         return None
 
+class ConcreteArray(ConcreteArrayNotOwning):
+    def __init__(self, shape, dtype, order, strides, backstrides):
+        # we allocate the actual storage later because we need to compute
+        # self.size first
+        null_storage = lltype.nullptr(RAW_STORAGE)
+        ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides,
+                                        null_storage)
+        self.storage = dtype.itemtype.malloc(self.size)
+
+    def __del__(self):
+        free_raw_storage(self.storage, track_allocation=False)
+
+
+        
+
 class NonWritableArray(ConcreteArray):
     def descr_setitem(self, space, orig_array, w_index, w_value):
         raise OperationError(space.w_RuntimeError, space.wrap(
@@ -331,6 +344,7 @@
         self.strides = strides
         self.backstrides = backstrides
         self.shape = shape
+        assert isinstance(parent, BaseConcreteArray)
         if isinstance(parent, SliceArray):
             parent = parent.parent # one level only
         self.parent = parent
diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
--- a/pypy/module/micronumpy/base.py
+++ b/pypy/module/micronumpy/base.py
@@ -30,8 +30,17 @@
         return W_NDimArray(impl)
 
     @staticmethod
-    def new_slice(offset, strides, backstrides, shape, parent, orig_arr,
-                  dtype=None):
+    def from_shape_and_storage(shape, storage, dtype, order='C'):
+        from pypy.module.micronumpy.arrayimpl import concrete
+        assert shape
+        strides, backstrides = calc_strides(shape, dtype, order)
+        impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides,
+                                               backstrides, storage)
+        return W_NDimArray(impl)
+
+
+    @staticmethod
+    def new_slice(offset, strides, backstrides, shape, parent, orig_arr, dtype=None):
         from pypy.module.micronumpy.arrayimpl import concrete
 
         impl = concrete.SliceArray(offset, strides, backstrides, shape, parent,
diff --git a/pypy/module/micronumpy/interp_flatiter.py b/pypy/module/micronumpy/interp_flatiter.py
--- a/pypy/module/micronumpy/interp_flatiter.py
+++ b/pypy/module/micronumpy/interp_flatiter.py
@@ -20,15 +20,14 @@
         return self.shape
 
     def create_iter(self, shape=None):
-        assert isinstance(self.base, W_NDimArray)
-        return self.base.create_iter()
+        assert isinstance(self.base(), W_NDimArray)
+        return self.base().create_iter()
 
 class W_FlatIterator(W_NDimArray):
     def __init__(self, arr):
         self.base = arr
         # this is needed to support W_NDimArray interface
-        imp = FakeArrayImplementation(self.base)
-        self.implementation = imp
+        self.implementation = FakeArrayImplementation(self.base)
         self.reset()
 
     def reset(self):
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
@@ -561,7 +561,6 @@
         raise OperationError(space.w_NotImplementedError, space.wrap(
             "view not implemented yet"))
 
-
     # --------------------- operations ----------------------------
 
     def _unaryop_impl(ufunc_name):
@@ -735,6 +734,20 @@
         return W_NDimArray.new_scalar(space, dtype)
     return W_NDimArray.from_shape(shape, dtype)
 
+ at unwrap_spec(addr=int)
+def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype):
+    """
+    Create an array from an existing buffer, given its address as int.
+    PyPy-only implementation detail.
+    """
+    from pypy.rpython.lltypesystem import rffi
+    from pypy.rlib.rawstorage import RAW_STORAGE_PTR
+    shape = _find_shape(space, w_shape)
+    storage = rffi.cast(RAW_STORAGE_PTR, addr)
+    dtype = space.interp_w(interp_dtype.W_Dtype,
+                           space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
+    return W_NDimArray.from_shape_and_storage(shape, storage, dtype)
+
 W_NDimArray.typedef = TypeDef(
     "ndarray",
     __new__ = interp2app(descr_new_array),
@@ -846,6 +859,8 @@
 
     ctypes = GetSetProperty(W_NDimArray.descr_get_ctypes), # XXX unimplemented
     __array_interface__ = GetSetProperty(W_NDimArray.descr_array_iface),
+   _from_shape_and_storage = interp2app(descr__from_shape_and_storage,
+                                        as_classmethod=True)
 )
 
 @unwrap_spec(ndmin=int, copy=bool, subok=bool)
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
@@ -189,7 +189,23 @@
         assert shape == [2]
         assert space.str_w(elems[0]) == "a"
         assert space.str_w(elems[1]) == "b"
-        
+
+    def test_from_shape_and_storage(self):
+        from pypy.rlib.rawstorage import alloc_raw_storage, raw_storage_setitem
+        from pypy.rpython.lltypesystem import rffi
+        from pypy.module.micronumpy.interp_dtype import get_dtype_cache
+        storage = alloc_raw_storage(4, track_allocation=False, zero=True)
+        for i in range(4):
+            raw_storage_setitem(storage, i, rffi.cast(rffi.UCHAR, i))
+        #
+        dtypes = get_dtype_cache(self.space)
+        w_array = W_NDimArray.from_shape_and_storage([2, 2], storage, dtypes.w_int8dtype)
+        def get(i, j):
+            return w_array.getitem(self.space, [i, j]).value
+        assert get(0, 0) == 0
+        assert get(0, 1) == 1
+        assert get(1, 0) == 2
+        assert get(1, 1) == 3
 
 class AppTestNumArray(BaseNumpyAppTest):
     def w_CustomIndexObject(self, index):
@@ -2482,7 +2498,7 @@
         s = repr(a)
         assert s.replace('\n', '') == \
                       "array(['abc', 'defg', 'ab'],       dtype='|S4')"
-         
+        
        
 class AppTestPyPy(BaseNumpyAppTest):
     def setup_class(cls):
@@ -2502,3 +2518,12 @@
         assert a[0][1] == 2
         a = _numpypy.array(([[[1, 2], [3, 4], [5, 6]]]))
         assert (a[0, 1] == [3, 4]).all()
+
+    def test_from_shape_and_storage(self):
+        from _numpypy import array, ndarray
+        x = array([1, 2, 3, 4])
+        addr, _ = x.__array_interface__['data']
+        y = ndarray._from_shape_and_storage([2, 2], addr, x.dtype)
+        assert y[0, 1] == 2
+        y[0, 1] = 42
+        assert x[1] == 42
diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py
--- a/pypy/module/pyexpat/interp_pyexpat.py
+++ b/pypy/module/pyexpat/interp_pyexpat.py
@@ -2,7 +2,7 @@
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
 from pypy.interpreter.error import OperationError
-from pypy.rlib import rgc
+from pypy.rlib import rgc, jit
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.tool import rffi_platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -288,6 +288,7 @@
         post_code = ''
 
     src = py.code.Source("""
+    @jit.jit_callback('XML:%(name)s')
     def %(name)s_callback(%(first_arg)s, %(args)s):
         id = rffi.cast(lltype.Signed, %(ll_id)s)
         userdata = global_storage.get_object(id)
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -6,7 +6,7 @@
 from pypy.tool.pairtype import extendabletype
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
-from pypy.rlib import jit, objectmodel
+from pypy.rlib import jit
 from pypy.rlib.jit import current_trace_length, unroll_parameters
 import pypy.interpreter.pyopcode   # for side-effects
 from pypy.interpreter.error import OperationError, operationerrfmt
@@ -97,15 +97,6 @@
                                     is_being_profiled=self.is_being_profiled)
         return jumpto
 
-callback_jit_driver = JitDriver(greens = ['name'], reds = 'auto')
-
-def callback_merge_point(name):
-    callback_jit_driver.jit_merge_point(name=name)
-
- at callback_jit_driver.inline(callback_merge_point)
-def callback_hook(name):
-    pass
-
 def _get_adapted_tick_counter():
     # Normally, the tick counter is decremented by 100 for every
     # Python opcode.  Here, to better support JIT compilation of
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -40,6 +40,7 @@
 includes = ['stdlib.h', 'src/signals.h']
 if sys.platform != 'win32':
     includes.append('sys/time.h')
+WIN32 = sys.platform == 'win32'
 
 cdir = py.path.local(autopath.pypydir).join('translator', 'c')
 
@@ -236,7 +237,10 @@
     None -- if an unknown handler is in effect (XXX UNIMPLEMENTED)
     anything else -- the callable Python object used as a handler
     """
-    check_signum_in_range(space, signum)
+    if WIN32:
+        check_signum_exists(space, signum)
+    else:
+        check_signum_in_range(space, signum)
     action = space.check_signal_action
     if signum in action.handlers_w:
         return action.handlers_w[signum]
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -55,7 +55,7 @@
             skip("requires os.kill() and os.getpid()")
         signal = self.signal   # the signal module to test
         if not hasattr(signal, 'SIGUSR1'):
-            py.test.skip("requires SIGUSR1 in signal")
+            skip("requires SIGUSR1 in signal")
         signum = signal.SIGUSR1
 
         received = []
@@ -156,6 +156,7 @@
         import sys
         if sys.platform == 'win32':
             raises(ValueError, signal, 42, lambda *args: None)
+            raises(ValueError, signal, 7, lambda *args: None)
         else:
             signal(42, lambda *args: None)
             signal(42, SIG_DFL)
diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py
--- a/pypy/module/thread/os_thread.py
+++ b/pypy/module/thread/os_thread.py
@@ -2,6 +2,7 @@
 Thread support based on OS-level threads.
 """
 
+import os
 from pypy.module.thread import ll_thread as thread
 from pypy.module.thread.error import wrap_thread_error
 from pypy.interpreter.error import OperationError, operationerrfmt
@@ -91,14 +92,18 @@
         # run!
         try:
             bootstrapper.run(space, w_callable, args)
-        finally:
-            bootstrapper.nbthreads -= 1
-            # clean up space.threadlocals to remove the ExecutionContext
-            # entry corresponding to the current thread
+            # done
+        except Exception, e:
+            # oups! last-level attempt to recover.
             try:
-                space.threadlocals.leave_thread(space)
-            finally:
-                thread.gc_thread_die()
+                STDERR = 2
+                os.write(STDERR, "Thread exited with ")
+                os.write(STDERR, str(e))
+                os.write(STDERR, "\n")
+            except OSError:
+                pass
+        bootstrapper.nbthreads -= 1
+        thread.gc_thread_die()
     bootstrap = staticmethod(bootstrap)
 
     def acquire(space, w_callable, args):
@@ -129,6 +134,9 @@
                 where = 'thread %d started by ' % ident
                 e.write_unraisable(space, where, w_callable)
             e.clear(space)
+        # clean up space.threadlocals to remove the ExecutionContext
+        # entry corresponding to the current thread
+        space.threadlocals.leave_thread(space)
     run = staticmethod(run)
 
 bootstrapper = Bootstrapper()
diff --git a/pypy/module/thread/test/test_gil.py b/pypy/module/thread/test/test_gil.py
--- a/pypy/module/thread/test/test_gil.py
+++ b/pypy/module/thread/test/test_gil.py
@@ -61,8 +61,9 @@
         def bootstrap():
             try:
                 runme()
-            finally:
-                thread.gc_thread_die()
+            except Exception, e:
+                assert 0
+            thread.gc_thread_die()
         def f():
             state.data = []
             state.datalen1 = 0
diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py
--- a/pypy/rlib/clibffi.py
+++ b/pypy/rlib/clibffi.py
@@ -421,6 +421,7 @@
                                    hints={'callback':True}))
 
 
+ at jit.jit_callback("CLIBFFI")
 def ll_callback(ffi_cif, ll_res, ll_args, ll_userdata):
     """ Callback specification.
     ffi_cif - something ffi specific, don't care
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -302,6 +302,32 @@
     pass
 
 
+def jit_callback(name):
+    """Use as a decorator for C callback functions, to insert a
+    jitdriver.jit_merge_point() at the start.  Only for callbacks
+    that typically invoke more app-level Python code.
+    """
+    def decorate(func):
+        from pypy.tool.sourcetools import compile2
+        #
+        def get_printable_location():
+            return name
+        jitdriver = JitDriver(get_printable_location=get_printable_location,
+                              greens=[], reds='auto', name=name)
+        #
+        args = ','.join(['a%d' % i for i in range(func.func_code.co_argcount)])
+        source = """def callback_with_jitdriver(%(args)s):
+                        jitdriver.jit_merge_point()
+                        return real_callback(%(args)s)""" % locals()
+        miniglobals = {
+            'jitdriver': jitdriver,
+            'real_callback': func,
+            }
+        exec compile2(source) in miniglobals
+        return miniglobals['callback_with_jitdriver']
+    return decorate
+
+
 # ____________________________________________________________
 # VRefs
 
@@ -458,9 +484,8 @@
             self.autoreds = True
             self.reds = []
             self.numreds = None # see warmspot.autodetect_jit_markers_redvars
-            for hook in (get_jitcell_at, set_jitcell_at, get_printable_location,
-                         confirm_enter_jit):
-                assert hook is None, "reds='auto' is not compatible with JitDriver hooks"
+            assert confirm_enter_jit is None, (
+                "reds='auto' is not compatible with confirm_enter_jit")
         else:
             if reds is not None:
                 self.reds = reds
diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py
+++ b/pypy/rlib/objectmodel.py
@@ -595,16 +595,6 @@
     llhelper(rffi.AroundFnPtr, before)
     llhelper(rffi.AroundFnPtr, after)
 
-def register_around_callback_hook(hook):
-    """ Register a hook that's called before a callback from C calls RPython.
-    Primary usage is for JIT to have 'started from' hook.
-    """
-    from pypy.rpython.lltypesystem import rffi
-    from pypy.rpython.annlowlevel import llhelper
-   
-    rffi.aroundstate.callback_hook = hook
-    llhelper(rffi.CallbackHookPtr, hook)
-
 def is_in_callback():
     from pypy.rpython.lltypesystem import rffi
     return rffi.stackcounter.stacks_counter > 1
diff --git a/pypy/rlib/runicode.py b/pypy/rlib/runicode.py
--- a/pypy/rlib/runicode.py
+++ b/pypy/rlib/runicode.py
@@ -460,6 +460,10 @@
                                  errorhandler=None,
                                  byteorder='little'):
     if size == 0:
+        if byteorder == 'native':
+            result = StringBuilder(2)
+            _STORECHAR(result, 0xFEFF, BYTEORDER)
+            return result.build()
         return ""
 
     result = StringBuilder(size * 2 + 2)
@@ -621,6 +625,10 @@
                                  errorhandler=None,
                                  byteorder='little'):
     if size == 0:
+        if byteorder == 'native':
+            result = StringBuilder(4)
+            _STORECHAR32(result, 0xFEFF, BYTEORDER)
+            return result.build()
         return ""
 
     result = StringBuilder(size * 4 + 4)
diff --git a/pypy/rlib/test/test_runicode.py b/pypy/rlib/test/test_runicode.py
--- a/pypy/rlib/test/test_runicode.py
+++ b/pypy/rlib/test/test_runicode.py
@@ -679,6 +679,11 @@
                          "utf-32 utf-32-be utf-32-le").split():
             self.checkencode(uni, encoding)
 
+    def test_empty(self):
+        for encoding in ("utf-8 utf-16 utf-16-be utf-16-le "
+                         "utf-32 utf-32-be utf-32-le").split():
+            self.checkencode(u'', encoding)
+
     def test_single_chars_utf8(self):
         # check every number of bytes per char
         for s in ["\xd7\x90", "\xd6\x96", "\xeb\x96\x95", "\xf0\x90\x91\x93"]:
diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -1,19 +1,19 @@
 import py
 from pypy.annotation import model as annmodel
-from pypy.rpython.lltypesystem import lltype, rstr
+from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem import ll2ctypes
-from pypy.rpython.lltypesystem.llmemory import cast_adr_to_ptr, cast_ptr_to_adr
+from pypy.rpython.lltypesystem.llmemory import cast_ptr_to_adr
 from pypy.rpython.lltypesystem.llmemory import itemoffsetof, raw_memcopy
 from pypy.annotation.model import lltype_to_annotation
 from pypy.tool.sourcetools import func_with_new_name
-from pypy.rlib.objectmodel import Symbolic, CDefinedIntSymbolic
-from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.objectmodel import Symbolic
+from pypy.rlib.objectmodel import keepalive_until_here, enforceargs
 from pypy.rlib import rarithmetic, rgc
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rpython.tool.rfficache import platform, sizeof_c_type
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rpython.annlowlevel import llhelper, llstr
+from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.rstring import StringBuilder, UnicodeBuilder, assert_str0
 from pypy.rlib import jit
@@ -279,17 +279,8 @@
     callable_name = getattr(callable, '__name__', '?')
     if callbackholder is not None:
         callbackholder.callbacks[callable] = True
-    callable_name_descr = str(callable).replace('"', '\\"')
     args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))])
     source = py.code.Source(r"""
-        def inner_wrapper(%(args)s):
-            if aroundstate is not None:
-                callback_hook = aroundstate.callback_hook
-                if callback_hook:
-                    callback_hook(llstr("%(callable_name_descr)s"))
-            return callable(%(args)s)
-        inner_wrapper._never_inline_ = True
-        
         def wrapper(%(args)s):    # no *args - no GIL for mallocing the tuple
             llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
             if aroundstate is not None:
@@ -299,7 +290,7 @@
             # from now on we hold the GIL
             stackcounter.stacks_counter += 1
             try:
-                result = inner_wrapper(%(args)s)
+                result = callable(%(args)s)
             except Exception, e:
                 os.write(2,
                     "Warning: uncaught exception in callback: %%s %%s\n" %%
@@ -321,7 +312,6 @@
     miniglobals = locals().copy()
     miniglobals['Exception'] = Exception
     miniglobals['os'] = os
-    miniglobals['llstr'] = llstr
     miniglobals['we_are_translated'] = we_are_translated
     miniglobals['stackcounter'] = stackcounter
     exec source.compile() in miniglobals
@@ -329,11 +319,8 @@
 _make_wrapper_for._annspecialcase_ = 'specialize:memo'
 
 AroundFnPtr = lltype.Ptr(lltype.FuncType([], lltype.Void))
-CallbackHookPtr = lltype.Ptr(lltype.FuncType([lltype.Ptr(rstr.STR)], lltype.Void))
 
 class AroundState:
-    callback_hook = None
-    
     def _cleanup_(self):
         self.before = None        # or a regular RPython function
         self.after = None         # or a regular RPython function
@@ -795,6 +782,7 @@
 
     # (char*, str, int, int) -> None
     @jit.dont_look_inside
+    @enforceargs(None, None, int, int)
     def str_from_buffer(raw_buf, gc_buf, allocated_size, needed_size):
         """
         Converts from a pair returned by alloc_buffer to a high-level string.
@@ -833,6 +821,7 @@
             lltype.free(raw_buf, flavor='raw')
 
     # char* -> str, with an upper bound on the length in case there is no \x00
+    @enforceargs(None, int)
     def charp2strn(cp, maxlen):
         b = builder_class(maxlen)
         i = 0
diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -979,6 +979,7 @@
         assert self.translator.config.translation.thread
         if hasattr(self.root_walker, 'thread_run_ptr'):
             livevars = self.push_roots(hop)
+            assert not livevars, "live GC var around %s!" % (hop.spaceop,)
             hop.genop("direct_call", [self.root_walker.thread_run_ptr])
             self.pop_roots(hop, livevars)
 
@@ -993,6 +994,7 @@
         assert self.translator.config.translation.thread
         if hasattr(self.root_walker, 'thread_die_ptr'):
             livevars = self.push_roots(hop)
+            assert not livevars, "live GC var around %s!" % (hop.spaceop,)
             hop.genop("direct_call", [self.root_walker.thread_die_ptr])
             self.pop_roots(hop, livevars)
 
diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py
--- a/pypy/rpython/memory/gctransform/shadowstack.py
+++ b/pypy/rpython/memory/gctransform/shadowstack.py
@@ -326,6 +326,8 @@
         self.gcdata.root_stack_top = llmemory.NULL  # to detect missing restore
 
     def forget_current_state(self):
+        ll_assert(self.gcdata.root_stack_base == self.gcdata.root_stack_top,
+                  "forget_current_state: shadowstack not empty!")
         if self.unused_full_stack:
             llmemory.raw_free(self.unused_full_stack)
         self.unused_full_stack = self.gcdata.root_stack_base
diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py
--- a/pypy/translator/goal/targetpypystandalone.py
+++ b/pypy/translator/goal/targetpypystandalone.py
@@ -28,11 +28,6 @@
     w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup))
     withjit = space.config.objspace.usemodules.pypyjit
 
-    if withjit:
-        from pypy.module.pypyjit.interp_jit import callback_hook
-        from pypy.rlib import objectmodel
-        objectmodel.register_around_callback_hook(callback_hook)
-
     def entry_point(argv):
         if withjit:
             from pypy.jit.backend.hlinfo import highleveljitinfo


More information about the pypy-commit mailing list