[pypy-svn] r6379 - in pypy/trunk/src/pypy: annotation translator

arigo at codespeak.net arigo at codespeak.net
Fri Sep 10 14:58:06 CEST 2004


Author: arigo
Date: Fri Sep 10 14:58:06 2004
New Revision: 6379

Modified:
   pypy/trunk/src/pypy/annotation/factory.py
   pypy/trunk/src/pypy/annotation/unaryop.py
   pypy/trunk/src/pypy/translator/classtyper.py
   pypy/trunk/src/pypy/translator/genc.py
   pypy/trunk/src/pypy/translator/genc_typeset.py
Log:
When annotating the usage of class instances, record for which attributes
setattr is used, and which ones it is not.  The latter are class attributes
that don't have to be allocated in each instance's C struct.

Cleaned up classtyper.py.

Next step is to figure out in which C struct the class attributes should be
stored (given that the goal is that subclasses can override them).  Maybe
in an extended PyTypeObject?


Modified: pypy/trunk/src/pypy/annotation/factory.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/factory.py	(original)
+++ pypy/trunk/src/pypy/annotation/factory.py	Fri Sep 10 14:58:06 2004
@@ -152,6 +152,7 @@
 
     def __init__(self, cls, bookkeeper):
         self.attrs = {}          # attrs is updated with new information
+        self.readonly = {}       # {attr: True-or-False}
         self.revision = 0        # which increases the revision number
         self.instancefactories = {}
         self.cls = cls
@@ -208,7 +209,7 @@
             factories.update(clsdef.instancefactories)
         return factories
 
-    def generalize(self, attr, s_value, bookkeeper=None):
+    def generalize(self, attr, s_value, bookkeeper=None, readonly=True):
         # we make sure that an attribute never appears both in a class
         # and in some subclass, in two steps:
         # (1) check if the attribute is already in a superclass
@@ -221,10 +222,13 @@
         for subdef in self.getallsubdefs():
             if attr in subdef.attrs:
                 subclass_values.append(subdef.attrs[attr])
+                readonly = readonly and subdef.readonly[attr]
                 del subdef.attrs[attr]
+                del subdef.readonly[attr]
             # bump the revision number of this class and all subclasses
             subdef.revision += 1
         self.attrs[attr] = unionof(s_value, *subclass_values)
+        self.readonly[attr] = readonly
         # reflow from all factories
         if bookkeeper:
             for factory in self.getallfactories():

Modified: pypy/trunk/src/pypy/annotation/unaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/unaryop.py	(original)
+++ pypy/trunk/src/pypy/annotation/unaryop.py	Fri Sep 10 14:58:06 2004
@@ -107,13 +107,14 @@
                     # look for the attribute in ins.classdef or a parent class
                     s_existing = clsdef.attrs[attr]
                     if s_existing.contains(s_value):
+                        clsdef.readonly[attr] = False
                         return   # already general enough, nothing to do
                     break
             else:
                 # if the attribute doesn't exist yet, create it here
                 clsdef = ins.classdef
             # create or update the attribute in clsdef
-            clsdef.generalize(attr, s_value, getbookkeeper())
+            clsdef.generalize(attr, s_value, getbookkeeper(), readonly=False)
             raise BlockedInference
         return SomeObject()
 

Modified: pypy/trunk/src/pypy/translator/classtyper.py
==============================================================================
--- pypy/trunk/src/pypy/translator/classtyper.py	(original)
+++ pypy/trunk/src/pypy/translator/classtyper.py	Fri Sep 10 14:58:06 2004
@@ -17,10 +17,11 @@
 class ClassField:
     "An attribute of a class, mapped to some field(s) of a low-level struct."
     
-    def __init__(self, hltype, name, llclass):
+    def __init__(self, hltype, name, llclass, is_class_attr):
         self.hltype  = hltype
         self.name    = name
         self.llclass = llclass
+        self.is_class_attr = is_class_attr
         varname = '%s_%s' % (llclass.field_prefix, name)
         # to avoid name collisions between the 2nd lltype of a field called xyz
         # and another field whose name is exactly xyz_1, forbid field names
@@ -48,49 +49,50 @@
     """Low-level representation of a class as a structure and
     global functions that operate on it."""
     
-    def __init__(self, typeset, name, cdef):
+    def __init__(self, typeset, name, cdef, llparent):
         LLTyper.__init__(self, typeset)
         self.typeset = typeset
         self.name = name
         self.cdef = cdef    # instance of pypy.annotator.factory.ClassDef
+        self.llparent = llparent
         self.bindings = typeset.bindings
+        self.s_instance = annmodel.SomeInstance(self.cdef)
 
         # collect the fields that the annotator deduced for this class
         cls = cdef.cls
         mainletters = [c.lower() for c in cls.__name__ if 'A' <= c <= 'Z']
         self.field_prefix = ''.join(mainletters[:3] or ['f'])
-        self.fields = [ClassField(typeset.gethltype(s_value), attr, self)
-                       for attr, s_value in cdef.attrs.items()]
-
-        self.pyobj_fields = [  # XXX this should not be necessary
-            fld.name for fld in self.fields if fld.hltype == R_OBJECT]
-        self.s_instance = annmodel.SomeInstance(self.cdef)
-
-    def getparent(self):
-        if self.cdef.basedef is None:
-            return None
+        self.fields_here = [ClassField(typeset.gethltype(s_value), attr, self,
+                                       is_class_attr = cdef.readonly[attr])
+                            for attr, s_value in cdef.attrs.items()]
+        # fields are divided in instance attributes and class attributes
+        # according to whether they are ever accessed with SET_ATTR or not
+        if llparent:
+            self.instance_fields = list(llparent.instance_fields)
+            self.class_fields    = list(llparent.class_fields)
         else:
-            return self.typeset.genc.llclasses[self.cdef.basedef.cls]
+            self.instance_fields = []
+            self.class_fields    = []
+        self.instance_fields += [fld for fld in self.fields_here
+                                 if not fld.is_class_attr]
+        self.class_fields    += [fld for fld in self.fields_here
+                                 if fld.is_class_attr]
 
-    def getfield(self, name):
+    def get_instance_field(self, name):
         """Returns the ClassField corresponding to this attribute name.
         Keep in mind that it might be from some parent LLClass."""
-        while self is not None:
-            for fld in self.fields:
-                if fld.name == name:
-                    return fld
-            self = self.getparent()
+        for fld in self.instance_fields:
+            if fld.name == name:
+                return fld
         return None
 
-    def getfields(self):
-        "Return the list of all fields, including the ones from the parent."
-        parent = self.getparent()
-        if parent is None:
-            fields = []
-        else:
-            fields = parent.getfields()
-        fields += self.fields
-        return fields
+    def get_class_field(self, name):
+        """Returns the ClassField corresponding to this class attribute name.
+        Keep in mind that it might be from some parent LLClass."""
+        for fld in self.class_fields:
+            if fld.name == name:
+                return fld
+        return None
 
     def get_management_functions(self):
         "Generate LLFunctions that operate on this class' structure."
@@ -115,8 +117,8 @@
         cls = self.cdef.cls
         v1 = op('alloc_instance', Constant(cls),
                 s_result = self.s_instance)
-        # class attributes are used as defaults to initialize fields
-        for fld in self.getfields():
+        # class attributes are used as defaults to initialize instance fields
+        for fld in self.instance_fields:
             if hasattr(cls, fld.name):
                 value = getattr(cls, fld.name)
                 op('setattr', v1, Constant(fld.name), Constant(value),

Modified: pypy/trunk/src/pypy/translator/genc.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genc.py	(original)
+++ pypy/trunk/src/pypy/translator/genc.py	Fri Sep 10 14:58:06 2004
@@ -91,12 +91,19 @@
             return
         n = 0
         for cdef in self.translator.annotator.getuserclassdefinitions():
+            # annotation.factory guarantees that this will enumerate
+            # the ClassDefs in a parent-first, children-last order.
             cls = cdef.cls
             assert cls not in self.llclasses, '%r duplicate' % (cls,)
+            if cdef.basedef is None:
+                llparent = None
+            else:
+                llparent = self.llclasses[cdef.basedef.cls]
             llclass = LLClass(
                 typeset = self.typeset,
                 name = '%s__%d' % (cls.__name__, n),
                 cdef = cdef,
+                llparent = llparent,
                 )
             self.llclasses[cls] = llclass
             self.classeslist.append(llclass)
@@ -243,12 +250,12 @@
             'name': llclass.name,
             'base': '0',
             }
-        if llclass.getparent() is not None:
-            info['base'] = '&%s_Type' % llclass.getparent().name
+        if llclass.llparent is not None:
+            info['base'] = '&%s_Type' % llclass.llparent.name
 
         # print the C struct declaration
         print >> f, self.C_STRUCT_HEADER % info
-        for fld in llclass.getfields():
+        for fld in llclass.instance_fields:
             for llvar in fld.llvars:
                 print >> f, '\t%s %s;' % (llvar.type, llvar.name)
         print >> f, self.C_STRUCT_FOOTER % info
@@ -257,7 +264,7 @@
         # other functions are generated by LLClass.get_management_functions()
         print >> f, self.C_DEALLOC_HEADER % info
         llxdecref = self.typeset.rawoperations['xdecref']
-        for fld in llclass.getfields():
+        for fld in llclass.instance_fields:
             llvars = fld.getllvars('op->%s')
             line = llxdecref(llvars)
             code = line.write()
@@ -269,7 +276,10 @@
         # generate the member list for the type object
         print >> f, self.C_MEMBERLIST_HEADER % info
         # XXX write member definitions for member with well-known types only
-        for fld in llclass.fields:  # members from parent inherited via tp_base
+        #     members from the parents are inherited via tp_base
+        for fld in llclass.fields_here:
+            if fld.is_class_attr:
+                continue   # XXX should provide a reader
             if fld.hltype == R_OBJECT:
                 t = 'T_OBJECT_EX'
             elif fld.hltype == R_INT:

Modified: pypy/trunk/src/pypy/translator/genc_typeset.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genc_typeset.py	(original)
+++ pypy/trunk/src/pypy/translator/genc_typeset.py	Fri Sep 10 14:58:06 2004
@@ -182,7 +182,7 @@
         r_obj, r_attr, r_result = hltypes
         if isinstance(r_obj, CInstance) and isinstance(r_attr, CConstant):
             # record the OP_GETATTR operation for this field
-            fld = r_obj.llclass.getfield(r_attr.value)
+            fld = r_obj.llclass.get_instance_field(r_attr.value)
             if fld is not None:
                 sig = (r_obj, constant_representation(fld.name), fld.hltype)
                 yield sig, genc_op.LoGetAttr.With(
@@ -195,7 +195,7 @@
         r_obj, r_attr, r_value, r_voidresult = hltypes
         if isinstance(r_obj, CInstance):
             # record the OP_SETATTR operation for this field
-            fld = r_obj.llclass.getfield(r_attr.value)
+            fld = r_obj.llclass.get_instance_field(r_attr.value)
             if fld is not None:
                 sig = (r_obj, constant_representation(fld.name), fld.hltype,
                        R_VOID)



More information about the Pypy-commit mailing list