[pypy-commit] pypy ClassRepr: merge InstanceRepr and AbstractInstanceRepr
rlamy
noreply at buildbot.pypy.org
Mon Oct 13 01:38:35 CEST 2014
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: ClassRepr
Changeset: r73909:2fdb3fb0122b
Date: 2014-10-13 00:38 +0100
http://bitbucket.org/pypy/pypy/changeset/2fdb3fb0122b/
Log: merge InstanceRepr and AbstractInstanceRepr
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -441,14 +441,91 @@
return self.__class__,
-class AbstractInstanceRepr(Repr):
- def __init__(self, rtyper, classdef):
+class InstanceRepr(Repr):
+ def __init__(self, rtyper, classdef, gcflavor='gc'):
self.rtyper = rtyper
self.classdef = classdef
+ if classdef is None:
+ self.object_type = OBJECT_BY_FLAVOR[LLFLAVOR[gcflavor]]
+ else:
+ ForwardRef = lltype.FORWARDREF_BY_FLAVOR[LLFLAVOR[gcflavor]]
+ self.object_type = ForwardRef()
+ self.iprebuiltinstances = identity_dict()
+ self.lowleveltype = Ptr(self.object_type)
+ self.gcflavor = gcflavor
- def _setup_repr(self):
+ def _setup_repr(self, llfields=None, hints=None, adtmeths=None):
+ # NOTE: don't store mutable objects like the dicts below on 'self'
+ # before they are fully built, to avoid strange bugs in case
+ # of recursion where other code would uses these
+ # partially-initialized dicts.
if self.classdef is None:
self.immutable_field_set = set()
+ self.rclass = getclassrepr(self.rtyper, self.classdef)
+ fields = {}
+ allinstancefields = {}
+ if self.classdef is None:
+ fields['__class__'] = 'typeptr', get_type_repr(self.rtyper)
+ else:
+ # instance attributes
+ attrs = self.classdef.attrs.items()
+ attrs.sort()
+ myllfields = []
+ for name, attrdef in attrs:
+ if not attrdef.readonly:
+ r = self.rtyper.getrepr(attrdef.s_value)
+ mangled_name = 'inst_' + name
+ fields[name] = mangled_name, r
+ myllfields.append((mangled_name, r.lowleveltype))
+
+ # Sort the instance attributes by decreasing "likely size",
+ # as reported by rffi.sizeof(), to minimize padding holes in C.
+ # Fields of the same size are sorted by name (by attrs.sort()
+ # above) just to minimize randomness.
+ def keysize((_, T)):
+ if T is lltype.Void:
+ return None
+ from rpython.rtyper.lltypesystem.rffi import sizeof
+ try:
+ return -sizeof(T)
+ except StandardError:
+ return None
+ myllfields.sort(key=keysize)
+ if llfields is None:
+ llfields = myllfields
+ else:
+ llfields = llfields + myllfields
+
+ self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef,
+ self.gcflavor)
+ self.rbase.setup()
+
+ MkStruct = lltype.STRUCT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
+ if adtmeths is None:
+ adtmeths = {}
+ if hints is None:
+ hints = {}
+ hints = self._check_for_immutable_hints(hints)
+ 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,
+ adtmeths=adtmeths,
+ *llfields,
+ **kwds)
+ self.object_type.become(object_type)
+ allinstancefields.update(self.rbase.allinstancefields)
+ allinstancefields.update(fields)
+ self.fields = fields
+ self.allinstancefields = allinstancefields
+
def _check_for_immutable_hints(self, hints):
loc = self.classdef.classdesc.lookup('_immutable_')
@@ -492,6 +569,30 @@
def _setup_repr_final(self):
self._setup_immutable_field_list()
self._check_for_immutable_conflicts()
+ if self.gcflavor == 'gc':
+ if (self.classdef is not None and
+ self.classdef.classdesc.lookup('__del__') is not None):
+ s_func = self.classdef.classdesc.s_read_attribute('__del__')
+ source_desc = self.classdef.classdesc.lookup('__del__')
+ source_classdef = source_desc.getclassdef(None)
+ source_repr = getinstancerepr(self.rtyper, source_classdef)
+ assert len(s_func.descriptions) == 1
+ funcdesc, = s_func.descriptions
+ graph = funcdesc.getuniquegraph()
+ self.check_graph_of_del_does_not_call_too_much(graph)
+ FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
+ destrptr = functionptr(FUNCTYPE, graph.name,
+ graph=graph,
+ _callable=graph.func)
+ else:
+ destrptr = None
+ OBJECT = OBJECT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
+ self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
+ ll_runtime_type_info,
+ OBJECT, destrptr)
+ vtable = self.rclass.getvtable()
+ self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
+
def _setup_immutable_field_list(self):
hints = self.object_type._hints
@@ -577,7 +678,34 @@
return False
def new_instance(self, llops, classcallhop=None):
- raise NotImplementedError
+ """Build a new instance, without calling __init__."""
+ flavor = self.gcflavor
+ flags = {'flavor': flavor}
+ ctype = inputconst(Void, self.object_type)
+ cflags = inputconst(Void, flags)
+ vlist = [ctype, cflags]
+ vptr = llops.genop('malloc', vlist,
+ resulttype=Ptr(self.object_type))
+ ctypeptr = inputconst(CLASSTYPE, self.rclass.getvtable())
+ self.setfield(vptr, '__class__', ctypeptr, llops)
+ # initialize instance attributes from their defaults from the class
+ if self.classdef is not None:
+ flds = self.allinstancefields.keys()
+ flds.sort()
+ for fldname in flds:
+ if fldname == '__class__':
+ continue
+ mangled_name, r = self.allinstancefields[fldname]
+ if r.lowleveltype is Void:
+ continue
+ value = self.classdef.classdesc.read_attribute(fldname, None)
+ if value is not None:
+ cvalue = inputconst(r.lowleveltype,
+ r.convert_desc_or_const(value))
+ self.setfield(vptr, fldname, cvalue, llops,
+ flags={'access_directly': True})
+ return vptr
+
def convert_const(self, value):
if value is None:
@@ -634,16 +762,46 @@
get_ll_fasthash_function = get_ll_hash_function
def rtype_type(self, hop):
- raise NotImplementedError
+ if hop.s_result.is_constant():
+ return hop.inputconst(hop.r_result, hop.s_result.const)
+ instance_repr = self.common_repr()
+ vinst, = hop.inputargs(instance_repr)
+ if hop.args_s[0].can_be_none():
+ return hop.gendirectcall(ll_inst_type, vinst)
+ else:
+ return instance_repr.getfield(vinst, '__class__', hop.llops)
def rtype_getattr(self, hop):
- raise NotImplementedError
+ if hop.s_result.is_constant():
+ return hop.inputconst(hop.r_result, hop.s_result.const)
+ attr = hop.args_s[1].const
+ vinst, vattr = hop.inputargs(self, Void)
+ if attr == '__class__' and hop.r_result.lowleveltype is Void:
+ # special case for when the result of '.__class__' is a constant
+ [desc] = hop.s_result.descriptions
+ return hop.inputconst(Void, desc.pyobj)
+ if attr in self.allinstancefields:
+ return self.getfield(vinst, attr, hop.llops,
+ flags=hop.args_s[0].flags)
+ elif attr in self.rclass.allmethods:
+ # special case for methods: represented as their 'self' only
+ # (see MethodsPBCRepr)
+ return hop.r_result.get_method_from_instance(self, vinst,
+ hop.llops)
+ else:
+ vcls = self.getfield(vinst, '__class__', hop.llops)
+ return self.rclass.getclsfield(vcls, attr, hop.llops)
def rtype_setattr(self, hop):
- raise NotImplementedError
+ attr = hop.args_s[1].const
+ r_value = self.getfieldrepr(attr)
+ vinst, vattr, vvalue = hop.inputargs(self, Void, r_value)
+ self.setfield(vinst, attr, vvalue, hop.llops,
+ flags=hop.args_s[0].flags)
def rtype_bool(self, hop):
- raise NotImplementedError
+ vinst, = hop.inputargs(self)
+ return hop.genop('ptr_nonzero', [vinst], resulttype=Bool)
def _emulate_call(self, hop, meth_name):
vinst = hop.args_v[0]
@@ -679,8 +837,24 @@
def rtype_len(self, hop):
return self._emulate_call(hop, "__len__")
- def ll_str(self, i):
- raise NotImplementedError
+ def ll_str(self, i): # doesn't work for non-gc classes!
+ from rpython.rtyper.lltypesystem.ll_str import ll_int2hex
+ from rpython.rlib.rarithmetic import r_uint
+ if not i:
+ return rstr.null_str
+ instance = cast_pointer(OBJECTPTR, i)
+ # Two choices: the first gives a fast answer but it can change
+ # (typically only once) during the life of the object.
+ #uid = r_uint(cast_ptr_to_int(i))
+ uid = r_uint(llop.gc_id(lltype.Signed, i))
+ #
+ res = rstr.instance_str_prefix
+ res = rstr.ll_strconcat(res, instance.typeptr.name)
+ res = rstr.ll_strconcat(res, rstr.instance_str_infix)
+ res = rstr.ll_strconcat(res, ll_int2hex(uid, False))
+ res = rstr.ll_strconcat(res, rstr.instance_str_suffix)
+ return res
+
def get_ll_eq_function(self):
return None # defaults to compare by identity ('==' on pointers)
@@ -725,124 +899,6 @@
if len(seen) == oldlength:
break
-
-class __extend__(pairtype(AbstractInstanceRepr, Repr)):
- def rtype_getitem((r_ins, r_obj), hop):
- return r_ins._emulate_call(hop, "__getitem__")
-
- def rtype_setitem((r_ins, r_obj), hop):
- return r_ins._emulate_call(hop, "__setitem__")
-
-class InstanceRepr(AbstractInstanceRepr):
- def __init__(self, rtyper, classdef, gcflavor='gc'):
- AbstractInstanceRepr.__init__(self, rtyper, classdef)
- if classdef is None:
- self.object_type = OBJECT_BY_FLAVOR[LLFLAVOR[gcflavor]]
- else:
- ForwardRef = lltype.FORWARDREF_BY_FLAVOR[LLFLAVOR[gcflavor]]
- self.object_type = ForwardRef()
-
- self.iprebuiltinstances = identity_dict()
- self.lowleveltype = Ptr(self.object_type)
- self.gcflavor = gcflavor
-
- def _setup_repr(self, llfields=None, hints=None, adtmeths=None):
- # NOTE: don't store mutable objects like the dicts below on 'self'
- # 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 = {}
- if self.classdef is None:
- fields['__class__'] = 'typeptr', get_type_repr(self.rtyper)
- else:
- # instance attributes
- attrs = self.classdef.attrs.items()
- attrs.sort()
- myllfields = []
- for name, attrdef in attrs:
- if not attrdef.readonly:
- r = self.rtyper.getrepr(attrdef.s_value)
- mangled_name = 'inst_' + name
- fields[name] = mangled_name, r
- myllfields.append((mangled_name, r.lowleveltype))
-
- # Sort the instance attributes by decreasing "likely size",
- # as reported by rffi.sizeof(), to minimize padding holes in C.
- # Fields of the same size are sorted by name (by attrs.sort()
- # above) just to minimize randomness.
- def keysize((_, T)):
- if T is lltype.Void:
- return None
- from rpython.rtyper.lltypesystem.rffi import sizeof
- try:
- return -sizeof(T)
- except StandardError:
- return None
- myllfields.sort(key=keysize)
- if llfields is None:
- llfields = myllfields
- else:
- llfields = llfields + myllfields
-
- self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef,
- self.gcflavor)
- self.rbase.setup()
-
- MkStruct = lltype.STRUCT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
- if adtmeths is None:
- adtmeths = {}
- if hints is None:
- hints = {}
- hints = self._check_for_immutable_hints(hints)
- 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,
- adtmeths=adtmeths,
- *llfields,
- **kwds)
- self.object_type.become(object_type)
- allinstancefields.update(self.rbase.allinstancefields)
- allinstancefields.update(fields)
- self.fields = fields
- self.allinstancefields = allinstancefields
-
- def _setup_repr_final(self):
- AbstractInstanceRepr._setup_repr_final(self)
- if self.gcflavor == 'gc':
- if (self.classdef is not None and
- self.classdef.classdesc.lookup('__del__') is not None):
- s_func = self.classdef.classdesc.s_read_attribute('__del__')
- source_desc = self.classdef.classdesc.lookup('__del__')
- source_classdef = source_desc.getclassdef(None)
- source_repr = getinstancerepr(self.rtyper, source_classdef)
- assert len(s_func.descriptions) == 1
- funcdesc, = s_func.descriptions
- graph = funcdesc.getuniquegraph()
- self.check_graph_of_del_does_not_call_too_much(graph)
- FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
- destrptr = functionptr(FUNCTYPE, graph.name,
- graph=graph,
- _callable=graph.func)
- else:
- destrptr = None
- OBJECT = OBJECT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
- self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
- ll_runtime_type_info,
- OBJECT, destrptr)
- vtable = self.rclass.getvtable()
- self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
-
def common_repr(self): # -> object or nongcobject reprs
return getinstancerepr(self.rtyper, None, self.gcflavor)
@@ -935,95 +991,6 @@
self.rbase.setfield(vinst, attr, vvalue, llops, force_cast=True,
flags=flags)
- def new_instance(self, llops, classcallhop=None):
- """Build a new instance, without calling __init__."""
- flavor = self.gcflavor
- flags = {'flavor': flavor}
- ctype = inputconst(Void, self.object_type)
- cflags = inputconst(Void, flags)
- vlist = [ctype, cflags]
- vptr = llops.genop('malloc', vlist,
- resulttype=Ptr(self.object_type))
- ctypeptr = inputconst(CLASSTYPE, self.rclass.getvtable())
- self.setfield(vptr, '__class__', ctypeptr, llops)
- # initialize instance attributes from their defaults from the class
- if self.classdef is not None:
- flds = self.allinstancefields.keys()
- flds.sort()
- for fldname in flds:
- if fldname == '__class__':
- continue
- mangled_name, r = self.allinstancefields[fldname]
- if r.lowleveltype is Void:
- continue
- value = self.classdef.classdesc.read_attribute(fldname, None)
- if value is not None:
- cvalue = inputconst(r.lowleveltype,
- r.convert_desc_or_const(value))
- self.setfield(vptr, fldname, cvalue, llops,
- flags={'access_directly': True})
- return vptr
-
- def rtype_type(self, hop):
- if hop.s_result.is_constant():
- return hop.inputconst(hop.r_result, hop.s_result.const)
- instance_repr = self.common_repr()
- vinst, = hop.inputargs(instance_repr)
- if hop.args_s[0].can_be_none():
- return hop.gendirectcall(ll_inst_type, vinst)
- else:
- return instance_repr.getfield(vinst, '__class__', hop.llops)
-
- def rtype_getattr(self, hop):
- if hop.s_result.is_constant():
- return hop.inputconst(hop.r_result, hop.s_result.const)
- attr = hop.args_s[1].const
- vinst, vattr = hop.inputargs(self, Void)
- if attr == '__class__' and hop.r_result.lowleveltype is Void:
- # special case for when the result of '.__class__' is a constant
- [desc] = hop.s_result.descriptions
- return hop.inputconst(Void, desc.pyobj)
- if attr in self.allinstancefields:
- return self.getfield(vinst, attr, hop.llops,
- flags=hop.args_s[0].flags)
- elif attr in self.rclass.allmethods:
- # special case for methods: represented as their 'self' only
- # (see MethodsPBCRepr)
- return hop.r_result.get_method_from_instance(self, vinst,
- hop.llops)
- else:
- vcls = self.getfield(vinst, '__class__', hop.llops)
- return self.rclass.getclsfield(vcls, attr, hop.llops)
-
- def rtype_setattr(self, hop):
- attr = hop.args_s[1].const
- r_value = self.getfieldrepr(attr)
- vinst, vattr, vvalue = hop.inputargs(self, Void, r_value)
- self.setfield(vinst, attr, vvalue, hop.llops,
- flags=hop.args_s[0].flags)
-
- def rtype_bool(self, hop):
- vinst, = hop.inputargs(self)
- return hop.genop('ptr_nonzero', [vinst], resulttype=Bool)
-
- def ll_str(self, i): # doesn't work for non-gc classes!
- from rpython.rtyper.lltypesystem.ll_str import ll_int2hex
- from rpython.rlib.rarithmetic import r_uint
- if not i:
- return rstr.null_str
- instance = cast_pointer(OBJECTPTR, i)
- # Two choices: the first gives a fast answer but it can change
- # (typically only once) during the life of the object.
- #uid = r_uint(cast_ptr_to_int(i))
- uid = r_uint(llop.gc_id(lltype.Signed, i))
- #
- res = rstr.instance_str_prefix
- res = rstr.ll_strconcat(res, instance.typeptr.name)
- res = rstr.ll_strconcat(res, rstr.instance_str_infix)
- res = rstr.ll_strconcat(res, ll_int2hex(uid, False))
- res = rstr.ll_strconcat(res, rstr.instance_str_suffix)
- return res
-
def rtype_isinstance(self, hop):
class_repr = get_type_repr(hop.rtyper)
instance_repr = self.common_repr()
@@ -1043,6 +1010,14 @@
return hop.gendirectcall(ll_isinstance, v_obj, v_cls)
+class __extend__(pairtype(InstanceRepr, Repr)):
+ def rtype_getitem((r_ins, r_obj), hop):
+ return r_ins._emulate_call(hop, "__getitem__")
+
+ def rtype_setitem((r_ins, r_obj), hop):
+ return r_ins._emulate_call(hop, "__setitem__")
+
+
class __extend__(pairtype(InstanceRepr, InstanceRepr)):
def convert_from_to((r_ins1, r_ins2), v, llops):
# which is a subclass of which?
diff --git a/rpython/rtyper/rmodel.py b/rpython/rtyper/rmodel.py
--- a/rpython/rtyper/rmodel.py
+++ b/rpython/rtyper/rmodel.py
@@ -380,7 +380,7 @@
def externalvsinternal(rtyper, item_repr): # -> external_item_repr, (internal_)item_repr
from rpython.rtyper import rclass
- if (isinstance(item_repr, rclass.AbstractInstanceRepr) and
+ if (isinstance(item_repr, rclass.InstanceRepr) and
getattr(item_repr, 'gcflavor', 'gc') == 'gc'):
return item_repr, rclass.getinstancerepr(rtyper, None)
else:
More information about the pypy-commit
mailing list