[pypy-svn] r6382 - in pypy/trunk/src/pypy/translator: . test
arigo at codespeak.net
arigo at codespeak.net
Fri Sep 10 16:44:46 CEST 2004
Author: arigo
Date: Fri Sep 10 16:44:45 2004
New Revision: 6382
Modified:
pypy/trunk/src/pypy/translator/classtyper.py
pypy/trunk/src/pypy/translator/genc.h
pypy/trunk/src/pypy/translator/genc.py
pypy/trunk/src/pypy/translator/genc_op.py
pypy/trunk/src/pypy/translator/genc_typeset.py
pypy/trunk/src/pypy/translator/test/snippet.py
pypy/trunk/src/pypy/translator/test/test_ctrans.py
Log:
Class attributes. (Methods are the next step.) This is done by storing the
attributes in an extension of the PyTypeObjects, as described in
genc.py. There is a bit of code duplication between class and instance
attributes, that should be cleaned up sometime.
--This line, and those below, will be ignored--
M translator/test/test_ctrans.py
M translator/test/snippet.py
M translator/classtyper.py
M translator/genc_typeset.py
M translator/genc_op.py
M translator/genc.h
M translator/genc.py
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 16:44:45 2004
@@ -97,6 +97,7 @@
def get_management_functions(self):
"Generate LLFunctions that operate on this class' structure."
yield self.make_fn_new()
+ yield self.make_fn_typenew()
def build_llfunc(self, graph):
return LLFunction(self.typeset, graph.name, graph)
@@ -128,3 +129,21 @@
self.bindings[graph.getreturnvar()] = self.bindings[v1]
b.closeblock(Link([v1], graph.returnblock))
return self.build_llfunc(graph)
+
+ def make_fn_typenew(self):
+ # generate the flow graph of the xxx_typenew() function that
+ # initializes the class attributes of the type object
+ b = Block([])
+ op = self.put_op(b)
+ cls = self.cdef.cls
+ v1 = Constant(cls)
+ # initialize class attributes
+ for fld in self.class_fields:
+ value = getattr(cls, fld.name)
+ op('initclassattr', v1, Constant(fld.name), Constant(value),
+ s_result = annmodel.SomeImpossibleValue())
+ # finally, return None
+ graph = FunctionGraph('%s_typenew' % self.name, b)
+ self.bindings[graph.getreturnvar()] = annmodel.immutablevalue(None)
+ b.closeblock(Link([Constant(None)], graph.returnblock))
+ return self.build_llfunc(graph)
Modified: pypy/trunk/src/pypy/translator/genc.h
==============================================================================
--- pypy/trunk/src/pypy/translator/genc.h (original)
+++ pypy/trunk/src/pypy/translator/genc.h Fri Sep 10 16:44:45 2004
@@ -97,12 +97,18 @@
#define INSTANTIATE(cls, r, err) if (!(r=cls##_new())) goto err;
#define ALLOC_INSTANCE(cls, r, err) \
- if (!(r=PyType_GenericAlloc(&cls##_Type, 0))) goto err;
+ if (!(r=PyType_GenericAlloc(&cls##_Type.type, 0))) goto err;
+#define SETUP_TYPE(cls) \
+ PyType_Ready(&cls##_Type.type); \
+ cls##_typenew();
#define GET_ATTR_py(fld, r) r=fld; Py_INCREF(r);
#define SET_ATTR_py(fld, v) { PyObject* o=fld; fld=v; \
Py_INCREF(v); Py_XDECREF(o); }
+#define GET_ATTR_cls(fld, r) r=fld; Py_INCREF(r);
+#define SET_ATTR_cls(fld, v) fld=v; Py_INCREF(v); /* initialization only */
+
/* a few built-in functions */
#define CALL_len_oi(o,r,err) if ((r=PyObject_Size(o))<0) goto err;
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 16:44:45 2004
@@ -251,7 +251,7 @@
'base': '0',
}
if llclass.llparent is not None:
- info['base'] = '&%s_Type' % llclass.llparent.name
+ info['base'] = '&%s_Type.type' % llclass.llparent.name
# print the C struct declaration
print >> f, self.C_STRUCT_HEADER % info
@@ -260,6 +260,14 @@
print >> f, '\t%s %s;' % (llvar.type, llvar.name)
print >> f, self.C_STRUCT_FOOTER % info
+ # print the struct Xxx_TypeObject, which is an extension of
+ # PyTypeObject with the class attributes of this class
+ print >> f, self.C_TYPESTRUCT_HEADER % info
+ for fld in llclass.class_fields:
+ for llvar in fld.llvars:
+ print >> f, '\t%s %s;' % (llvar.type, llvar.name)
+ print >> f, self.C_TYPESTRUCT_FOOTER % info
+
# generate the deallocator function -- must special-case it;
# other functions are generated by LLClass.get_management_functions()
print >> f, self.C_DEALLOC_HEADER % info
@@ -293,7 +301,7 @@
# declare and initialize the static PyTypeObject
print >> f, self.C_TYPEOBJECT % info
- self.initializationcode += (self.C_INITTYPE % info).split('\n')
+ self.initializationcode.append('SETUP_TYPE(%s)' % llclass.name)
# ____________________________________________________________
@@ -332,7 +340,7 @@
C_DEALLOC_HEADER = '''static void %(name)s_dealloc(%(name)s_Object* op)
{'''
- C_DEALLOC_FOOTER = ''' op->ob_type->tp_free((PyObject*) op);
+ C_DEALLOC_FOOTER = ''' PyObject_Del((PyObject*) op);
}
'''
@@ -342,7 +350,24 @@
};
'''
- C_TYPEOBJECT = '''static PyTypeObject %(name)s_Type = {
+ # NB: our types don't have Py_TPFLAGS_BASETYPE because we do not want
+ # the complications of dynamically created subclasses. This doesn't
+ # prevent the various types from inheriting from each other via
+ # tp_base. This is ok because we expect all RPython classes to exist
+ # and be analyzed in advance. This allows class attributes to be stored
+ # as an extensison of the PyTypeObject structure, which are then
+ # accessed with ((PyXxxTypeObject*)op->ob_type)->classattrname.
+ # This doesn't work if op->ob_type can point to a heap-allocated
+ # type object over which we have no control.
+
+ C_TYPESTRUCT_HEADER = '''typedef struct {
+ PyTypeObject type;
+ /* class attributes follow */'''
+
+ C_TYPESTRUCT_FOOTER = '''} %(name)s_TypeObject;
+'''
+
+ C_TYPEOBJECT = '''static %(name)s_TypeObject %(name)s_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"%(name)s",
@@ -363,7 +388,7 @@
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* XXX need GC */ /* tp_traverse */
0, /* tp_clear */
@@ -386,6 +411,4 @@
};
'''
- C_INITTYPE = '''PyType_Ready(&%(name)s_Type);'''
-
# ____________________________________________________________
Modified: pypy/trunk/src/pypy/translator/genc_op.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genc_op.py (original)
+++ pypy/trunk/src/pypy/translator/genc_op.py Fri Sep 10 16:44:45 2004
@@ -158,25 +158,34 @@
assert len(result) == len(self.fld.llvars)
ls = []
llclass = self.fld.llclass
- for src, dstname in zip(self.fld.llvars, result):
- fldexpr = '((%s_Object*) %s)->%s' % (llclass.name, inst,
- src.name)
- if src.type == 'PyObject*':
- ls.append('GET_ATTR_py(%s, %s)' % (fldexpr, dstname))
- else:
- ls.append('%s = %s;' % (dstname, fldexpr))
+ if self.fld.is_class_attr:
+ for src, dstname in zip(self.fld.llvars, result):
+ fldexpr = '((%s_TypeObject*)(%s->ob_type))->%s' % (
+ llclass.name, inst, src.name)
+ if src.type == 'PyObject*':
+ ls.append('GET_ATTR_cls(%s, %s)' % (fldexpr, dstname))
+ else:
+ ls.append('%s = %s;' % (dstname, fldexpr))
+ else:
+ for src, dstname in zip(self.fld.llvars, result):
+ fldexpr = '((%s_Object*) %s)->%s' % (llclass.name, inst,
+ src.name)
+ if src.type == 'PyObject*':
+ ls.append('GET_ATTR_py(%s, %s)' % (fldexpr, dstname))
+ else:
+ ls.append('%s = %s;' % (dstname, fldexpr))
return '\n'.join(ls)
class LoSetAttr(LoC):
- cost = 1
- fld = PARAMETER
+ cost = 1
+ llclass = PARAMETER # the class involved in the operation
+ fld = PARAMETER # the field, which might come from a parent class
def writestr(self, inst, *value):
assert len(value) == len(self.fld.llvars)
ls = []
- llclass = self.fld.llclass
for srcname, dst in zip(value, self.fld.llvars):
- fldexpr = '((%s_Object*) %s)->%s' % (llclass.name, inst,
+ fldexpr = '((%s_Object*) %s)->%s' % (self.llclass.name, inst,
dst.name)
if dst.type == 'PyObject*':
ls.append('SET_ATTR_py(%s, %s)' % (fldexpr, srcname))
@@ -184,6 +193,23 @@
ls.append('%s = %s;' % (fldexpr, srcname))
return '\n'.join(ls)
+class LoInitClassAttr(LoC):
+ cost = 1
+ llclass = PARAMETER # the class involved in the operation
+ fld = PARAMETER # the field, which might come from a parent class
+
+ def writestr(self, *value):
+ assert len(value) == len(self.fld.llvars)
+ ls = []
+ # setting class attributes is only used for initialization
+ for srcname, dst in zip(value, self.fld.llvars):
+ fldexpr = '%s_Type.%s' % (self.llclass.name, dst.name)
+ if dst.type == 'PyObject*':
+ ls.append('SET_ATTR_cls(%s, %s)' % (fldexpr, srcname))
+ else:
+ ls.append('%s = %s;' % (fldexpr, srcname))
+ return '\n'.join(ls)
+
class LoConvertChain(LoOptimized):
r_from = PARAMETER
r_middle = PARAMETER
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 16:44:45 2004
@@ -180,11 +180,14 @@
if len(hltypes) != 3:
return
r_obj, r_attr, r_result = hltypes
- if isinstance(r_obj, CInstance) and isinstance(r_attr, CConstant):
+ if not isinstance(r_attr, CConstant):
+ return
+ if isinstance(r_obj, CInstance):
# record the OP_GETATTR operation for this field
- fld = r_obj.llclass.get_instance_field(r_attr.value)
+ fld = (r_obj.llclass.get_instance_field(r_attr.value) or
+ r_obj.llclass.get_class_field(r_attr.value))
if fld is not None:
- sig = (r_obj, constant_representation(fld.name), fld.hltype)
+ sig = (r_obj, r_attr, fld.hltype)
yield sig, genc_op.LoGetAttr.With(
fld = fld,
)
@@ -193,16 +196,35 @@
if len(hltypes) != 4:
return
r_obj, r_attr, r_value, r_voidresult = hltypes
+ if not isinstance(r_attr, CConstant):
+ return
if isinstance(r_obj, CInstance):
# record the OP_SETATTR operation for this field
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)
+ sig = (r_obj, r_attr, fld.hltype, R_VOID)
yield sig, genc_op.LoSetAttr.With(
fld = fld,
+ llclass = r_obj.llclass,
)
+ def extend_OP_INITCLASSATTR(self, hltypes):
+ # only to initialize class attributes
+ if len(hltypes) != 4:
+ return
+ r_obj, r_attr, r_value, r_voidresult = hltypes
+ if isinstance(r_attr, CConstant) and isinstance(r_obj, CConstant):
+ cls = r_obj.value
+ if cls in self.genc.llclasses:
+ llclass = self.genc.llclasses[cls]
+ fld = llclass.get_class_field(r_attr.value)
+ if fld is not None:
+ sig = (r_obj, r_attr, fld.hltype, R_VOID)
+ yield sig, genc_op.LoInitClassAttr.With(
+ fld = fld,
+ llclass = llclass,
+ )
+
# ____________________________________________________________
def parse_operation_templates(self):
Modified: pypy/trunk/src/pypy/translator/test/snippet.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/snippet.py (original)
+++ pypy/trunk/src/pypy/translator/test/snippet.py Fri Sep 10 16:44:45 2004
@@ -319,6 +319,30 @@
def prime(n=int):
return len([i for i in range(1,n+1) if n%i==0]) == 2
+class A1:
+ clsattr = 123
+class A2(A1):
+ clsattr = 456
+class A3(A2):
+ clsattr = 789
+class A4(A3):
+ pass
+class A5(A1):
+ clsattr = 101112
+
+def classattribute(flag=int):
+ if flag == 1:
+ x = A1()
+ elif flag == 2:
+ x = A2()
+ elif flag == 3:
+ x = A3()
+ elif flag == 4:
+ x = A4()
+ else:
+ x = A5()
+ return x.clsattr
+
class Z:
def my_method(self):
Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original)
+++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Fri Sep 10 16:44:45 2004
@@ -151,5 +151,13 @@
fn = self.getcompiled(tuple_repr)
self.assertEquals(fn(6,'a'), (6,'a'))
+ def test_classattribute(self):
+ fn = self.getcompiled(snippet.classattribute)
+ self.assertEquals(fn(1), 123)
+ self.assertEquals(fn(2), 456)
+ self.assertEquals(fn(3), 789)
+ self.assertEquals(fn(4), 789)
+ self.assertEquals(fn(5), 101112)
+
if __name__ == '__main__':
testit.main()
More information about the Pypy-commit
mailing list