[pypy-svn] pypy out-of-line-guards-2: Redo "jit-invariant-fields" as "quasi-immutable fields". Reuse as

arigo commits-noreply at bitbucket.org
Sat Apr 2 11:26:31 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: out-of-line-guards-2
Changeset: r43108:87905b4483df
Date: 2011-04-02 11:20 +0200
http://bitbucket.org/pypy/pypy/changeset/87905b4483df/

Log:	Redo "jit-invariant-fields" as "quasi-immutable fields". Reuse as
	much the existing code as possible.

diff --git a/pypy/rpython/ootypesystem/rclass.py b/pypy/rpython/ootypesystem/rclass.py
--- a/pypy/rpython/ootypesystem/rclass.py
+++ b/pypy/rpython/ootypesystem/rclass.py
@@ -262,6 +262,10 @@
         self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef)
         self.rbase.setup()
 
+        for name, attrdef in selfattrs.iteritems():
+            if not attrdef.readonly and self.is_quasi_immutable(name):
+                ootype.addFields(self.lowleveltype, {'mutable_'+name: OBJECT})
+
         classattributes = {}
         baseInstance = self.lowleveltype._superclass
         classrepr = getclassrepr(self.rtyper, self.classdef)
@@ -476,11 +480,9 @@
         mangled_name = mangle(attr, self.rtyper.getconfig())
         cname = inputconst(ootype.Void, mangled_name)
         self.hook_access_field(vinst, cname, llops, flags)
+        self.hook_setfield(vinst, attr, llops)
         llops.genop('oosetfield', [vinst, cname, vvalue])
 
-    def hook_access_field(self, vinst, cname, llops, flags):
-        pass        # for virtualizables; see rvirtualizable2.py
-
     def rtype_is_true(self, hop):
         vinst, = hop.inputargs(self)
         return hop.genop('oononnull', [vinst], resulttype=ootype.Bool)

diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py
--- a/pypy/rpython/lltypesystem/opimpl.py
+++ b/pypy/rpython/lltypesystem/opimpl.py
@@ -525,6 +525,9 @@
 def op_jit_force_virtual(x):
     return x
 
+def op_jit_force_quasi_immutable(x):
+    pass
+
 def op_get_group_member(TYPE, grpptr, memberoffset):
     from pypy.rpython.lltypesystem import llgroup
     assert isinstance(memberoffset, llgroup.GroupMemberOffset)

diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py
--- a/pypy/rpython/rclass.py
+++ b/pypy/rpython/rclass.py
@@ -3,7 +3,8 @@
 #from pypy.annotation.classdef import isclassdef
 from pypy.annotation import description
 from pypy.rpython.error import TyperError
-from pypy.rpython.rmodel import Repr, getgcflavor
+from pypy.rpython.rmodel import Repr, getgcflavor, inputconst
+from pypy.rpython.lltypesystem.lltype import Void
 
 
 class FieldListAccessor(object):
@@ -155,7 +156,8 @@
         self.classdef = classdef
 
     def _setup_repr(self):
-        pass
+        if self.classdef is None:
+            self.immutable_field_set = set()
 
     def _check_for_immutable_hints(self, hints):
         loc = self.classdef.classdesc.lookup('_immutable_')
@@ -167,13 +169,13 @@
                     self.classdef,))
             hints = hints.copy()
             hints['immutable'] = True
-        self.immutable_field_list = []  # unless overwritten below
+        self.immutable_field_set = set()  # unless overwritten below
         if self.classdef.classdesc.lookup('_immutable_fields_') is not None:
             hints = hints.copy()
             immutable_fields = self.classdef.classdesc.classdict.get(
                 '_immutable_fields_')
             if immutable_fields is not None:
-                self.immutable_field_list = immutable_fields.value
+                self.immutable_field_set = set(immutable_fields.value)
             accessor = FieldListAccessor()
             hints['immutable_fields'] = accessor
         return hints
@@ -201,20 +203,23 @@
         if "immutable_fields" in hints:
             accessor = hints["immutable_fields"]
             if not hasattr(accessor, 'fields'):
-                immutable_fields = []
+                immutable_fields = set()
                 rbase = self
                 while rbase.classdef is not None:
-                    immutable_fields += rbase.immutable_field_list
+                    immutable_fields.update(rbase.immutable_field_set)
                     rbase = rbase.rbase
                 self._parse_field_list(immutable_fields, accessor)
 
     def _parse_field_list(self, fields, accessor):
         with_suffix = {}
         for name in fields:
-            if name.endswith('[*]'):
+            if name.endswith('[*]'):    # for virtualizables' lists
                 name = name[:-3]
                 suffix = '[*]'
-            else:
+            elif name.endswith('?'):    # a quasi-immutable field
+                name = name[:-1]
+                suffix = '?'
+            else:                       # a regular immutable/green field
                 suffix = ''
             try:
                 mangled_name, r = self._get_field(name)
@@ -227,7 +232,6 @@
     def _check_for_immutable_conflicts(self):
         # check for conflicts, i.e. a field that is defined normally as
         # mutable in some parent class but that is now declared immutable
-        from pypy.rpython.lltypesystem.lltype import Void
         is_self_immutable = "immutable" in self.object_type._hints
         base = self
         while base.classdef is not None:
@@ -248,12 +252,30 @@
                         "class %r has _immutable_=True, but parent class %r "
                         "defines (at least) the mutable field %r" % (
                         self, base, fieldname))
-                if fieldname in self.immutable_field_list:
+                if (fieldname in self.immutable_field_set or
+                    (fieldname + '?') in self.immutable_field_set):
                     raise ImmutableConflictError(
                         "field %r is defined mutable in class %r, but "
                         "listed in _immutable_fields_ in subclass %r" % (
                         fieldname, base, self))
 
+    def hook_access_field(self, vinst, cname, llops, flags):
+        pass        # for virtualizables; see rvirtualizable2.py
+
+    def hook_setfield(self, vinst, fieldname, llops):
+        if self.is_quasi_immutable(fieldname):
+            c_fieldname = inputconst(Void, 'mutate_' + fieldname)
+            llops.genop('jit_force_quasi_immutable', [vinst, c_fieldname])
+
+    def is_quasi_immutable(self, fieldname):
+        search = fieldname + '?'
+        rbase = self
+        while rbase.classdef is not None:
+            if search in rbase.immutable_field_set:
+                return True
+            rbase = rbase.rbase
+        return False
+
     def new_instance(self, llops, classcallhop=None):
         raise NotImplementedError
 

diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -433,6 +433,7 @@
     'jit_marker':           LLOp(),
     'jit_force_virtualizable':LLOp(canrun=True),
     'jit_force_virtual':    LLOp(canrun=True),
+    'jit_force_quasi_immutable': LLOp(canrun=True),
     'get_exception_addr':   LLOp(),
     'get_exc_value_addr':   LLOp(),
     'do_malloc_fixedsize_clear':LLOp(canraise=(MemoryError,),canunwindgc=True),

diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py
--- a/pypy/rpython/test/test_rclass.py
+++ b/pypy/rpython/test/test_rclass.py
@@ -895,6 +895,30 @@
         B_TYPE = deref(graph.getreturnvar().concretetype)
         assert B_TYPE._hints["immutable"]
 
+    def test_quasi_immutable(self):
+        from pypy.jit.metainterp.typesystem import deref
+        class A(object):
+            _immutable_fields_ = ['x', 'y?', 'z?']
+        class B(A):
+            pass
+        def f():
+            A().x = 42
+            A().y = 43
+            b = B()
+            b.y = 41
+            b.z = 44
+            return B()
+        t, typer, graph = self.gengraph(f, [])
+        B_TYPE = deref(graph.getreturnvar().concretetype)
+        accessor = B_TYPE._hints["immutable_fields"]
+        assert accessor.fields == {"inst_z" : "?"} or \
+               accessor.fields == {'ox':'', 'oy':'?', 'oz':'?'} # for ootype
+        found = []
+        for op in graph.startblock.operations:
+            if op.opname == 'jit_force_quasi_immutable':
+                found.append(op.args[1].value)
+        assert found == ['mutate_y', 'mutate_y', 'mutate_z']
+
 
 class TestLLtype(BaseTestRclass, LLRtypeMixin):
 

diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py
--- a/pypy/rpython/lltypesystem/rclass.py
+++ b/pypy/rpython/lltypesystem/rclass.py
@@ -322,6 +322,7 @@
         #       before they are fully built, to avoid strange bugs in case
         #       of recursion where other code would uses these
         #       partially-initialized dicts.
+        AbstractInstanceRepr._setup_repr(self)
         self.rclass = getclassrepr(self.rtyper, self.classdef)
         fields = {}
         allinstancefields = {}
@@ -370,6 +371,11 @@
             kwds = {}
             if self.gcflavor == 'gc':
                 kwds['rtti'] = True
+
+            for name, attrdef in attrs:
+                if not attrdef.readonly and self.is_quasi_immutable(name):
+                    llfields.append(('mutate_' + name, OBJECTPTR))
+
             object_type = MkStruct(self.classdef.name,
                                    ('super', self.rbase.object_type),
                                    hints=hints,
@@ -488,6 +494,7 @@
             if force_cast:
                 vinst = llops.genop('cast_pointer', [vinst], resulttype=self)
             self.hook_access_field(vinst, cname, llops, flags)
+            self.hook_setfield(vinst, attr, llops)
             llops.genop('setfield', [vinst, cname, vvalue])
         else:
             if self.classdef is None:
@@ -495,9 +502,6 @@
             self.rbase.setfield(vinst, attr, vvalue, llops, force_cast=True,
                                 flags=flags)
 
-    def hook_access_field(self, vinst, cname, llops, flags):
-        pass        # for virtualizables; see rvirtualizable2.py
-
     def new_instance(self, llops, classcallhop=None):
         """Build a new instance, without calling __init__."""
         flavor = self.gcflavor


More information about the Pypy-commit mailing list