Commits

Benjamin Peterson committed 0e75334

(arigo, benjamin) add a _immutable_fields_ hint to describe fields where operations can be folded safely
It uses the syntax of _virtualizable2_, so arrays can be indicated.

Comments (0)

Files changed (12)

pypy/interpreter/pycode.py

 class PyCode(eval.Code):
     "CPython-style code objects."
     _immutable_ = True
+    _immutable_fields_ = ["co_consts_w[*]", "co_names_w[*]", "co_varnames[*]",
+                          "co_freevars[*]", "co_cellvars[*]"]
 
     def __init__(self, space,  argcount, nlocals, stacksize, flags,
                      code, consts, names, varnames, filename,

pypy/jit/metainterp/codewriter.py

         self.register_var(op.result)
 
     def serialize_op_debug_assert(self, op):
-        pass     # for now
+        log.WARNING("found debug_assert in %r; should have be removed" %
+                    (self.graph,))
 
     def serialize_op_promote_virtualizable(self, op):
         vinfo = self.codewriter.metainterp_sd.virtualizable_info

pypy/jit/metainterp/test/test_virtualizable.py

 from pypy.rlib.rarithmetic import intmask
 from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
 from pypy.rpython.lltypesystem.rvirtualizable2 import VABLERTIPTR
-from pypy.rpython.lltypesystem.rvirtualizable2 import VirtualizableAccessor
+from pypy.rpython.rclass import FieldListAccessor
 from pypy.jit.metainterp.warmspot import get_stats
 from pypy.jit.metainterp import history, heaptracker
 from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin
         ('vable_rti', VABLERTIPTR),
         ('inst_x', lltype.Signed),
         ('inst_node', lltype.Ptr(LLtypeMixin.NODE)),
-        hints = {'virtualizable2_accessor': VirtualizableAccessor()})
+        hints = {'virtualizable2_accessor': FieldListAccessor()})
     XY._hints['virtualizable2_accessor'].initialize(
         XY, ['inst_x', 'inst_node'])
 
         ('inst_x', lltype.Signed),
         ('inst_l1', lltype.Ptr(lltype.GcArray(lltype.Signed))),
         ('inst_l2', lltype.Ptr(lltype.GcArray(lltype.Signed))),
-        hints = {'virtualizable2_accessor': VirtualizableAccessor()})
+        hints = {'virtualizable2_accessor': FieldListAccessor()})
     XY2._hints['virtualizable2_accessor'].initialize(
         XY2, ['inst_x', 'inst_l1[*]', 'inst_l2[*]'])
 

pypy/jit/metainterp/virtualizable.py

         self.VTYPE = VTYPE = deref(VTYPEPTR)
         #
         accessor = VTYPE._hints['virtualizable2_accessor']
-        all_fields = accessor.redirected_fields
+        all_fields = accessor.fields
         static_fields = []
         array_fields = []
         for name in all_fields:

pypy/rpython/lltypesystem/rclass.py

                                 AbstractInstanceRepr,\
                                 MissingRTypeAttribute,\
                                 getclassrepr, getinstancerepr,\
-                                get_type_repr, rtype_new_instance
+                                get_type_repr, rtype_new_instance, \
+                                FieldListAccessor
 from pypy.rpython.lltypesystem.lltype import \
      Ptr, Struct, GcStruct, malloc, \
      cast_pointer, cast_ptr_to_int, castable, nullptr, \
             if '_immutable_' in self.classdef.classdesc.classdict:
                 hints = hints.copy()
                 hints['immutable'] = True
+            if '_immutable_fields_' in self.classdef.classdesc.classdict:
+                hints = hints.copy()
+                self.immutable_field_list = self.classdef.classdesc.classdict['_immutable_fields_'].value
+                accessor = FieldListAccessor()
+                hints['immutable_fields'] = accessor
             if ('_hash_cache_' in fields or
                 '_hash_cache_' in self.rbase.allinstancefields):
                 adtmeths = adtmeths.copy()
             attachRuntimeTypeInfo(self.object_type)
 
     def _setup_repr_final(self):
+        hints = self.object_type._hints
+        if "immutable_fields" in hints:
+            accessor = hints["immutable_fields"]
+            self._parse_field_list(self.immutable_field_list, accessor)
         if self.gcflavor == 'gc':
             if (self.classdef is not None and
                 self.classdef.classdesc.lookup('__del__') is not None):
     def common_repr(self): # -> object or nongcobject reprs
         return getinstancerepr(self.rtyper, None, self.gcflavor)
 
+    def _get_field(self, attr):
+        return self.fields[attr]
+
     def null_instance(self):
         return nullptr(self.object_type)
 

pypy/rpython/lltypesystem/rvirtualizable2.py

 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.lltypesystem.rvirtualizable import VABLERTIPTR
 from pypy.rpython.lltypesystem.rclass import InstanceRepr
-from pypy.rpython.rvirtualizable2 import AbstractVirtualizableAccessor
 from pypy.rpython.rvirtualizable2 import AbstractVirtualizable2InstanceRepr
 
 
-class VirtualizableAccessor(AbstractVirtualizableAccessor):
-    pass
-
-
 class Virtualizable2InstanceRepr(AbstractVirtualizable2InstanceRepr, InstanceRepr):
 
-    VirtualizableAccessor = VirtualizableAccessor
-
     def _setup_repr_llfields(self):
         llfields = []
         if self.top_of_virtualizable_hierarchy:
             llfields.append(('vable_rti', VABLERTIPTR))
         return llfields
 
-    def get_field(self, attr):
-        return self.fields[attr]
-
     def set_vable(self, llops, vinst, force_cast=False):
         if self.top_of_virtualizable_hierarchy:
             if force_cast:

pypy/rpython/ootypesystem/rclass.py

 
         ootype.overrideDefaultForFields(self.lowleveltype, overridden_defaults)
 
+    def _get_field(self, attr):
+        mangled = mangle(attr, self.rtyper.getconfig())
+        return mangled, self.allfields[mangled]
+
     def attach_abstract_class_attr_accessor(self, mangled, attrtype):
         M = ootype.Meth([], attrtype)
         m = ootype.meth(M, _name=mangled, abstract=True)

pypy/rpython/ootypesystem/rvirtualizable2.py

 from pypy.rpython.rmodel import inputconst
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.ootypesystem.rclass import InstanceRepr, mangle, OBJECT
-from pypy.rpython.rvirtualizable2 import AbstractVirtualizableAccessor
 from pypy.rpython.rvirtualizable2 import AbstractVirtualizable2InstanceRepr
 
 VABLERTI = OBJECT
 
 
-class VirtualizableAccessor(AbstractVirtualizableAccessor):
-    pass
-
-
 class Virtualizable2InstanceRepr(AbstractVirtualizable2InstanceRepr, InstanceRepr):
 
-    VirtualizableAccessor = VirtualizableAccessor
-
     def _setup_repr_llfields(self):
         llfields = []
         if self.top_of_virtualizable_hierarchy:
             llfields.append(('vable_rti', VABLERTI))
         return llfields
 
-    def get_field(self, attr):
-        mangled = mangle(attr, self.rtyper.getconfig())
-        return mangled, self.allfields[mangled]
-
     def set_vable(self, llops, vinst, force_cast=False):
         pass # TODO

pypy/rpython/rclass.py

 from pypy.rpython.error import TyperError
 from pypy.rpython.rmodel import Repr, getgcflavor
 
+
+class FieldListAccessor(object):
+
+    def initialize(self, TYPE, fields):
+        self.TYPE = TYPE
+        self.fields = fields
+
+    def __repr__(self):
+        return '<FieldListAccessor for %s>' % getattr(self, 'TYPE', '?')
+
+    def _freeze_(self):
+        return True
+
+
 def getclassrepr(rtyper, classdef):
     try:
         result = rtyper.class_reprs[classdef]
     def _setup_repr_final(self):
         pass
 
+    def _parse_field_list(self, fields, accessor):
+        mangled_fields = {}
+        with_suffix = []
+        for name in fields:
+            if name.endswith('[*]'):
+                name = name[:-3]
+                suffix = '[*]'
+            else:
+                suffix = ''
+            mangled_name, r = self._get_field(name)
+            with_suffix.append(mangled_name + suffix)
+            mangled_fields[mangled_name] = True
+        accessor.initialize(self.object_type, with_suffix)
+        return mangled_fields
+
     def new_instance(self, llops, classcallhop=None):
         raise NotImplementedError
 

pypy/rpython/rvirtualizable2.py

 from pypy.rpython.rmodel import inputconst, log
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.ootypesystem import ootype
-from pypy.rpython.rclass import AbstractInstanceRepr
-
-
-class AbstractVirtualizableAccessor(object):
-
-    def initialize(self, TYPE, redirected_fields):
-        self.TYPE = TYPE
-        self.redirected_fields = redirected_fields
-
-    def __repr__(self):
-        return '<VirtualizableAccessor for %s>' % getattr(self, 'TYPE', '?')
-
-    def _freeze_(self):
-        return True
+from pypy.rpython.rclass import AbstractInstanceRepr, FieldListAccessor
 
 
 class AbstractVirtualizable2InstanceRepr(AbstractInstanceRepr):
 
-    VirtualizableAccessor = AbstractVirtualizableAccessor
-
     def _super(self):
         return super(AbstractVirtualizable2InstanceRepr, self)
 
             basedesc = classdesc.basedesc
             assert basedesc is None or basedesc.lookup('_virtualizable2_') is None
             self.top_of_virtualizable_hierarchy = True
-            self.accessor = self.VirtualizableAccessor()
+            self.accessor = FieldListAccessor()
         else:
             self.top_of_virtualizable_hierarchy = False
 
     def set_vable(self, llops, vinst, force_cast=False):
         raise NotImplementedError
 
-    def get_field(self, attr):
-        raise NotImplementedError
-
     def _setup_repr(self):
         if self.top_of_virtualizable_hierarchy:
             hints = {'virtualizable2_accessor': self.accessor}
                 self._super()._setup_repr(llfields, hints = hints)
             else:
                 self._super()._setup_repr(hints = hints)
-            my_redirected_fields = []
-            self.my_redirected_fields = {}
             c_vfields = self.classdef.classdesc.classdict['_virtualizable2_']
-            for name in c_vfields.value:
-                if name.endswith('[*]'):
-                    name = name[:-3]
-                    suffix = '[*]'
-                else:
-                    suffix = ''
-                mangled_name, r = self.get_field(name)
-                my_redirected_fields.append(mangled_name + suffix)
-                self.my_redirected_fields[mangled_name] = True
-            self.accessor.initialize(self.object_type, my_redirected_fields)
+            self.my_redirected_fields = self._parse_field_list(c_vfields.value,
+                                                               self.accessor)
         else:
             self.my_redirected_fields = {}
             self._super()._setup_repr()

pypy/rpython/test/test_rclass.py

         t, typer, graph = self.gengraph(f, [], backendopt=True)
         assert summary(graph) == {}
 
+    def test_immutable_fields(self):
+        class A(object):
+            _immutable_fields_ = ["x", "y[*]"]
+
+            def __init__(self, x, y):
+                self.x = x
+                self.y = y
+
+        def f():
+            return A(3, [])
+        t, typer, graph = self.gengraph(f, [])
+        A_TYPE = graph.getreturnvar().concretetype
+        accessor = A_TYPE.TO._hints["immutable_fields"]
+        assert accessor.fields == ["inst_x", "inst_y[*]"]
+
     def test_immutable_inheritance(self):
         class I(object):
             def __init__(self, v):

pypy/rpython/test/test_rvirtualizable2.py

         TYPE = self.gettype(v_inst)
         accessor = TYPE._hints['virtualizable2_accessor']
         assert accessor.TYPE == TYPE
-        assert accessor.redirected_fields == [self.prefix + 'v1',
-                                              self.prefix + 'v2[*]']
+        assert accessor.fields == [self.prefix + 'v1',
+                                   self.prefix + 'v2[*]']
         #
         def fn2(n):
             Base().base1 = 42