Commits

Philip Jenvey committed 98718a0 Merge

merge default

Comments (0)

Files changed (21)

lib_pypy/greenlet.py

     _tls.main = gmain
     _tls.current = gmain
 
-def _greenlet_start(greenlet, (args, kwds)):
+def _greenlet_start(greenlet, args):
+    args, kwds = args
     _tls.current = greenlet
     try:
         res = greenlet.run(*args, **kwds)

pypy/doc/how-to-contribute.rst

 entry point.
 
 .. _`introduction to RPython`: getting-started-dev.html
+.. _`pytest`: http://pytest.org/

pypy/doc/whatsnew-head.rst

 .. branch: ndarray-view
 Add view to ndarray and zeroD arrays, not on dtype scalars yet
 
+.. branch: identity-set
+Faster sets for objects
+
+.. branch: inline-identityhash
+Inline the fast path of id() and hash()

pypy/module/micronumpy/__init__.py

     appleveldefs = {}
     interpleveldefs = {
         'choose': 'interp_arrayops.choose',
+        'put': 'interp_arrayops.put',
         'repeat': 'interp_arrayops.repeat',
     }
     submodules = {

pypy/module/micronumpy/arrayimpl/scalar.py

     def next(self):
         self.called_once = True
 
+    def next_skip_x(self, n):
+        self.called_once = True
+
     def getitem(self):
         return self.v.get_scalar_value()
 

pypy/module/micronumpy/interp_arrayops.py

     loop.choose(space, arr, choices, shape, dtype, out, MODES[mode])
     return out
 
+
+@unwrap_spec(mode=str)
+def put(space, w_arr, w_indices, w_values, mode='raise'):
+    from pypy.module.micronumpy import constants
+    from pypy.module.micronumpy.support import int_w
+
+    arr = convert_to_array(space, w_arr)
+
+    if mode not in constants.MODES:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("mode %s not known" % (mode,)))
+    if not w_indices:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("indice list cannot be empty"))
+    if not w_values:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("value list cannot be empty"))
+
+    dtype = arr.get_dtype()
+
+    if space.isinstance_w(w_indices, space.w_list):
+        indices = space.listview(w_indices)
+    else:
+        indices = [w_indices]
+
+    if space.isinstance_w(w_values, space.w_list):
+        values = space.listview(w_values)
+    else:
+        values = [w_values]
+
+    v_idx = 0
+    for idx in indices:
+        index = int_w(space, idx)
+
+        if index < 0 or index >= arr.get_size():
+            if constants.MODES[mode] == constants.MODE_RAISE:
+                raise OperationError(space.w_ValueError, space.wrap(
+                    "invalid entry in choice array"))
+            elif constants.MODES[mode] == constants.MODE_WRAP:
+                index = index % arr.get_size()
+            else:
+                assert constants.MODES[mode] == constants.MODE_CLIP
+                if index < 0:
+                    index = 0
+                else:
+                    index = arr.get_size() - 1
+
+        value = values[v_idx]
+
+        if v_idx + 1 < len(values):
+            v_idx += 1
+
+        arr.setitem(space, [index], dtype.coerce(space, value))
+
+
 def diagonal(space, arr, offset, axis1, axis2):
     shape = arr.get_shape()
     shapelen = len(shape)

pypy/module/micronumpy/interp_numarray.py

         raise OperationError(space.w_NotImplementedError, space.wrap(
             "ptp (peak to peak) not implemented yet"))
 
-    def descr_put(self, space, w_indices, w_values, w_mode='raise'):
-        raise OperationError(space.w_NotImplementedError, space.wrap(
-            "put not implemented yet"))
+    @unwrap_spec(mode=str)
+    def descr_put(self, space, w_indices, w_values, mode='raise'):
+        from pypy.module.micronumpy.interp_arrayops import put
+        put(space, self, w_indices, w_values, mode)
 
     def descr_resize(self, space, w_new_shape, w_refcheck=True):
         raise OperationError(space.w_NotImplementedError, space.wrap(
         old_itemsize = self.get_dtype().get_size()
         new_itemsize = dtype.get_size()
         impl = self.implementation
-        new_shape = self.get_shape()
+        new_shape = self.get_shape()[:]
         dims = len(new_shape)
         if dims == 0:
             # Cannot resize scalars
     prod = interp2app(W_NDimArray.descr_prod),
     max = interp2app(W_NDimArray.descr_max),
     min = interp2app(W_NDimArray.descr_min),
+    put = interp2app(W_NDimArray.descr_put),
     argmax = interp2app(W_NDimArray.descr_argmax),
     argmin = interp2app(W_NDimArray.descr_argmin),
     all = interp2app(W_NDimArray.descr_all),

pypy/module/micronumpy/iter.py

 we can go faster.
 All the calculations happen in next()
 
-next_skip_x() tries to do the iteration for a number of steps at once,
+next_skip_x(steps) tries to do the iteration for a number of steps at once,
 but then we cannot gaurentee that we only overflow one single shape
 dimension, perhaps we could overflow times in one big step.
 """

pypy/module/micronumpy/test/test_arrayops.py

         x = array([0, 0, 0], dtype='i2')
         r = array([2, 1, 0]).choose([a, b, c], out=x)
         assert r.dtype == 'i2'
+
+    def test_put_basic(self):
+        from numpypy import arange, array
+        a = arange(5)
+        a.put([0, 2], [-44, -55])
+        assert (a == array([-44, 1, -55, 3, 4])).all()
+        a = arange(5)
+        a.put([3, 4], 9)
+        assert (a == array([0, 1, 2, 9, 9])).all()
+        a = arange(5)
+        a.put(1, [7, 8])
+        assert (a == array([0, 7, 2, 3, 4])).all()
+
+    def test_put_modes(self):
+        from numpypy import array, arange
+        a = arange(5)
+        a.put(22, -5, mode='clip')
+        assert (a == array([0, 1, 2, 3, -5])).all()
+        a = arange(5)
+        a.put(22, -5, mode='wrap')
+        assert (a == array([0, 1, -5, 3, 4])).all()
+        raises(ValueError, "arange(5).put(22, -5, mode='raise')")
+        raises(ValueError, "arange(5).put(22, -5, mode='wrongmode')")

pypy/module/micronumpy/test/test_iter.py

 from pypy.module.micronumpy.iter import MultiDimViewIterator
+from pypy.module.micronumpy.arrayimpl.scalar import ScalarIterator
 
 class MockArray(object):
     size = 1
         #Let's get started, simple iteration in C order with
         #contiguous layout => strides[-1] is 1
         start = 0
-        shape = [3, 5] 
+        shape = [3, 5]
         strides = [5, 1]
         backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
         assert backstrides == [10, 4]
         #iteration in C order with #contiguous layout => strides[-1] is 1
         #skip less than the shape
         start = 0
-        shape = [3, 5] 
+        shape = [3, 5]
         strides = [5, 1]
         backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
         assert backstrides == [10, 4]
         assert i.indexes == [0,1]
         assert i.offset == 3
         assert i.done()
+
+    def test_scalar_iter(self):
+        i = ScalarIterator(MockArray)
+        i.next()
+        i.next_skip_x(3)
+        assert i.done()

pypy/module/micronumpy/test/test_numarray.py

         assert a[3].imag == -10
         assert a[2].imag == -5
 
-    def test_ndarray_view(self):
+    def test_view(self):
         from numpypy import array, int8, int16, dtype
-        x = array([(1, 2)], dtype=[('a', int8), ('b', int8)])
+        x = array((1, 2), dtype=int8)
+        assert x.shape == (2,)
         y = x.view(dtype=int16)
-        print y,y.shape
+        assert x.shape == (2,)
         assert y[0] == 513
         assert y.dtype == dtype('int16')
         y[0] = 670
-        assert x['a'] == -98
-        assert x['b'] == 2
+        assert x[0] == -98
+        assert x[1] == 2
         f = array([1000, -1234], dtype='i4')
         nnp = self.non_native_prefix
         d = f.view(dtype=nnp + 'i4')

pypy/module/pypyjit/test_pypy_c/test_containers.py

         def main(n):
             i = 0
             while i < n:
-                s = set([1,2,3])
+                s = set([1, 2, 3])
                 i += 1
         log = self.run(main, [1000])
         assert log.result == main(1000)
         loop, = log.loops_by_filename(self.filepath)
         opnames = log.opnames(loop.allops())
         assert opnames.count('new_with_vtable') == 0
+
+    def test_specialised_tuple(self):
+        def main(n):
+            import pypyjit
+
+            f = lambda: None
+            tup = (n, n)
+            while n > 0:
+                tup[0]  # ID: getitem
+                pypyjit.residual_call(f)
+                n -= 1
+
+        log = self.run(main, [1000])
+        assert log.result == main(1000)
+        loop, = log.loops_by_filename(self.filepath)
+        ops = loop.ops_by_id('getitem')
+        assert log.opnames(ops) == []

pypy/module/test_lib_pypy/test_ctypes_config_cache.py

     return d
 
 
-def test_syslog():
-    try:
-        import lib_pypy.syslog
-    except ImportError:
-        py.test.skip('no syslog on this platform')
-    d = run('syslog.ctc.py', '_syslog_cache.py')
-    assert 'LOG_NOTICE' in d
-
 def test_resource():
     try:
         import lib_pypy.resource

pypy/module/test_lib_pypy/test_grp_extra.py

 def test_basic():
     g = grp.getgrnam("root")
     assert g.gr_gid == 0
-    assert g.gr_mem == ['root']
+    assert g.gr_mem == ['root'] or g.gr_mem == []
     assert g.gr_name == 'root'
     assert isinstance(g.gr_passwd, str)    # usually just 'x', don't hope :-)
 

pypy/module/test_lib_pypy/test_syslog.py

-import py
+import sys, py
 try:
     from lib_pypy import syslog
 except ImportError:
     py.test.skip('no syslog on this platform')
+except AssertionError:
+    if '__pypy__' in sys.builtin_module_names:
+        raise
+    py.test.skip('AssertionError during import (wrong cffi version?)')
 
 # XXX very minimal test
 

pypy/objspace/std/setobject.py

     def __repr__(self):
         """representation for debugging purposes"""
         reprlist = [repr(w_item) for w_item in self.getkeys()]
-        return "<%s(%s)>" % (self.__class__.__name__, ', '.join(reprlist))
+        return "<%s(%s)(%s)>" % (self.__class__.__name__, self.strategy, ', '.join(reprlist))
 
     def from_storage_and_strategy(self, storage, strategy):
         obj = self._newobj(self.space, None)
             strategy = self.space.fromcache(StringSetStrategy)
         elif type(w_key) is W_UnicodeObject:
             strategy = self.space.fromcache(UnicodeSetStrategy)
+        elif self.space.type(w_key).compares_by_identity():
+            strategy = self.space.fromcache(IdentitySetStrategy)
         else:
             strategy = self.space.fromcache(ObjectSetStrategy)
         w_set.strategy = strategy
     def equals(self, w_set, w_other):
         if w_set.length() != w_other.length():
             return False
+        if w_set.length() == 0:
+            return True
+        # it's possible to have 0-lenght strategy that's not empty
+        if w_set.strategy is w_other.strategy:
+            return self._issubset_unwrapped(w_set, w_other)
+        if not self.may_contain_equal_elements(w_other.strategy):
+            return False
         items = self.unerase(w_set.sstorage).keys()
         for key in items:
             if not w_other.has_key(self.wrap(key)):
     def may_contain_equal_elements(self, strategy):
         if strategy is self.space.fromcache(IntegerSetStrategy):
             return False
-        if strategy is self.space.fromcache(EmptySetStrategy):
+        elif strategy is self.space.fromcache(EmptySetStrategy):
+            return False
+        elif strategy is self.space.fromcache(IdentitySetStrategy):
             return False
         return True
 
     def may_contain_equal_elements(self, strategy):
         if strategy is self.space.fromcache(IntegerSetStrategy):
             return False
-        if strategy is self.space.fromcache(EmptySetStrategy):
+        elif strategy is self.space.fromcache(EmptySetStrategy):
+            return False
+        elif strategy is self.space.fromcache(IdentitySetStrategy):
             return False
         return True
 
     def may_contain_equal_elements(self, strategy):
         if strategy is self.space.fromcache(UnicodeSetStrategy):
             return False
-        if strategy is self.space.fromcache(UnicodeSetStrategy):
+        elif strategy is self.space.fromcache(UnicodeSetStrategy):
             return False
-        if strategy is self.space.fromcache(EmptySetStrategy):
+        elif strategy is self.space.fromcache(EmptySetStrategy):
+            return False
+        elif strategy is self.space.fromcache(IdentitySetStrategy):
             return False
         return True
 
                 break
             d_obj[w_item] = None
 
+class IdentitySetStrategy(AbstractUnwrappedSetStrategy, SetStrategy):
+    erase, unerase = rerased.new_erasing_pair("identityset")
+    erase = staticmethod(erase)
+    unerase = staticmethod(unerase)
+
+    def get_empty_storage(self):
+        return self.erase({})
+
+    def get_empty_dict(self):
+        return {}
+
+    def is_correct_type(self, w_key):
+        w_type = self.space.type(w_key)
+        return w_type.compares_by_identity()
+
+    def may_contain_equal_elements(self, strategy):
+        #empty first, probably more likely
+        if strategy is self.space.fromcache(EmptySetStrategy):
+            return False
+        if strategy is self.space.fromcache(IntegerSetStrategy):
+            return False
+        if strategy is self.space.fromcache(StringSetStrategy):
+            return False
+        if strategy is self.space.fromcache(UnicodeSetStrategy):
+            return False
+        return True
+
+    def unwrap(self, w_item):
+        return w_item
+
+    def wrap(self, item):
+        return item
+
+    def iter(self, w_set):
+        return IdentityIteratorImplementation(self.space, self, w_set)
 
 class IteratorImplementation(object):
     def __init__(self, space, strategy, implementation):
         else:
             return None
 
+class IdentityIteratorImplementation(IteratorImplementation):
+    def __init__(self, space, strategy, w_set):
+        IteratorImplementation.__init__(self, space, strategy, w_set)
+        d = strategy.unerase(w_set.sstorage)
+        self.iterator = d.iterkeys()
+
+    def next_entry(self):
+        for key in self.iterator:
+            return self.space.wrap(key)
+        else:
+            return None
 
 class RDictIteratorImplementation(IteratorImplementation):
     def __init__(self, space, strategy, w_set):
         w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
         return
 
+    # check for compares by identity
+    for w_item in iterable_w:
+        if not space.type(w_item).compares_by_identity():
+            break
+    else:
+        w_set.strategy = space.fromcache(IdentitySetStrategy)
+        w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
+        return
+
     w_set.strategy = space.fromcache(ObjectSetStrategy)
     w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
 

pypy/objspace/std/specialisedtupleobject.py

     iter_n = unrolling_iterable(range(typelen))
 
     class cls(W_AbstractTupleObject):
+        _immutable_fields_ = ['value%s' % i for i in iter_n]
+
         def __init__(self, space, *values_w):
             self.space = space
             assert len(values_w) == typelen

pypy/objspace/std/test/test_identityset.py

+import py
+
+
+class AppTestIdentitySet(object):
+
+    # needed for compares_by_identity
+    spaceconfig = {"objspace.std.withidentitydict": True}
+
+    def setup_class(cls):
+        from pypy.objspace.std import identitydict
+        if cls.runappdirect:
+            py.test.skip("interp2app doesn't work on appdirect")
+
+    def w_uses_strategy(self, s , obj):
+        import __pypy__
+        return s in __pypy__.internal_repr(obj)
+
+    def test_use_identity_strategy(self):
+
+        class Plain(object):
+            pass
+
+        class CustomEq(object):
+            def __eq__(self, other):
+                return True
+
+        class CustomCmp (object):
+            def __cmp__(self, other):
+                return 0
+
+        class CustomHash(object):
+            def __hash__(self):
+                return 0
+
+        s = set()
+
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+
+        s.add(Plain())
+
+        assert self.uses_strategy('IdentitySetStrategy',s)
+
+        for cls in [CustomEq,CustomCmp,CustomHash]:
+            s = set()
+            s.add(cls())
+            assert not self.uses_strategy('IdentitySetStrategy',s)
+
+
+    def test_use_identity_strategy_list(self):
+
+        class X(object):
+            pass
+
+        assert self.uses_strategy('IdentitySetStrategy',set([X(),X()]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),""]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),u""]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),1]))
+
+    def test_identity_strategy_add(self):
+
+        class X(object):
+            pass
+
+        class NotIdent(object):
+            def __eq__(self,other):
+                pass
+
+        s = set([X(),X()])
+        s.add('foo')
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+        s = set([X(),X()])
+        s.add(NotIdent())
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+
+    def test_identity_strategy_sanity(self):
+
+        class X(object):
+            pass
+
+        class Y(object):
+            pass
+
+        a,b,c,d,e,f = X(),Y(),X(),Y(),X(),Y()
+
+        s = set([a,b]).union(set([c]))
+        assert self.uses_strategy('IdentitySetStrategy',s)
+        assert set([a,b,c]) == s
+        s = set([a,b,c,d,e,f]) - set([d,e,f])
+        assert self.uses_strategy('IdentitySetStrategy',s)
+        assert set([a,b,c]) == s
+
+
+        s = set([a])
+        s.update([b,c])
+
+        assert s == set([a,b,c])
+
+
+    def test_identity_strategy_iterators(self):
+
+        class X(object):
+            pass
+
+        s = set([X() for i in range(10)])
+        counter = 0
+        for item in s:
+            counter += 1
+            assert item in s
+
+        assert counter == 10
+
+
+    def test_identity_strategy_other_cmp(self):
+
+        # test tries to hit positive and negative in
+        # may_contain_equal_elements
+
+        class X(object):
+            pass
+
+        s = set([X() for i in range(10)])
+
+        assert s.intersection(set([1,2,3])) == set()
+        assert s.intersection(set(['a','b','c'])) == set()
+        assert s.intersection(set(['a','b','c'])) == set()
+        assert s.intersection(set([X(),X()])) == set()
+
+        other = set(['a','b','c',s.__iter__().next()])
+        intersect = s.intersection(other)
+        assert len(intersect) == 1
+        assert intersect.__iter__().next() in s
+        assert intersect.__iter__().next() in other
+
+    def test_class_monkey_patch(self):
+
+        class X(object):
+            pass
+
+        s = set()
+
+        s.add(X())
+        assert self.uses_strategy('IdentitySetStrategy',s)
+        X.__eq__ = lambda self,other : None
+        s.add(X())
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),X()]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),""]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),u""]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),1]))
+
+        # An interesting case, add an instance, mutate the class,
+        # then add the same instance.
+
+        class X(object):
+            pass
+
+        s = set()
+        inst = X()
+        s.add(inst)
+        X.__eq__ = lambda x,y : x is y
+        s.add(inst)
+
+        assert len(s) == 1
+        assert s.__iter__().next() is inst
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+
+
+        # Add instance, mutate class, check membership of that instance.
+
+        class X(object):
+            pass
+
+
+        inst = X()
+        s = set()
+        s.add(inst)
+        X.__eq__ = lambda x,y : x is y
+        assert inst in s
+
+        # Test Wrong strategy
+        # If the strategy is changed by mutation, but the instance
+        # does not change, then this tests the methods that call
+        # may_contain_equal_elements still function.
+        # i.e. same instance in two sets, one with object strategy, one with
+        # identity strategy.
+
+        class X(object):
+            pass
+
+
+        inst = X()
+        s1 = set()
+        s1.add(inst)
+        assert self.uses_strategy('IdentitySetStrategy',s1)
+        X.__eq__ = lambda x,y : x is y
+        s2 = set()
+        s2.add(inst)
+        assert not self.uses_strategy('IdentitySetStrategy',s2)
+
+        assert s1.intersection(s2) == set([inst])
+        assert (s1 - s2) == set()
+        assert (s2 - s1) == set()
+
+        s1.difference_update(s2)
+        assert s1 == set()

rpython/memory/gc/minimark.py

 from rpython.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint
 from rpython.rlib.rarithmetic import LONG_BIT_SHIFT
 from rpython.rlib.debug import ll_assert, debug_print, debug_start, debug_stop
-from rpython.rlib.objectmodel import we_are_translated
-from rpython.tool.sourcetools import func_with_new_name
+from rpython.rlib.objectmodel import specialize
+
 
 #
 # Handles the objects in 2 generations:
     # ----------
     # id() and identityhash() support
 
+    def _allocate_shadow(self, obj):
+        size_gc_header = self.gcheaderbuilder.size_gc_header
+        size = self.get_size(obj)
+        shadowhdr = self._malloc_out_of_nursery(size_gc_header +
+                                                size)
+        # Initialize the shadow enough to be considered a
+        # valid gc object.  If the original object stays
+        # alive at the next minor collection, it will anyway
+        # be copied over the shadow and overwrite the
+        # following fields.  But if the object dies, then
+        # the shadow will stay around and only be freed at
+        # the next major collection, at which point we want
+        # it to look valid (but ready to be freed).
+        shadow = shadowhdr + size_gc_header
+        self.header(shadow).tid = self.header(obj).tid
+        typeid = self.get_type_id(obj)
+        if self.is_varsize(typeid):
+            lenofs = self.varsize_offset_to_length(typeid)
+            (shadow + lenofs).signed[0] = (obj + lenofs).signed[0]
+        #
+        self.header(obj).tid |= GCFLAG_HAS_SHADOW
+        self.nursery_objects_shadows.setitem(obj, shadow)
+        return shadow
+
+    def _find_shadow(self, obj):
+        #
+        # The object is not a tagged pointer, and it is still in the
+        # nursery.  Find or allocate a "shadow" object, which is
+        # where the object will be moved by the next minor
+        # collection
+        if self.header(obj).tid & GCFLAG_HAS_SHADOW:
+            shadow = self.nursery_objects_shadows.get(obj)
+            ll_assert(shadow != NULL,
+                      "GCFLAG_HAS_SHADOW but no shadow found")
+        else:
+            shadow = self._allocate_shadow(obj)
+        #
+        # The answer is the address of the shadow.
+        return shadow
+    _find_shadow._dont_inline_ = True
+
+    @specialize.arg(2)
     def id_or_identityhash(self, gcobj, is_hash):
         """Implement the common logic of id() and identityhash()
         of an object, given as a GCREF.
         #
         if self.is_valid_gc_object(obj):
             if self.is_in_nursery(obj):
-                #
-                # The object is not a tagged pointer, and it is still in the
-                # nursery.  Find or allocate a "shadow" object, which is
-                # where the object will be moved by the next minor
-                # collection
-                if self.header(obj).tid & GCFLAG_HAS_SHADOW:
-                    shadow = self.nursery_objects_shadows.get(obj)
-                    ll_assert(shadow != NULL,
-                              "GCFLAG_HAS_SHADOW but no shadow found")
-                else:
-                    size_gc_header = self.gcheaderbuilder.size_gc_header
-                    size = self.get_size(obj)
-                    shadowhdr = self._malloc_out_of_nursery(size_gc_header +
-                                                            size)
-                    # Initialize the shadow enough to be considered a
-                    # valid gc object.  If the original object stays
-                    # alive at the next minor collection, it will anyway
-                    # be copied over the shadow and overwrite the
-                    # following fields.  But if the object dies, then
-                    # the shadow will stay around and only be freed at
-                    # the next major collection, at which point we want
-                    # it to look valid (but ready to be freed).
-                    shadow = shadowhdr + size_gc_header
-                    self.header(shadow).tid = self.header(obj).tid
-                    typeid = self.get_type_id(obj)
-                    if self.is_varsize(typeid):
-                        lenofs = self.varsize_offset_to_length(typeid)
-                        (shadow + lenofs).signed[0] = (obj + lenofs).signed[0]
-                    #
-                    self.header(obj).tid |= GCFLAG_HAS_SHADOW
-                    self.nursery_objects_shadows.setitem(obj, shadow)
-                #
-                # The answer is the address of the shadow.
-                obj = shadow
-                #
+                obj = self._find_shadow(obj)
             elif is_hash:
                 if self.header(obj).tid & GCFLAG_HAS_SHADOW:
                     #
         if is_hash:
             i = mangle_hash(i)
         return i
+    id_or_identityhash._always_inline_ = True
 
     def id(self, gcobj):
         return self.id_or_identityhash(gcobj, False)

rpython/memory/gctransform/framework.py

         self.identityhash_ptr = getfn(GCClass.identityhash.im_func,
                                       [s_gc, s_gcref],
                                       annmodel.SomeInteger(),
-                                      minimal_transform=False)
+                                      minimal_transform=False, inline=True)
         if getattr(GCClass, 'obtain_free_space', False):
             self.obtainfreespace_ptr = getfn(GCClass.obtain_free_space.im_func,
                                              [s_gc, annmodel.SomeInteger()],
         if GCClass.moving_gc:
             self.id_ptr = getfn(GCClass.id.im_func,
                                 [s_gc, s_gcref], annmodel.SomeInteger(),
-                                inline = False,
+                                inline = True,
                                 minimal_transform = False)
         else:
             self.id_ptr = None

rpython/translator/platform/arm.py

 
 class ARM(Linux):
     name = "arm"
+    shared_only = ('-fPIC',)
 
     available_librarydirs = [SB2 + '/lib/arm-linux-gnueabi/',
                              SB2 + '/lib/arm-linux-gnueabihf/',