[pypy-svn] r68694 - in pypy/trunk/pypy: rpython/lltypesystem rpython/lltypesystem/test rpython/memory rpython/memory/test translator/backendopt translator/backendopt/test

arigo at codespeak.net arigo at codespeak.net
Wed Oct 21 18:34:54 CEST 2009


Author: arigo
Date: Wed Oct 21 18:34:53 2009
New Revision: 68694

Modified:
   pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
   pypy/trunk/pypy/rpython/lltypesystem/opimpl.py
   pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py
   pypy/trunk/pypy/rpython/memory/gctypelayout.py
   pypy/trunk/pypy/rpython/memory/test/test_gctypelayout.py
   pypy/trunk/pypy/translator/backendopt/mallocv.py
   pypy/trunk/pypy/translator/backendopt/test/test_constfold.py
Log:
Improve support of 'immutable_fields' wherever 'immutable'
is supported, notably in optimizations.  Add tests.
(merge r68679 to r68681)


Modified: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/lloperation.py	Wed Oct 21 18:34:53 2009
@@ -84,12 +84,17 @@
         return op_impl
     fold = roproperty(get_fold_impl)
 
-    def is_pure(self, *ARGTYPES):
+    def is_pure(self, args_v):
         return (self.canfold or                # canfold => pure operation
                 self is llop.debug_assert or   # debug_assert is pure enough
                                                # reading from immutable
                 (self in (llop.getfield, llop.getarrayitem) and
-                 ARGTYPES[0].TO._hints.get('immutable'))) # XXX: what about ootype immutable arrays?
+                 args_v[0].concretetype.TO._hints.get('immutable')) or
+                (self is llop.getfield and     # reading from immutable_field
+                 'immutable_fields' in args_v[0].concretetype.TO._hints and
+                 args_v[1].value in args_v[0].concretetype.TO
+                                           ._hints['immutable_fields'].fields))
+        # XXX: what about ootype immutable arrays?
 
     def __repr__(self):
         return '<LLOp %s>' % (getattr(self, 'opname', '?'),)

Modified: pypy/trunk/pypy/rpython/lltypesystem/opimpl.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/opimpl.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/opimpl.py	Wed Oct 21 18:34:53 2009
@@ -142,7 +142,12 @@
     # we can constant-fold this if the innermost structure from which we
     # read the final field is immutable.
     T = lltype.typeOf(innermostcontainer).TO
-    if not T._hints.get('immutable'):
+    if T._hints.get('immutable'):
+        pass
+    elif ('immutable_fields' in T._hints and
+          offsets[-1] in T._hints['immutable_fields'].fields):
+        pass
+    else:
         raise TypeError("cannot fold getinteriorfield on mutable struct")
     assert not isinstance(ob, lltype._interior_ptr)
     return ob
@@ -390,7 +395,13 @@
 
 def op_getfield(p, name):
     checkptr(p)
-    if not lltype.typeOf(p).TO._hints.get('immutable'):
+    TYPE = lltype.typeOf(p).TO
+    if TYPE._hints.get('immutable'):
+        pass
+    elif ('immutable_fields' in TYPE._hints and
+          name in TYPE._hints['immutable_fields'].fields):
+        pass
+    else:
         raise TypeError("cannot fold getfield on mutable struct")
     return getattr(p, name)
 

Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py	Wed Oct 21 18:34:53 2009
@@ -4,6 +4,7 @@
 from pypy.rpython.ootypesystem import ootype, ooopimpl
 from pypy.rpython.llinterp import LLFrame
 from pypy.rpython.test.test_llinterp import interpret
+from pypy.rpython import rclass
 
 LL_INTERP_OPERATIONS = [name[3:] for name in LLFrame.__dict__.keys()
                                  if name.startswith('op_')]
@@ -50,7 +51,72 @@
         return s.x + s.y
     res = interpret(llf, [], policy=LowLevelAnnotatorPolicy())
     assert res == 5
-    
+
+def test_is_pure():
+    from pypy.objspace.flow.model import Variable, Constant
+    assert llop.bool_not.is_pure([Variable()])
+    assert llop.debug_assert.is_pure([Variable()])
+    assert not llop.int_add_ovf.is_pure([Variable(), Variable()])
+    #
+    S1 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed))
+    v_s1 = Variable()
+    v_s1.concretetype = lltype.Ptr(S1)
+    assert not llop.setfield.is_pure([v_s1, Constant('x'), Variable()])
+    assert not llop.getfield.is_pure([v_s1, Constant('y')])
+    #
+    A1 = lltype.GcArray(lltype.Signed)
+    v_a1 = Variable()
+    v_a1.concretetype = lltype.Ptr(A1)
+    assert not llop.setarrayitem.is_pure([v_a1, Variable(), Variable()])
+    assert not llop.getarrayitem.is_pure([v_a1, Variable()])
+    assert llop.getarraysize.is_pure([v_a1])
+    #
+    S2 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed),
+                         hints={'immutable': True})
+    v_s2 = Variable()
+    v_s2.concretetype = lltype.Ptr(S2)
+    assert not llop.setfield.is_pure([v_s2, Constant('x'), Variable()])
+    assert llop.getfield.is_pure([v_s2, Constant('y')])
+    #
+    A2 = lltype.GcArray(lltype.Signed, hints={'immutable': True})
+    v_a2 = Variable()
+    v_a2.concretetype = lltype.Ptr(A2)
+    assert not llop.setarrayitem.is_pure([v_a2, Variable(), Variable()])
+    assert llop.getarrayitem.is_pure([v_a2, Variable()])
+    assert llop.getarraysize.is_pure([v_a2])
+    #
+    accessor = rclass.FieldListAccessor()
+    S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed),
+                         hints={'immutable_fields': accessor})
+    accessor.initialize(S3, ['x'])
+    v_s3 = Variable()
+    v_s3.concretetype = lltype.Ptr(S3)
+    assert not llop.setfield.is_pure([v_s3, Constant('x'), Variable()])
+    assert not llop.setfield.is_pure([v_s3, Constant('y'), Variable()])
+    assert llop.getfield.is_pure([v_s3, Constant('x')])
+    assert not llop.getfield.is_pure([v_s3, Constant('y')])
+
+def test_getfield_pure():
+    S1 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed))
+    S2 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed),
+                         hints={'immutable': True})
+    accessor = rclass.FieldListAccessor()
+    S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed),
+                         hints={'immutable_fields': accessor})
+    accessor.initialize(S3, ['x'])
+    #
+    s1 = lltype.malloc(S1); s1.x = 45
+    py.test.raises(TypeError, llop.getfield, lltype.Signed, s1, 'x')
+    s2 = lltype.malloc(S2); s2.x = 45
+    assert llop.getfield(lltype.Signed, s2, 'x') == 45
+    s3 = lltype.malloc(S3); s3.x = 46; s3.y = 47
+    assert llop.getfield(lltype.Signed, s3, 'x') == 46
+    py.test.raises(TypeError, llop.getfield, lltype.Signed, s3, 'y')
+    #
+    py.test.raises(TypeError, llop.getinteriorfield, lltype.Signed, s1, 'x')
+    assert llop.getinteriorfield(lltype.Signed, s2, 'x') == 45
+    assert llop.getinteriorfield(lltype.Signed, s3, 'x') == 46
+    py.test.raises(TypeError, llop.getinteriorfield, lltype.Signed, s3, 'y')
 
 # ___________________________________________________________________________
 # This tests that the LLInterpreter and the LL_OPERATIONS tables are in sync.

Modified: pypy/trunk/pypy/rpython/memory/gctypelayout.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctypelayout.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gctypelayout.py	Wed Oct 21 18:34:53 2009
@@ -350,11 +350,16 @@
 def gc_pointers_inside(v, adr, mutable_only=False):
     t = lltype.typeOf(v)
     if isinstance(t, lltype.Struct):
-        if mutable_only and t._hints.get('immutable'):
-            return
+        skip = ()
+        if mutable_only:
+            if t._hints.get('immutable'):
+                return
+            if 'immutable_fields' in t._hints:
+                skip = t._hints['immutable_fields'].fields
         for n, t2 in t._flds.iteritems():
             if isinstance(t2, lltype.Ptr) and t2.TO._gckind == 'gc':
-                yield adr + llmemory.offsetof(t, n)
+                if n not in skip:
+                    yield adr + llmemory.offsetof(t, n)
             elif isinstance(t2, (lltype.Array, lltype.Struct)):
                 for a in gc_pointers_inside(getattr(v, n),
                                             adr + llmemory.offsetof(t, n),

Modified: pypy/trunk/pypy/rpython/memory/test/test_gctypelayout.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/test/test_gctypelayout.py	(original)
+++ pypy/trunk/pypy/rpython/memory/test/test_gctypelayout.py	Wed Oct 21 18:34:53 2009
@@ -1,7 +1,8 @@
 import py
 from pypy.rpython.memory.gctypelayout import TypeLayoutBuilder, GCData
 from pypy.rpython.memory.gctypelayout import offsets_to_gc_pointers
-from pypy.rpython.lltypesystem import lltype, rclass
+from pypy.rpython.memory.gctypelayout import gc_pointers_inside
+from pypy.rpython.lltypesystem import lltype, llmemory, rclass
 from pypy.rpython.test.test_llinterp import get_interpreter
 from pypy.objspace.flow.model import Constant
 
@@ -90,3 +91,31 @@
     interp, graph = get_interpreter(f, [], backendopt=True)
     assert interp.eval_graph(graph, []) == 11001
     assert graph.startblock.exits[0].args == [Constant(11001, lltype.Signed)]
+
+def test_gc_pointers_inside():
+    from pypy.rpython import rclass
+    PT = lltype.Ptr(lltype.GcStruct('T'))
+    S1 = lltype.GcStruct('S', ('x', PT), ('y', PT))
+    S2 = lltype.GcStruct('S', ('x', PT), ('y', PT),
+                         hints={'immutable': True})
+    accessor = rclass.FieldListAccessor()
+    S3 = lltype.GcStruct('S', ('x', PT), ('y', PT),
+                         hints={'immutable_fields': accessor})
+    accessor.initialize(S3, ['x'])
+    #
+    s1 = lltype.malloc(S1)
+    adr = llmemory.cast_ptr_to_adr(s1)
+    lst = list(gc_pointers_inside(s1._obj, adr, mutable_only=True))
+    expected = [adr + llmemory.offsetof(S1, 'x'),
+                adr + llmemory.offsetof(S1, 'y')]
+    assert lst == expected or lst == expected[::-1]
+    #
+    s2 = lltype.malloc(S2)
+    adr = llmemory.cast_ptr_to_adr(s2)
+    lst = list(gc_pointers_inside(s2._obj, adr, mutable_only=True))
+    assert lst == []
+    #
+    s3 = lltype.malloc(S3)
+    adr = llmemory.cast_ptr_to_adr(s3)
+    lst = list(gc_pointers_inside(s3._obj, adr, mutable_only=True))
+    assert lst == [adr + llmemory.offsetof(S3, 'y')]

Modified: pypy/trunk/pypy/translator/backendopt/mallocv.py
==============================================================================
--- pypy/trunk/pypy/translator/backendopt/mallocv.py	(original)
+++ pypy/trunk/pypy/translator/backendopt/mallocv.py	Wed Oct 21 18:34:53 2009
@@ -1046,7 +1046,7 @@
         op = getattr(llop, opname)
     except AttributeError:
         return
-    if not op.is_pure(*[v.concretetype for v in args_v]):
+    if not op.is_pure(args_v):
         return
     try:
         result = op(RESTYPE, *args)

Modified: pypy/trunk/pypy/translator/backendopt/test/test_constfold.py
==============================================================================
--- pypy/trunk/pypy/translator/backendopt/test/test_constfold.py	(original)
+++ pypy/trunk/pypy/translator/backendopt/test/test_constfold.py	Wed Oct 21 18:34:53 2009
@@ -4,6 +4,7 @@
 from pypy.rpython.llinterp import LLInterpreter
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rpython import rclass
 from pypy.rlib import objectmodel
 from pypy.translator.backendopt.constfold import constant_fold_graph
 from pypy import conftest
@@ -26,8 +27,10 @@
     assert res == expected_result
 
 
-def test_simple():
-    S1 = lltype.GcStruct('S1', ('x', lltype.Signed), hints={'immutable': True})
+def test_simple(S1=None):
+    if S1 is None:
+        S1 = lltype.GcStruct('S1', ('x', lltype.Signed),
+                             hints={'immutable': True})
     s1 = lltype.malloc(S1)
     s1.x = 123
     def g(y):
@@ -42,6 +45,14 @@
     check_graph(graph, [], 124, t)
 
 
+def test_immutable_fields():
+    accessor = rclass.FieldListAccessor()
+    S2 = lltype.GcStruct('S2', ('x', lltype.Signed),
+                         hints={'immutable_fields': accessor})
+    accessor.initialize(S2, ['x'])
+    test_simple(S2)
+
+
 def test_along_link():
     S1 = lltype.GcStruct('S1', ('x', lltype.Signed), hints={'immutable': True})
     s1 = lltype.malloc(S1)



More information about the Pypy-commit mailing list