[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