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

bivab noreply at buildbot.pypy.org
Sat Jan 21 13:39:54 CET 2012


Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r51574:f81818811f73
Date: 2012-01-21 12:32 +0100
http://bitbucket.org/pypy/pypy/changeset/f81818811f73/

Log:	merge default

diff --git a/pypy/doc/translation.rst b/pypy/doc/translation.rst
--- a/pypy/doc/translation.rst
+++ b/pypy/doc/translation.rst
@@ -155,7 +155,7 @@
                    function.  The two input variables are the exception class
                    and the exception value, respectively.  (No other block will
                    actually link to the exceptblock if the function does not
-                   explicitely raise exceptions.)
+                   explicitly raise exceptions.)
 
 
 ``Block``
@@ -325,7 +325,7 @@
 Mutable objects need special treatment during annotation, because
 the annotation of contained values needs to be possibly updated to account
 for mutation operations, and consequently the annotation information
-reflown through the relevant parts of the flow the graphs.
+reflown through the relevant parts of the flow graphs.
 
 * ``SomeList`` stands for a list of homogeneous type (i.e. all the
   elements of the list are represented by a single common ``SomeXxx``
@@ -503,8 +503,8 @@
 
 Since RPython is a garbage collected language there is a lot of heap memory
 allocation going on all the time, which would either not occur at all in a more
-traditional explicitely managed language or results in an object which dies at
-a time known in advance and can thus be explicitely deallocated. For example a
+traditional explicitly managed language or results in an object which dies at
+a time known in advance and can thus be explicitly deallocated. For example a
 loop of the following form::
 
     for i in range(n):
@@ -696,7 +696,7 @@
 
 So far it is the second most mature high level backend after GenCLI:
 it still can't translate the full Standard Interpreter, but after the
-Leysin sprint we were able to compile and run the rpytstone and
+Leysin sprint we were able to compile and run the rpystone and
 richards benchmarks.
 
 GenJVM is almost entirely the work of Niko Matsakis, who worked on it
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
@@ -1118,6 +1118,12 @@
             for src, dst in singlefloats:
                 self.mc.MOVD(dst, src)
         # Finally remap the arguments in the main regs
+        # If x is a register and is in dst_locs, then oups, it needs to
+        # be moved away:
+        if x in dst_locs:
+            src_locs.append(x)
+            dst_locs.append(r10)
+            x = r10
         remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG)
 
         self._regalloc.reserve_param(len(pass_on_stack))
@@ -2042,10 +2048,7 @@
         size = sizeloc.value
         signloc = arglocs[1]
 
-        if isinstance(op.getarg(0), Const):
-            x = imm(op.getarg(0).getint())
-        else:
-            x = arglocs[2]
+        x = arglocs[2]     # the function address
         if x is eax:
             tmp = ecx
         else:
diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -6,7 +6,7 @@
 from pypy.jit.codewriter import longlong
 from pypy.jit.metainterp import history, compile
 from pypy.jit.backend.x86.assembler import Assembler386
-from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS
+from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS, IS_X86_32
 from pypy.jit.backend.x86.profagent import ProfileAgent
 from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU
 from pypy.jit.backend.x86 import regloc
@@ -142,7 +142,9 @@
     cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)'
     cast_ptr_to_int = staticmethod(cast_ptr_to_int)
 
-    all_null_registers = lltype.malloc(rffi.LONGP.TO, 24,
+    all_null_registers = lltype.malloc(rffi.LONGP.TO,
+                                       IS_X86_32 and (16+8)  # 16 + 8 regs
+                                                 or (16+16), # 16 + 16 regs
                                        flavor='raw', zero=True,
                                        immortal=True)
 
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -70,6 +70,7 @@
         ("exp", "exp"),
         ("fabs", "fabs"),
         ("floor", "floor"),
+        ("ceil", "ceil"),
         ("greater", "greater"),
         ("greater_equal", "greater_equal"),
         ("less", "less"),
@@ -85,6 +86,8 @@
         ("subtract", "subtract"),
         ('sqrt', 'sqrt'),
         ("tan", "tan"),
+        ('bitwise_and', 'bitwise_and'),
+        ('bitwise_or', 'bitwise_or'),
     ]:
         interpleveldefs[exposed] = "interp_ufuncs.get(space).%s" % impl
 
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -47,6 +47,10 @@
     def getitem(self, storage, i):
         return self.itemtype.read(storage, self.itemtype.get_element_size(), i, 0)
 
+    def getitem_bool(self, storage, i):
+        isize = self.itemtype.get_element_size()
+        return self.itemtype.read_bool(storage, isize, i, 0)
+
     def setitem(self, storage, i, box):
         self.itemtype.store(storage, self.itemtype.get_element_size(), i, 0, box)
 
@@ -85,6 +89,12 @@
     def descr_get_shape(self, space):
         return space.newtuple([])
 
+    def is_int_type(self):
+        return self.kind == SIGNEDLTR or self.kind == UNSIGNEDLTR
+
+    def is_bool_type(self):
+        return self.kind == BOOLLTR
+
 W_Dtype.typedef = TypeDef("dtype",
     __module__ = "numpypy",
     __new__ = interp2app(W_Dtype.descr__new__.im_func),
diff --git a/pypy/module/micronumpy/interp_iter.py b/pypy/module/micronumpy/interp_iter.py
--- a/pypy/module/micronumpy/interp_iter.py
+++ b/pypy/module/micronumpy/interp_iter.py
@@ -4,6 +4,19 @@
 from pypy.module.micronumpy.strides import calculate_broadcast_strides,\
      calculate_slice_strides
 
+# structures to describe slicing
+
+class Chunk(object):
+    def __init__(self, start, stop, step, lgt):
+        self.start = start
+        self.stop = stop
+        self.step = step
+        self.lgt = lgt
+
+    def extend_shape(self, shape):
+        if self.step != 0:
+            shape.append(self.lgt)
+
 class BaseTransform(object):
     pass
 
@@ -38,11 +51,18 @@
         self.size = size
 
     def next(self, shapelen):
+        return self._next(1)
+
+    def _next(self, ofs):
         arr = instantiate(ArrayIterator)
         arr.size = self.size
-        arr.offset = self.offset + 1
+        arr.offset = self.offset + ofs
         return arr
 
+    def next_no_increase(self, shapelen):
+        # a hack to make JIT believe this is always virtual
+        return self._next(0)
+
     def done(self):
         return self.offset >= self.size
 
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
@@ -2,14 +2,15 @@
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import interp2app, NoneNotWrapped
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.module.micronumpy import interp_ufuncs, interp_dtype, signature
+from pypy.module.micronumpy import interp_ufuncs, interp_dtype, signature,\
+     interp_boxes
 from pypy.module.micronumpy.strides import calculate_slice_strides
 from pypy.rlib import jit
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib.rstring import StringBuilder
 from pypy.module.micronumpy.interp_iter import ArrayIterator, OneDimIterator,\
-     SkipLastAxisIterator
+     SkipLastAxisIterator, Chunk, ViewIterator
 
 numpy_driver = jit.JitDriver(
     greens=['shapelen', 'sig'],
@@ -39,7 +40,24 @@
     get_printable_location=signature.new_printable_location('slice'),
     name='numpy_slice',
 )
-
+count_driver = jit.JitDriver(
+    greens=['shapelen'],
+    virtualizables=['frame'],
+    reds=['s', 'frame', 'iter', 'arr'],
+    name='numpy_count'
+)
+filter_driver = jit.JitDriver(
+    greens=['shapelen', 'sig'],
+    virtualizables=['frame'],
+    reds=['concr', 'argi', 'ri', 'frame', 'v', 'res', 'self'],
+    name='numpy_filter',
+)
+filter_set_driver = jit.JitDriver(
+    greens=['shapelen', 'sig'],
+    virtualizables=['frame'],
+    reds=['idx', 'idxi', 'frame', 'arr'],
+    name='numpy_filterset',
+)
 
 def _find_shape_and_elems(space, w_iterable):
     shape = [space.len_w(w_iterable)]
@@ -270,6 +288,9 @@
     descr_gt = _binop_impl("greater")
     descr_ge = _binop_impl("greater_equal")
 
+    descr_and = _binop_impl("bitwise_and")
+    descr_or = _binop_impl("bitwise_or")
+
     def _binop_right_impl(ufunc_name):
         def impl(self, space, w_other):
             w_other = scalar_w(space,
@@ -479,11 +500,69 @@
     def _prepare_slice_args(self, space, w_idx):
         if (space.isinstance_w(w_idx, space.w_int) or
             space.isinstance_w(w_idx, space.w_slice)):
-            return [space.decode_index4(w_idx, self.shape[0])]
-        return [space.decode_index4(w_item, self.shape[i]) for i, w_item in
+            return [Chunk(*space.decode_index4(w_idx, self.shape[0]))]
+        return [Chunk(*space.decode_index4(w_item, self.shape[i])) for i, w_item in
                 enumerate(space.fixedview(w_idx))]
 
+    def count_all_true(self, arr):
+        sig = arr.find_sig()
+        frame = sig.create_frame(self)
+        shapelen = len(arr.shape)
+        s = 0
+        iter = None
+        while not frame.done():
+            count_driver.jit_merge_point(arr=arr, frame=frame, iter=iter, s=s,
+                                         shapelen=shapelen)
+            iter = frame.get_final_iter()
+            s += arr.dtype.getitem_bool(arr.storage, iter.offset)
+            frame.next(shapelen)
+        return s
+
+    def getitem_filter(self, space, arr):
+        concr = arr.get_concrete()
+        size = self.count_all_true(concr)
+        res = W_NDimArray(size, [size], self.find_dtype())
+        ri = ArrayIterator(size)
+        shapelen = len(self.shape)
+        argi = concr.create_iter()
+        sig = self.find_sig()
+        frame = sig.create_frame(self)
+        v = None
+        while not frame.done():
+            filter_driver.jit_merge_point(concr=concr, argi=argi, ri=ri,
+                                          frame=frame, v=v, res=res, sig=sig,
+                                          shapelen=shapelen, self=self)
+            if concr.dtype.getitem_bool(concr.storage, argi.offset):
+                v = sig.eval(frame, self)
+                res.setitem(ri.offset, v)
+                ri = ri.next(1)
+            else:
+                ri = ri.next_no_increase(1)
+            argi = argi.next(shapelen)
+            frame.next(shapelen)
+        return res
+
+    def setitem_filter(self, space, idx, val):
+        size = self.count_all_true(idx)
+        arr = SliceArray([size], self.dtype, self, val)
+        sig = arr.find_sig()
+        shapelen = len(self.shape)
+        frame = sig.create_frame(arr)
+        idxi = idx.create_iter()
+        while not frame.done():
+            filter_set_driver.jit_merge_point(idx=idx, idxi=idxi, sig=sig,
+                                              frame=frame, arr=arr,
+                                              shapelen=shapelen)
+            if idx.dtype.getitem_bool(idx.storage, idxi.offset):
+                sig.eval(frame, arr)
+                frame.next_from_second(1)
+            frame.next_first(shapelen)
+            idxi = idxi.next(shapelen)
+
     def descr_getitem(self, space, w_idx):
+        if (isinstance(w_idx, BaseArray) and w_idx.shape == self.shape and
+            w_idx.find_dtype().is_bool_type()):
+            return self.getitem_filter(space, w_idx)
         if self._single_item_result(space, w_idx):
             concrete = self.get_concrete()
             item = concrete._index_of_single_item(space, w_idx)
@@ -493,6 +572,11 @@
 
     def descr_setitem(self, space, w_idx, w_value):
         self.invalidated()
+        if (isinstance(w_idx, BaseArray) and w_idx.shape == self.shape and
+            w_idx.find_dtype().is_bool_type()):
+            return self.get_concrete().setitem_filter(space,
+                                                      w_idx.get_concrete(),
+                                             convert_to_array(space, w_value))
         if self._single_item_result(space, w_idx):
             concrete = self.get_concrete()
             item = concrete._index_of_single_item(space, w_idx)
@@ -509,9 +593,8 @@
     def create_slice(self, chunks):
         shape = []
         i = -1
-        for i, (start_, stop, step, lgt) in enumerate(chunks):
-            if step != 0:
-                shape.append(lgt)
+        for i, chunk in enumerate(chunks):
+            chunk.extend_shape(shape)
         s = i + 1
         assert s >= 0
         shape += self.shape[s:]
@@ -724,8 +807,7 @@
                                          frame=frame,
                                          ri=ri,
                                          self=self, result=result)
-            result.dtype.setitem(result.storage, ri.offset,
-                                 sig.eval(frame, self))
+            result.setitem(ri.offset, sig.eval(frame, self))
             frame.next(shapelen)
             ri = ri.next(shapelen)
         return result
@@ -945,7 +1027,7 @@
                             builder.append('\n' + indent)
                         else:
                             builder.append(indent)
-                    view = self.create_slice([(i, 0, 0, 1)]).get_concrete()
+                    view = self.create_slice([Chunk(i, 0, 0, 1)]).get_concrete()
                     view.to_str(space, comma, builder, indent=indent + ' ',
                                                     use_ellipsis=use_ellipsis)
                 if i < self.shape[0] - 1:
@@ -962,7 +1044,7 @@
                         builder.append(indent)
                 # create_slice requires len(chunks) > 1 in order to reduce
                 # shape
-                view = self.create_slice([(i, 0, 0, 1)]).get_concrete()
+                view = self.create_slice([Chunk(i, 0, 0, 1)]).get_concrete()
                 view.to_str(space, comma, builder, indent=indent + ' ',
                                                     use_ellipsis=use_ellipsis)
                 i += 1
@@ -1091,6 +1173,10 @@
                                parent)
         self.start = start
 
+    def create_iter(self):
+        return ViewIterator(self.start, self.strides, self.backstrides,
+                            self.shape)
+
     def setshape(self, space, new_shape):
         if len(self.shape) < 1:
             return
@@ -1137,6 +1223,9 @@
         self.shape = new_shape
         self.calc_strides(new_shape)
 
+    def create_iter(self):
+        return ArrayIterator(self.size)
+
     def create_sig(self):
         return signature.ArraySignature(self.dtype)
 
@@ -1191,6 +1280,7 @@
     arr = W_NDimArray(size, shape[:], dtype=dtype, order=order)
     shapelen = len(shape)
     arr_iter = ArrayIterator(arr.size)
+    # XXX we might want to have a jitdriver here
     for i in range(len(elems_w)):
         w_elem = elems_w[i]
         dtype.setitem(arr.storage, arr_iter.offset,
@@ -1257,6 +1347,9 @@
     __gt__ = interp2app(BaseArray.descr_gt),
     __ge__ = interp2app(BaseArray.descr_ge),
 
+    __and__ = interp2app(BaseArray.descr_and),
+    __or__ = interp2app(BaseArray.descr_or),
+
     __repr__ = interp2app(BaseArray.descr_repr),
     __str__ = interp2app(BaseArray.descr_str),
     __array_interface__ = GetSetProperty(BaseArray.descr_array_iface),
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
@@ -249,15 +249,16 @@
 
 
 class W_Ufunc2(W_Ufunc):
-    _immutable_fields_ = ["comparison_func", "func", "name"]
+    _immutable_fields_ = ["comparison_func", "func", "name", "int_only"]
     argcount = 2
 
     def __init__(self, func, name, promote_to_float=False, promote_bools=False,
-        identity=None, comparison_func=False):
+        identity=None, comparison_func=False, int_only=False):
 
         W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity)
         self.func = func
         self.comparison_func = comparison_func
+        self.int_only = int_only
 
     def call(self, space, args_w):
         from pypy.module.micronumpy.interp_numarray import (Call2,
@@ -268,6 +269,7 @@
         w_rhs = convert_to_array(space, w_rhs)
         calc_dtype = find_binop_result_dtype(space,
             w_lhs.find_dtype(), w_rhs.find_dtype(),
+            int_only=self.int_only,
             promote_to_float=self.promote_to_float,
             promote_bools=self.promote_bools,
         )
@@ -304,10 +306,12 @@
 
 
 def find_binop_result_dtype(space, dt1, dt2, promote_to_float=False,
-    promote_bools=False):
+    promote_bools=False, int_only=False):
     # dt1.num should be <= dt2.num
     if dt1.num > dt2.num:
         dt1, dt2 = dt2, dt1
+    if int_only and (not dt1.is_int_type() or not dt2.is_int_type()):
+        raise OperationError(space.w_TypeError, space.wrap("Unsupported types"))
     # Some operations promote op(bool, bool) to return int8, rather than bool
     if promote_bools and (dt1.kind == dt2.kind == interp_dtype.BOOLLTR):
         return interp_dtype.get_dtype_cache(space).w_int8dtype
@@ -425,6 +429,10 @@
             ("add", "add", 2, {"identity": 0}),
             ("subtract", "sub", 2),
             ("multiply", "mul", 2, {"identity": 1}),
+            ("bitwise_and", "bitwise_and", 2, {"identity": 1,
+                                               'int_only': True}),
+            ("bitwise_or", "bitwise_or", 2, {"identity": 0,
+                                             'int_only': True}),
             ("divide", "div", 2, {"promote_bools": True}),
             ("mod", "mod", 2, {"promote_bools": True}),
             ("power", "pow", 2, {"promote_bools": True}),
@@ -449,6 +457,7 @@
 
             ("fabs", "fabs", 1, {"promote_to_float": True}),
             ("floor", "floor", 1, {"promote_to_float": True}),
+            ("ceil", "ceil", 1, {"promote_to_float": True}),
             ("exp", "exp", 1, {"promote_to_float": True}),
 
             ('sqrt', 'sqrt', 1, {'promote_to_float': True}),
@@ -475,7 +484,7 @@
         extra_kwargs["identity"] = identity
 
         func = ufunc_dtype_caller(space, ufunc_name, op_name, argcount,
-            comparison_func=extra_kwargs.get("comparison_func", False)
+            comparison_func=extra_kwargs.get("comparison_func", False),
         )
         if argcount == 1:
             ufunc = W_Ufunc1(func, ufunc_name, **extra_kwargs)
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
--- a/pypy/module/micronumpy/signature.py
+++ b/pypy/module/micronumpy/signature.py
@@ -82,6 +82,16 @@
         for i in range(len(self.iterators)):
             self.iterators[i] = self.iterators[i].next(shapelen)
 
+    @unroll_safe
+    def next_from_second(self, shapelen):
+        """ Don't increase the first iterator
+        """
+        for i in range(1, len(self.iterators)):
+            self.iterators[i] = self.iterators[i].next(shapelen)
+
+    def next_first(self, shapelen):
+        self.iterators[0] = self.iterators[0].next(shapelen)
+
     def get_final_iter(self):
         final_iter = promote(self.final_iter)
         if final_iter < 0:
diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
--- a/pypy/module/micronumpy/strides.py
+++ b/pypy/module/micronumpy/strides.py
@@ -10,12 +10,12 @@
     rstart = start
     rshape = []
     i = -1
-    for i, (start_, stop, step, lgt) in enumerate(chunks):
-        if step != 0:
-            rstrides.append(strides[i] * step)
-            rbackstrides.append(strides[i] * (lgt - 1) * step)
-            rshape.append(lgt)
-        rstart += strides[i] * start_
+    for i, chunk in enumerate(chunks):
+        if chunk.step != 0:
+            rstrides.append(strides[i] * chunk.step)
+            rbackstrides.append(strides[i] * (chunk.lgt - 1) * chunk.step)
+            rshape.append(chunk.lgt)
+        rstart += strides[i] * chunk.start
     # add a reminder
     s = i + 1
     assert s >= 0
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
@@ -2,6 +2,7 @@
 import py
 from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
 from pypy.module.micronumpy.interp_numarray import W_NDimArray, shape_agreement
+from pypy.module.micronumpy.interp_iter import Chunk
 from pypy.module.micronumpy import signature
 from pypy.interpreter.error import OperationError
 from pypy.conftest import gettestobjspace
@@ -37,53 +38,54 @@
 
     def test_create_slice_f(self):
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
-        s = a.create_slice([(3, 0, 0, 1)])
+        s = a.create_slice([Chunk(3, 0, 0, 1)])
         assert s.start == 3
         assert s.strides == [10, 50]
         assert s.backstrides == [40, 100]
-        s = a.create_slice([(1, 9, 2, 4)])
+        s = a.create_slice([Chunk(1, 9, 2, 4)])
         assert s.start == 1
         assert s.strides == [2, 10, 50]
         assert s.backstrides == [6, 40, 100]
-        s = a.create_slice([(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
+        s = a.create_slice([Chunk(1, 5, 3, 2), Chunk(1, 2, 1, 1), Chunk(1, 0, 0, 1)])
         assert s.shape == [2, 1]
         assert s.strides == [3, 10]
         assert s.backstrides == [3, 0]
-        s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
+        s = a.create_slice([Chunk(0, 10, 1, 10), Chunk(2, 0, 0, 1)])
         assert s.start == 20
         assert s.shape == [10, 3]
 
     def test_create_slice_c(self):
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
-        s = a.create_slice([(3, 0, 0, 1)])
+        s = a.create_slice([Chunk(3, 0, 0, 1)])
         assert s.start == 45
         assert s.strides == [3, 1]
         assert s.backstrides == [12, 2]
-        s = a.create_slice([(1, 9, 2, 4)])
+        s = a.create_slice([Chunk(1, 9, 2, 4)])
         assert s.start == 15
         assert s.strides == [30, 3, 1]
         assert s.backstrides == [90, 12, 2]
-        s = a.create_slice([(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
+        s = a.create_slice([Chunk(1, 5, 3, 2), Chunk(1, 2, 1, 1),
+                            Chunk(1, 0, 0, 1)])
         assert s.start == 19
         assert s.shape == [2, 1]
         assert s.strides == [45, 3]
         assert s.backstrides == [45, 0]
-        s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
+        s = a.create_slice([Chunk(0, 10, 1, 10), Chunk(2, 0, 0, 1)])
         assert s.start == 6
         assert s.shape == [10, 3]
 
     def test_slice_of_slice_f(self):
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
-        s = a.create_slice([(5, 0, 0, 1)])
+        s = a.create_slice([Chunk(5, 0, 0, 1)])
         assert s.start == 5
-        s2 = s.create_slice([(3, 0, 0, 1)])
+        s2 = s.create_slice([Chunk(3, 0, 0, 1)])
         assert s2.shape == [3]
         assert s2.strides == [50]
         assert s2.parent is a
         assert s2.backstrides == [100]
         assert s2.start == 35
-        s = a.create_slice([(1, 5, 3, 2)])
-        s2 = s.create_slice([(0, 2, 1, 2), (2, 0, 0, 1)])
+        s = a.create_slice([Chunk(1, 5, 3, 2)])
+        s2 = s.create_slice([Chunk(0, 2, 1, 2), Chunk(2, 0, 0, 1)])
         assert s2.shape == [2, 3]
         assert s2.strides == [3, 50]
         assert s2.backstrides == [3, 100]
@@ -91,16 +93,16 @@
 
     def test_slice_of_slice_c(self):
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
-        s = a.create_slice([(5, 0, 0, 1)])
+        s = a.create_slice([Chunk(5, 0, 0, 1)])
         assert s.start == 15 * 5
-        s2 = s.create_slice([(3, 0, 0, 1)])
+        s2 = s.create_slice([Chunk(3, 0, 0, 1)])
         assert s2.shape == [3]
         assert s2.strides == [1]
         assert s2.parent is a
         assert s2.backstrides == [2]
         assert s2.start == 5 * 15 + 3 * 3
-        s = a.create_slice([(1, 5, 3, 2)])
-        s2 = s.create_slice([(0, 2, 1, 2), (2, 0, 0, 1)])
+        s = a.create_slice([Chunk(1, 5, 3, 2)])
+        s2 = s.create_slice([Chunk(0, 2, 1, 2), Chunk(2, 0, 0, 1)])
         assert s2.shape == [2, 3]
         assert s2.strides == [45, 1]
         assert s2.backstrides == [45, 2]
@@ -108,14 +110,14 @@
 
     def test_negative_step_f(self):
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
-        s = a.create_slice([(9, -1, -2, 5)])
+        s = a.create_slice([Chunk(9, -1, -2, 5)])
         assert s.start == 9
         assert s.strides == [-2, 10, 50]
         assert s.backstrides == [-8, 40, 100]
 
     def test_negative_step_c(self):
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
-        s = a.create_slice([(9, -1, -2, 5)])
+        s = a.create_slice([Chunk(9, -1, -2, 5)])
         assert s.start == 135
         assert s.strides == [-30, 3, 1]
         assert s.backstrides == [-120, 12, 2]
@@ -124,7 +126,7 @@
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
         r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
         assert r == 1 + 2 * 10 + 2 * 50
-        s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
+        s = a.create_slice([Chunk(0, 10, 1, 10), Chunk(2, 0, 0, 1)])
         r = s._index_of_single_item(self.space, self.newtuple(1, 0))
         assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
         r = s._index_of_single_item(self.space, self.newtuple(1, 1))
@@ -134,7 +136,7 @@
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
         r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
         assert r == 1 * 3 * 5 + 2 * 3 + 2
-        s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
+        s = a.create_slice([Chunk(0, 10, 1, 10), Chunk(2, 0, 0, 1)])
         r = s._index_of_single_item(self.space, self.newtuple(1, 0))
         assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
         r = s._index_of_single_item(self.space, self.newtuple(1, 1))
@@ -1302,15 +1304,25 @@
         assert isinstance(i['data'][0], int)
         raises(TypeError, getattr, array(3), '__array_interface__')
 
+    def test_array_indexing_one_elem(self):
+        skip("not yet")
+        from _numpypy import array, arange
+        raises(IndexError, 'arange(3)[array([3.5])]')
+        a = arange(3)[array([1])]
+        assert a == 1
+        assert a[0] == 1
+        raises(IndexError,'arange(3)[array([15])]')
+        assert arange(3)[array([-3])] == 0
+        raises(IndexError,'arange(3)[array([-15])]')
+        assert arange(3)[array(1)] == 1
+
     def test_fill(self):
         from _numpypy import array
-
         a = array([1, 2, 3])
         a.fill(10)
         assert (a == [10, 10, 10]).all()
         a.fill(False)
         assert (a == [0, 0, 0]).all()
-
         b = a[:1]
         b.fill(4)
         assert (b == [4]).all()
@@ -1324,6 +1336,24 @@
         d.fill(100)
         assert d == 100
 
+    def test_array_indexing_bool(self):
+        from _numpypy import arange
+        a = arange(10)
+        assert (a[a > 3] == [4, 5, 6, 7, 8, 9]).all()
+        a = arange(10).reshape(5, 2)
+        assert (a[a > 3] == [4, 5, 6, 7, 8, 9]).all()
+        assert (a[a & 1 == 1] == [1, 3, 5, 7, 9]).all()
+
+    def test_array_indexing_bool_setitem(self):
+        from _numpypy import arange, array
+        a = arange(6)
+        a[a > 3] = 15
+        assert (a == [0, 1, 2, 3, 15, 15]).all()
+        a = arange(6).reshape(3, 2)
+        a[a & 1 == 1] = array([8, 9, 10])
+        assert (a == [[0, 8], [2, 9], [4, 10]]).all()
+
+
 
 class AppTestSupport(BaseNumpyAppTest):
     def setup_class(cls):
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
@@ -190,14 +190,24 @@
         for i in range(3):
             assert c[i] == a[i] - b[i]
 
-    def test_floor(self):
-        from _numpypy import array, floor
-
-        reference = [-2.0, -1.0, 0.0, 1.0, 1.0]
-        a = array([-1.4, -1.0, 0.0, 1.0, 1.4])
+    def test_floorceil(self):
+        from _numpypy import array, floor, ceil
+        import math
+        reference = [-2.0, -2.0, -1.0, 0.0, 1.0, 1.0, 0]
+        a = array([-1.4, -1.5, -1.0, 0.0, 1.0, 1.4, 0.5])
         b = floor(a)
         for i in range(5):
             assert b[i] == reference[i]
+        reference = [-1.0, -1.0, -1.0, 0.0, 1.0, 2.0, 1.0]
+        a = array([-1.4, -1.5, -1.0, 0.0, 1.0, 1.4, 0.5])
+        b = ceil(a)
+        assert (reference == b).all()
+        inf = float("inf")
+        data = [1.5, 2.9999, -1.999, inf]
+        results = [math.floor(x) for x in data]
+        assert (floor(data) == results).all()
+        results = [math.ceil(x) for x in data]
+        assert (ceil(data) == results).all()
 
     def test_copysign(self):
         from _numpypy import array, copysign
@@ -238,7 +248,7 @@
             assert b[i] == math.sin(a[i])
 
         a = sin(array([True, False], dtype=bool))
-        assert abs(a[0] - sin(1)) < 1e-7 # a[0] will be less precise
+        assert abs(a[0] - sin(1)) < 1e-7  # a[0] will be less precise
         assert a[1] == 0.0
 
     def test_cos(self):
@@ -259,7 +269,6 @@
         for i in range(len(a)):
             assert b[i] == math.tan(a[i])
 
-
     def test_arcsin(self):
         import math
         from _numpypy import array, arcsin
@@ -283,7 +292,6 @@
         for i in range(len(a)):
             assert b[i] == math.acos(a[i])
 
-
         a = array([-10, -1.5, -1.01, 1.01, 1.5, 10, float('nan'), float('inf'), float('-inf')])
         b = arccos(a)
         for f in b:
@@ -347,11 +355,20 @@
         raises(ValueError, maximum.reduce, [])
 
     def test_reduceND(self):
-        from numpypy import add, arange
+        from _numpypy import add, arange
         a = arange(12).reshape(3, 4)
         assert (add.reduce(a, 0) == [12, 15, 18, 21]).all()
         assert (add.reduce(a, 1) == [6.0, 22.0, 38.0]).all()
 
+    def test_bitwise(self):
+        from _numpypy import bitwise_and, bitwise_or, arange, array
+        a = arange(6).reshape(2, 3)
+        assert (a & 1 == [[0, 1, 0], [1, 0, 1]]).all()
+        assert (a & 1 == bitwise_and(a, 1)).all()
+        assert (a | 1 == [[1, 1, 3], [3, 5, 5]]).all()
+        assert (a | 1 == bitwise_or(a, 1)).all()
+        raises(TypeError, 'array([1.0]) & 1')
+
     def test_comparisons(self):
         import operator
         from _numpypy import equal, not_equal, less, less_equal, greater, greater_equal
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
@@ -217,6 +217,7 @@
         # This is the sum of the ops for both loops, however if you remove the
         # optimization then you end up with 2 float_adds, so we can still be
         # sure it was optimized correctly.
+        py.test.skip("too fragile")
         self.check_resops({'setinteriorfield_raw': 4, 'getfield_gc': 22,
                            'getarrayitem_gc': 4, 'getarrayitem_gc_pure': 2,
                            'getfield_gc_pure': 8,
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -94,6 +94,9 @@
             width, storage, i, offset
         ))
 
+    def read_bool(self, storage, width, i, offset):
+        raise NotImplementedError
+
     def store(self, storage, width, i, offset, box):
         value = self.unbox(box)
         libffi.array_setitem(clibffi.cast_type_to_ffitype(self.T),
@@ -168,6 +171,7 @@
     @simple_binary_op
     def min(self, v1, v2):
         return min(v1, v2)
+    
 
 class Bool(BaseType, Primitive):
     T = lltype.Bool
@@ -185,6 +189,11 @@
         else:
             return self.False
 
+
+    def read_bool(self, storage, width, i, offset):
+        return libffi.array_getitem(clibffi.cast_type_to_ffitype(self.T),
+                                    width, storage, i, offset)
+
     def coerce_subtype(self, space, w_subtype, w_item):
         # Doesn't return subclasses so it can return the constants.
         return self._coerce(space, w_item)
@@ -253,6 +262,14 @@
             assert v == 0
             return 0
 
+    @simple_binary_op
+    def bitwise_and(self, v1, v2):
+        return v1 & v2
+
+    @simple_binary_op
+    def bitwise_or(self, v1, v2):
+        return v1 | v2
+
 class Int8(BaseType, Integer):
     T = rffi.SIGNEDCHAR
     BoxType = interp_boxes.W_Int8Box
@@ -374,6 +391,10 @@
         return math.floor(v)
 
     @simple_unary_op
+    def ceil(self, v):
+        return math.ceil(v)
+
+    @simple_unary_op
     def exp(self, v):
         try:
             return math.exp(v)
@@ -436,4 +457,4 @@
 class Float64(BaseType, Float):
     T = rffi.DOUBLE
     BoxType = interp_boxes.W_Float64Box
-    format_code = "d"
\ No newline at end of file
+    format_code = "d"
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -624,8 +624,8 @@
 
     if step == 1:
         assert start >= 0
-        assert slicelength >= 0
-        del items[start:start+slicelength]
+        if slicelength > 0:
+            del items[start:start+slicelength]
     else:
         n = len(items)
         i = start
@@ -662,10 +662,11 @@
             while i >= lim:
                 items[i] = items[i-delta]
                 i -= 1
-        elif start >= 0:
+        elif delta == 0:
+            pass
+        else:
+            assert start >= 0   # start<0 is only possible with slicelength==0
             del items[start:start+delta]
-        else:
-            assert delta==0   # start<0 is only possible with slicelength==0
     elif len2 != slicelength:  # No resize for extended slices
         raise operationerrfmt(space.w_ValueError, "attempt to "
               "assign sequence of size %d to extended slice of size %d",
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -804,10 +804,11 @@
                 while i >= lim:
                     items[i] = items[i-delta]
                     i -= 1
-            elif start >= 0:
+            elif delta == 0:
+                pass
+            else:
+                assert start >= 0 # start<0 is only possible with slicelength==0
                 del items[start:start+delta]
-            else:
-                assert delta==0   # start<0 is only possible with slicelength==0
         elif len2 != slicelength:  # No resize for extended slices
             raise operationerrfmt(self.space.w_ValueError, "attempt to "
                   "assign sequence of size %d to extended slice of size %d",
@@ -851,8 +852,8 @@
 
         if step == 1:
             assert start >= 0
-            assert slicelength >= 0
-            del items[start:start+slicelength]
+            if slicelength > 0:
+                del items[start:start+slicelength]
         else:
             n = len(items)
             i = start
diff --git a/pypy/objspace/std/test/test_bytearrayobject.py b/pypy/objspace/std/test/test_bytearrayobject.py
--- a/pypy/objspace/std/test/test_bytearrayobject.py
+++ b/pypy/objspace/std/test/test_bytearrayobject.py
@@ -1,5 +1,9 @@
+from pypy import conftest
 
 class AppTestBytesArray:
+    def setup_class(cls):
+        cls.w_runappdirect = cls.space.wrap(conftest.option.runappdirect)
+
     def test_basics(self):
         b = bytearray()
         assert type(b) is bytearray
@@ -439,3 +443,15 @@
     def test_reduce(self):
         assert bytearray('caf\xe9').__reduce__() == (
             bytearray, (u'caf\xe9', 'latin-1'), None)
+
+    def test_setitem_slice_performance(self):
+        # because of a complexity bug, this used to take forever on a
+        # translated pypy.  On CPython2.6 -A, it takes around 8 seconds.
+        if self.runappdirect:
+            count = 16*1024*1024
+        else:
+            count = 1024
+        b = bytearray(count)
+        for i in range(count):
+            b[i:i+1] = 'y'
+        assert str(b) == 'y' * count
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -397,6 +397,7 @@
         on_cpython = (option.runappdirect and
                             not hasattr(sys, 'pypy_translation_info'))
         cls.w_on_cpython = cls.space.wrap(on_cpython)
+        cls.w_runappdirect = cls.space.wrap(option.runappdirect)
 
     def test_getstrategyfromlist_w(self):
         l0 = ["a", "2", "a", True]
@@ -898,6 +899,18 @@
         l[::-1] = l
         assert l == [6,5,4,3,2,1]
 
+    def test_setitem_slice_performance(self):
+        # because of a complexity bug, this used to take forever on a
+        # translated pypy.  On CPython2.6 -A, it takes around 5 seconds.
+        if self.runappdirect:
+            count = 16*1024*1024
+        else:
+            count = 1024
+        b = [None] * count
+        for i in range(count):
+            b[i:i+1] = ['y']
+        assert b == ['y'] * count
+
     def test_recursive_repr(self):
         l = []
         assert repr(l) == '[]'
diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py
--- a/pypy/rpython/lltypesystem/module/ll_math.py
+++ b/pypy/rpython/lltypesystem/module/ll_math.py
@@ -292,6 +292,10 @@
     # deal directly with IEEE specials, to cope with problems on various
     # platforms whose semantics don't exactly match C99
 
+    if y == 2.0:
+        return x * x     # this is always a correct answer, and is relatively
+                         # common in user programs.
+
     if isnan(y):
         if x == 1.0:
             return 1.0   # 1**Nan = 1
diff --git a/pypy/tool/test/test_version.py b/pypy/tool/test/test_version.py
--- a/pypy/tool/test/test_version.py
+++ b/pypy/tool/test/test_version.py
@@ -1,6 +1,22 @@
 import os, sys
 import py
-from pypy.tool.version import get_repo_version_info
+from pypy.tool.version import get_repo_version_info, _get_hg_archive_version
+
+def test_hg_archival_version(tmpdir):
+    def version_for(name, **kw):
+        path = tmpdir.join(name)
+        path.write('\n'.join('%s: %s' % x for x in kw.items()))
+        return _get_hg_archive_version(str(path))
+
+    assert version_for('release',
+                       tag='release-123',
+                       node='000',
+                      ) == ('PyPy', 'release-123', '000')
+    assert version_for('somebranch',
+                       node='000',
+                       branch='something',
+                      ) == ('PyPy', 'something', '000')
+
 
 def test_get_repo_version_info():
     assert get_repo_version_info(None)
diff --git a/pypy/tool/version.py b/pypy/tool/version.py
--- a/pypy/tool/version.py
+++ b/pypy/tool/version.py
@@ -3,111 +3,139 @@
 from subprocess import Popen, PIPE
 import pypy
 pypydir = os.path.dirname(os.path.abspath(pypy.__file__))
+pypyroot = os.path.dirname(pypydir)
+default_retval = 'PyPy', '?', '?'
+
+def maywarn(err, repo_type='Mercurial'):
+    if not err:
+        return
+
+    from pypy.tool.ansi_print import ansi_log
+    log = py.log.Producer("version")
+    py.log.setconsumer("version", ansi_log)
+    log.WARNING('Errors getting %s information: %s' % (repo_type, err))
 
 def get_repo_version_info(hgexe=None):
     '''Obtain version information by invoking the 'hg' or 'git' commands.'''
-    # TODO: support extracting from .hg_archival.txt
-
-    default_retval = 'PyPy', '?', '?'
-    pypyroot = os.path.abspath(os.path.join(pypydir, '..'))
-
-    def maywarn(err, repo_type='Mercurial'):
-        if not err:
-            return
-
-        from pypy.tool.ansi_print import ansi_log
-        log = py.log.Producer("version")
-        py.log.setconsumer("version", ansi_log)
-        log.WARNING('Errors getting %s information: %s' % (repo_type, err))
 
     # Try to see if we can get info from Git if hgexe is not specified.
     if not hgexe:
         if os.path.isdir(os.path.join(pypyroot, '.git')):
-            gitexe = py.path.local.sysfind('git')
-            if gitexe:
-                try:
-                    p = Popen(
-                        [str(gitexe), 'rev-parse', 'HEAD'],
-                        stdout=PIPE, stderr=PIPE, cwd=pypyroot
-                        )
-                except OSError, e:
-                    maywarn(e, 'Git')
-                    return default_retval
-                if p.wait() != 0:
-                    maywarn(p.stderr.read(), 'Git')
-                    return default_retval
-                revision_id = p.stdout.read().strip()[:12]
-                p = Popen(
-                    [str(gitexe), 'describe', '--tags', '--exact-match'],
-                    stdout=PIPE, stderr=PIPE, cwd=pypyroot
-                    )
-                if p.wait() != 0:
-                    p = Popen(
-                        [str(gitexe), 'branch'], stdout=PIPE, stderr=PIPE,
-                        cwd=pypyroot
-                        )
-                    if p.wait() != 0:
-                        maywarn(p.stderr.read(), 'Git')
-                        return 'PyPy', '?', revision_id
-                    branch = '?'
-                    for line in p.stdout.read().strip().split('\n'):
-                        if line.startswith('* '):
-                            branch = line[1:].strip()
-                            if branch == '(no branch)':
-                                branch = '?'
-                            break
-                    return 'PyPy', branch, revision_id
-                return 'PyPy', p.stdout.read().strip(), revision_id
+            return _get_git_version()
 
     # Fallback to trying Mercurial.
     if hgexe is None:
         hgexe = py.path.local.sysfind('hg')
 
-    if not os.path.isdir(os.path.join(pypyroot, '.hg')):
+    if os.path.isfile(os.path.join(pypyroot, '.hg_archival.txt')):
+        return _get_hg_archive_version(os.path.join(pypyroot, '.hg_archival.txt'))
+    elif not os.path.isdir(os.path.join(pypyroot, '.hg')):
         maywarn('Not running from a Mercurial repository!')
         return default_retval
     elif not hgexe:
         maywarn('Cannot find Mercurial command!')
         return default_retval
     else:
-        env = dict(os.environ)
-        # get Mercurial into scripting mode
-        env['HGPLAIN'] = '1'
-        # disable user configuration, extensions, etc.
-        env['HGRCPATH'] = os.devnull
+        return _get_hg_version(hgexe)
 
-        try:
-            p = Popen([str(hgexe), 'version', '-q'],
-                      stdout=PIPE, stderr=PIPE, env=env)
-        except OSError, e:
-            maywarn(e)
-            return default_retval
 
-        if not p.stdout.read().startswith('Mercurial Distributed SCM'):
-            maywarn('command does not identify itself as Mercurial')
-            return default_retval
+def _get_hg_version(hgexe):
+    env = dict(os.environ)
+    # get Mercurial into scripting mode
+    env['HGPLAIN'] = '1'
+    # disable user configuration, extensions, etc.
+    env['HGRCPATH'] = os.devnull
 
-        p = Popen([str(hgexe), 'id', '-i', pypyroot],
+    try:
+        p = Popen([str(hgexe), 'version', '-q'],
                   stdout=PIPE, stderr=PIPE, env=env)
-        hgid = p.stdout.read().strip()
+    except OSError, e:
+        maywarn(e)
+        return default_retval
+
+    if not p.stdout.read().startswith('Mercurial Distributed SCM'):
+        maywarn('command does not identify itself as Mercurial')
+        return default_retval
+
+    p = Popen([str(hgexe), 'id', '-i', pypyroot],
+              stdout=PIPE, stderr=PIPE, env=env)
+    hgid = p.stdout.read().strip()
+    maywarn(p.stderr.read())
+    if p.wait() != 0:
+        hgid = '?'
+
+    p = Popen([str(hgexe), 'id', '-t', pypyroot],
+              stdout=PIPE, stderr=PIPE, env=env)
+    hgtags = [t for t in p.stdout.read().strip().split() if t != 'tip']
+    maywarn(p.stderr.read())
+    if p.wait() != 0:
+        hgtags = ['?']
+
+    if hgtags:
+        return 'PyPy', hgtags[0], hgid
+    else:
+        # use the branch instead
+        p = Popen([str(hgexe), 'id', '-b', pypyroot],
+                  stdout=PIPE, stderr=PIPE, env=env)
+        hgbranch = p.stdout.read().strip()
         maywarn(p.stderr.read())
+
+        return 'PyPy', hgbranch, hgid
+
+
+def _get_hg_archive_version(path):
+    fp = open(path)
+    try:
+        data = dict(x.split(': ', 1) for x in fp.read().splitlines())
+    finally:
+        fp.close()
+    if 'tag' in data:
+        return 'PyPy', data['tag'], data['node']
+    else:
+        return 'PyPy', data['branch'], data['node']
+
+
+def _get_git_version():
+    #XXX: this function is a untested hack,
+    #     so the git mirror tav made will work
+    gitexe = py.path.local.sysfind('git')
+    if not gitexe:
+        return default_retval
+
+    try:
+        p = Popen(
+            [str(gitexe), 'rev-parse', 'HEAD'],
+            stdout=PIPE, stderr=PIPE, cwd=pypyroot
+            )
+    except OSError, e:
+        maywarn(e, 'Git')
+        return default_retval
+    if p.wait() != 0:
+        maywarn(p.stderr.read(), 'Git')
+        return default_retval
+    revision_id = p.stdout.read().strip()[:12]
+    p = Popen(
+        [str(gitexe), 'describe', '--tags', '--exact-match'],
+        stdout=PIPE, stderr=PIPE, cwd=pypyroot
+        )
+    if p.wait() != 0:
+        p = Popen(
+            [str(gitexe), 'branch'], stdout=PIPE, stderr=PIPE,
+            cwd=pypyroot
+            )
         if p.wait() != 0:
-            hgid = '?'
+            maywarn(p.stderr.read(), 'Git')
+            return 'PyPy', '?', revision_id
+        branch = '?'
+        for line in p.stdout.read().strip().split('\n'):
+            if line.startswith('* '):
+                branch = line[1:].strip()
+                if branch == '(no branch)':
+                    branch = '?'
+                break
+        return 'PyPy', branch, revision_id
+    return 'PyPy', p.stdout.read().strip(), revision_id
 
-        p = Popen([str(hgexe), 'id', '-t', pypyroot],
-                  stdout=PIPE, stderr=PIPE, env=env)
-        hgtags = [t for t in p.stdout.read().strip().split() if t != 'tip']
-        maywarn(p.stderr.read())
-        if p.wait() != 0:
-            hgtags = ['?']
 
-        if hgtags:
-            return 'PyPy', hgtags[0], hgid
-        else:
-            # use the branch instead
-            p = Popen([str(hgexe), 'id', '-b', pypyroot],
-                      stdout=PIPE, stderr=PIPE, env=env)
-            hgbranch = p.stdout.read().strip()
-            maywarn(p.stderr.read())
-
-            return 'PyPy', hgbranch, hgid
+if __name__ == '__main__':
+    print get_repo_version_info()


More information about the pypy-commit mailing list