def __init__(self, rtyper, classdef): AbstractClassRepr.__init__(self, rtyper, classdef) # This is the Repr for a reference to the class 'classdef' or # any subclass. In the simple case, the lowleveltype is just # ootype.Class. If we need to store class attributes, we use a # "meta" class where the attributes are defined, and the class # reference is a reference to an instance of this meta class. extra_access_sets = self.rtyper.class_pbc_attributes.get(classdef, {}) has_class_attributes = bool(extra_access_sets) if self.classdef is not None: self.rbase = getclassrepr(self.rtyper, self.classdef.basedef) meta_base_type = self.rbase.lowleveltype baseclass_has_meta = meta_base_type != ootype.Class else: baseclass_has_meta = False if not has_class_attributes and not baseclass_has_meta: self.lowleveltype = ootype.Class # simple case else: if self.classdef is None: raise TyperError("the root 'object' class should not have" " class attributes") if self.classdef.classdesc.pyobj in standardexceptions: raise TyperError("Standard exception class %r should not have" " class attributes" % (self.classdef.name, )) if not baseclass_has_meta: meta_base_type = META self.lowleveltype = ootype.Instance(self.classdef.name + "_meta", meta_base_type)
def _setup_repr(self): InstanceRepr._setup_repr(self) flds = self.allinstancefields.keys() flds.remove('__class__') if self.is_parent: if flds: raise TyperError("%r is a base class of an UnboxedValue," "so it cannot have fields: %r" % (self.classdef, flds)) else: if len(flds) != 1: raise TyperError("%r must have exactly one field: %r" % (self.classdef, flds)) self.specialfieldname = flds[0]
def getpbcfield(self, vcls, access_set, attr, llops): if (access_set, attr) not in self.pbcfields: raise TyperError("internal error: missing PBC field") mangled_name, r = self.pbcfields[access_set, attr] v_meta = self.fromclasstype(vcls, llops) cname = inputconst(ootype.Void, mangled_name) return llops.genop('oogetfield', [v_meta, cname], resulttype=r)
def rtype_getattr(self, hop): v_inst, _ = hop.inputargs(self, ootype.Void) s_inst = hop.args_s[0] attr = hop.args_s[1].const mangled = mangle(attr, self.rtyper.getconfig()) v_attr = hop.inputconst(ootype.Void, mangled) if mangled in self.allfields: # regular instance attributes self.lowleveltype._check_field(mangled) return hop.genop("oogetfield", [v_inst, v_attr], resulttype=hop.r_result.lowleveltype) elif mangled in self.allmethods: # special case for methods: represented as their 'self' only # (see MethodsPBCRepr) return hop.r_result.get_method_from_instance( self, v_inst, hop.llops) elif mangled in self.allclassattributes: # class attributes if hop.s_result.is_constant(): return hop.inputconst(hop.r_result, hop.s_result.const) else: cname = hop.inputconst(ootype.Void, mangled) return hop.genop("oosend", [cname, v_inst], resulttype=hop.r_result.lowleveltype) elif attr == '__class__': if hop.r_result.lowleveltype is ootype.Void: # special case for when the result of '.__class__' is constant [desc] = hop.s_result.descriptions return hop.inputconst(ootype.Void, desc.pyobj) else: cmeta = inputconst(ootype.Void, "meta") return hop.genop('oogetfield', [v_inst, cmeta], resulttype=CLASSTYPE) else: raise TyperError("no attribute %r on %r" % (attr, self))
def rtype_builtin_hasattr(hop): if hop.s_result.is_constant(): return hop.inputconst(lltype.Bool, hop.s_result.const) if hop.args_r[0] == pyobj_repr: v_obj, v_name = hop.inputargs(pyobj_repr, pyobj_repr) c = hop.inputconst(pyobj_repr, hasattr) v = hop.genop('simple_call', [c, v_obj, v_name], resulttype = pyobj_repr) return hop.llops.convertvar(v, pyobj_repr, bool_repr) raise TyperError("hasattr is only suported on a constant or on PyObject")
def new_instance(self, llops, classcallhop=None): if self.is_parent: raise TyperError("don't instantiate %r, it is a parent of an " "UnboxedValue class" % (self.classdef, )) if classcallhop is None: raise TyperError("must instantiate %r by calling the class" % (self.classdef, )) hop = classcallhop if not (hop.spaceop.opname == 'simple_call' and hop.nb_args == 2): raise TyperError("must instantiate %r with a simple class call" % (self.classdef, )) v_value = hop.inputarg(lltype.Signed, arg=1) c_one = hop.inputconst(lltype.Signed, 1) hop.exception_is_here() v2 = hop.genop('int_lshift_ovf', [v_value, c_one], resulttype=lltype.Signed) v2p1 = hop.genop('int_add', [v2, c_one], resulttype=lltype.Signed) v_instance = hop.genop('cast_int_to_ptr', [v2p1], resulttype=self.lowleveltype) return v_instance, False # don't call __init__
def get_meta_instance(self, cast_to_root_meta=True): if self.lowleveltype == ootype.Class: raise TyperError("no meta-instance for class %r" % (self.classdef, )) if self.meta_instance is None: self.meta_instance = ootype.new(self.lowleveltype) self.setup_meta_instance(self.meta_instance, self) meta_instance = self.meta_instance if cast_to_root_meta: meta_instance = ootype.ooupcast(META, meta_instance) return meta_instance
def rtype_isinstance(self, hop): if not hop.args_s[1].is_constant(): raise TyperError("isinstance() too complicated") [classdesc] = hop.args_s[1].descriptions classdef = classdesc.getuniqueclassdef() class_repr = get_type_repr(self.rtyper) instance_repr = self.common_repr() v_obj, v_cls = hop.inputargs(instance_repr, class_repr) cls = v_cls.value answer = self.unboxedclassdef.issubclass(classdef) c_answer_if_unboxed = hop.inputconst(lltype.Bool, answer) minid = hop.inputconst(lltype.Signed, cls.subclassrange_min) maxid = hop.inputconst(lltype.Signed, cls.subclassrange_max) return hop.gendirectcall(ll_unboxed_isinstance_const, v_obj, minid, maxid, c_answer_if_unboxed)
def rtype_getattr(self, hop): if hop.s_result.is_constant(): return hop.inputconst(hop.r_result, hop.s_result.const) v_inst, _ = hop.inputargs(self, ootype.Void) s_inst = hop.args_s[0] attr = hop.args_s[1].const mangled = mangle(attr, self.rtyper.getconfig()) if mangled in self.allfields: # regular instance attributes return self.getfield(v_inst, attr, hop.llops, flags=hop.args_s[0].flags) elif mangled in self.allmethods: # special case for methods: represented as their 'self' only # (see MethodsPBCRepr) return hop.r_result.get_method_from_instance( self, v_inst, hop.llops) elif mangled in self.allclassattributes: # class attributes if hop.s_result.is_constant(): return hop.inputconst(hop.r_result, hop.s_result.const) else: cname = hop.inputconst(ootype.Void, mangled) return hop.genop("oosend", [cname, v_inst], resulttype=hop.r_result.lowleveltype) elif attr == '__class__': expected_type = hop.r_result.lowleveltype if expected_type is ootype.Void: # special case for when the result of '.__class__' is constant [desc] = hop.s_result.descriptions return hop.inputconst(ootype.Void, desc.pyobj) elif expected_type == ootype.Class: return hop.genop('classof', [v_inst], resulttype=ootype.Class) else: assert expected_type == META _, meth = v_inst.concretetype._lookup('getmeta') assert meth c_getmeta = hop.inputconst(ootype.Void, 'getmeta') return hop.genop('oosend', [c_getmeta, v_inst], resulttype=META) else: raise TyperError("no attribute %r on %r" % (attr, self))
def rtype_builtin_isinstance(hop): if hop.s_result.is_constant(): return hop.inputconst(lltype.Bool, hop.s_result.const) if hop.args_r[0] == pyobj_repr or hop.args_r[1] == pyobj_repr: v_obj, v_typ = hop.inputargs(pyobj_repr, pyobj_repr) c = hop.inputconst(pyobj_repr, isinstance) v = hop.genop('simple_call', [c, v_obj, v_typ], resulttype = pyobj_repr) return hop.llops.convertvar(v, pyobj_repr, bool_repr) if hop.args_s[1].is_constant() and hop.args_s[1].const == list: if hop.args_s[0].knowntype != list: raise TyperError("isinstance(x, list) expects x to be known statically to be a list or None") rlist = hop.args_r[0] vlist = hop.inputarg(rlist, arg=0) cnone = hop.inputconst(rlist, None) return hop.genop('ptr_ne', [vlist, cnone], resulttype=lltype.Bool) assert isinstance(hop.args_r[0], rclass.InstanceRepr) return hop.args_r[0].rtype_isinstance(hop)
def rtype_is_None(robj1, rnone2, hop, pos=0): if isinstance(robj1.lowleveltype, Ptr): v1 = hop.inputarg(robj1, pos) return hop.genop('ptr_iszero', [v1], resulttype=Bool) elif robj1.lowleveltype == llmemory.Address: v1 = hop.inputarg(robj1, pos) cnull = hop.inputconst(llmemory.Address, robj1.null_instance()) return hop.genop('adr_eq', [v1, cnull], resulttype=Bool) elif robj1 == none_frozen_pbc_repr: return hop.inputconst(Bool, True) elif isinstance(robj1, SmallFunctionSetPBCRepr): if robj1.s_pbc.can_be_None: v1 = hop.inputarg(robj1, pos) return hop.genop('char_eq', [v1, inputconst(Char, '\000')], resulttype=Bool) else: return inputconst(Bool, False) else: raise TyperError('rtype_is_None of %r' % (robj1))
def _setup_repr(self, llfields=None, hints=None): if hints: self.lowleveltype._hints.update(hints) if self.classdef is None: self.fields = {} self.allfields = {} self.allmethods = {} self.allclassattributes = {} self.classattributes = {} return if self.baserepr is not None: allfields = self.baserepr.allfields.copy() allmethods = self.baserepr.allmethods.copy() allclassattributes = self.baserepr.allclassattributes.copy() else: allfields = {} allmethods = {} allclassattributes = {} fields = {} nonmangledfields = [] fielddefaults = {} if llfields: fields.update(dict(llfields)) selfattrs = self.classdef.attrs for name, attrdef in selfattrs.iteritems(): mangled = mangle(name, self.rtyper.getconfig()) if not attrdef.readonly: repr = self.rtyper.getrepr(attrdef.s_value) allfields[mangled] = repr oot = repr.lowleveltype fields[mangled] = oot nonmangledfields.append(name) try: value = self.classdef.classdesc.read_attribute(name) fielddefaults[mangled] = repr.convert_desc_or_const(value) except AttributeError: pass else: s_value = attrdef.s_value if isinstance(s_value, annmodel.SomePBC): if len(s_value.descriptions) > 0 and s_value.getKind( ) == description.MethodDesc: # attrdef is for a method if mangled in allclassattributes: raise TyperError( "method overrides class attribute") allmethods[ mangled] = name, self.classdef.lookup_filter( s_value) continue # class attribute if mangled in allmethods: raise TyperError("class attribute overrides method") allclassattributes[mangled] = name, s_value special_methods = ["__init__", "__del__"] for meth_name in special_methods: if meth_name not in selfattrs and \ self.classdef.classdesc.find_source_for(meth_name) is not None: s_meth = self.classdef.classdesc.s_get_value( self.classdef, meth_name) if isinstance(s_meth, annmodel.SomePBC): mangled = mangle(meth_name, self.rtyper.getconfig()) allmethods[mangled] = meth_name, s_meth # else: it's the __init__ of a builtin exception ootype.addFields(self.lowleveltype, fields) 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): name = mangle('mutable_' + name, self.rtyper.getconfig()) ootype.addFields(self.lowleveltype, {name: OBJECT}) classattributes = {} baseInstance = self.lowleveltype._superclass classrepr = getclassrepr(self.rtyper, self.classdef) # if this class has a corresponding metaclass, attach # a getmeta() method to get the corresponding meta_instance if classrepr.lowleveltype != ootype.Class: oovalue = classrepr.get_meta_instance() self.attach_class_attr_accessor('getmeta', oovalue) for classdef in self.classdef.getmro(): for name, attrdef in classdef.attrs.iteritems(): if not attrdef.readonly: continue mangled = mangle(name, self.rtyper.getconfig()) if mangled in allclassattributes: selfdesc = self.classdef.classdesc if name not in selfattrs: # if the attr was already found in a parent class, # we register it again only if it is overridden. if selfdesc.find_source_for(name) is None: continue value = selfdesc.read_attribute(name) else: # otherwise, for new attrs, we look in all parent # classes to see if it's defined in a parent but only # actually first used in self.classdef. value = selfdesc.read_attribute(name, None) # a non-method class attribute if not attrdef.s_value.is_constant(): classattributes[mangled] = attrdef.s_value, value self.fields = nonmangledfields self.allfields = allfields self.allmethods = allmethods self.allclassattributes = allclassattributes self.classattributes = classattributes # the following is done after the rest of the initialization because # convert_const can require 'self' to be fully initialized. # step 2: provide default values for fields for mangled, impl in fielddefaults.items(): oot = fields[mangled] ootype.addFields(self.lowleveltype, {mangled: (oot, impl)}, with_default=True)
def _setup_repr(self): if self.classdef is None: self.allfields = {} self.allmethods = {} self.allclassattributes = {} self.classattributes = {} return if self.baserepr is not None: allfields = self.baserepr.allfields.copy() allmethods = self.baserepr.allmethods.copy() allclassattributes = self.baserepr.allclassattributes.copy() else: allfields = {} allmethods = {} allclassattributes = {} fields = {} fielddefaults = {} selfattrs = self.classdef.attrs for name, attrdef in selfattrs.iteritems(): mangled = mangle(name, self.rtyper.getconfig()) if not attrdef.readonly: repr = self.rtyper.getrepr(attrdef.s_value) allfields[mangled] = repr oot = repr.lowleveltype fields[mangled] = oot try: value = self.classdef.classdesc.read_attribute(name) fielddefaults[mangled] = repr.convert_desc_or_const(value) except AttributeError: pass else: s_value = attrdef.s_value if isinstance(s_value, annmodel.SomePBC): if len(s_value.descriptions) > 0 and s_value.getKind( ) == description.MethodDesc: # attrdef is for a method if mangled in allclassattributes: raise TyperError( "method overrides class attribute") allmethods[ mangled] = name, self.classdef.lookup_filter( s_value) continue # class attribute if mangled in allmethods: raise TyperError("class attribute overrides method") allclassattributes[mangled] = name, s_value special_methods = ["__init__", "__del__"] for meth_name in special_methods: if meth_name not in selfattrs and \ self.classdef.classdesc.find_source_for(meth_name) is not None: s_meth = self.classdef.classdesc.s_get_value( self.classdef, meth_name) if isinstance(s_meth, annmodel.SomePBC): mangled = mangle(meth_name, self.rtyper.getconfig()) allmethods[mangled] = meth_name, s_meth # else: it's the __init__ of a builtin exception # # hash() support if self.rtyper.needs_hash_support(self.classdef): from pypy.rpython import rint allfields['_hash_cache_'] = rint.signed_repr fields['_hash_cache_'] = ootype.Signed ootype.addFields(self.lowleveltype, fields) self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef) self.rbase.setup() methods = {} classattributes = {} baseInstance = self.lowleveltype._superclass classrepr = getclassrepr(self.rtyper, self.classdef) for mangled, (name, s_value) in allmethods.iteritems(): methdescs = s_value.descriptions origin = dict([(methdesc.originclassdef, methdesc) for methdesc in methdescs]) if self.classdef in origin: methdesc = origin[self.classdef] else: if name in selfattrs: for superdef in self.classdef.getmro(): if superdef in origin: # put in methods methdesc = origin[superdef] break else: # abstract method methdesc = None else: continue # get method implementation from pypy.rpython.ootypesystem.rpbc import MethodImplementations methimpls = MethodImplementations.get(self.rtyper, s_value) m_impls = methimpls.get_impl(mangled, methdesc, is_finalizer=name == "__del__") methods.update(m_impls) for classdef in self.classdef.getmro(): for name, attrdef in classdef.attrs.iteritems(): if not attrdef.readonly: continue mangled = mangle(name, self.rtyper.getconfig()) if mangled in allclassattributes: selfdesc = self.classdef.classdesc if name not in selfattrs: # if the attr was already found in a parent class, # we register it again only if it is overridden. if selfdesc.find_source_for(name) is None: continue value = selfdesc.read_attribute(name) else: # otherwise, for new attrs, we look in all parent # classes to see if it's defined in a parent but only # actually first used in self.classdef. value = selfdesc.read_attribute(name, None) # a non-method class attribute if not attrdef.s_value.is_constant(): classattributes[mangled] = attrdef.s_value, value ootype.addMethods(self.lowleveltype, methods) self.allfields = allfields self.allmethods = allmethods self.allclassattributes = allclassattributes self.classattributes = classattributes # the following is done after the rest of the initialization because # convert_const can require 'self' to be fully initialized. # step 2: provide default values for fields for mangled, impl in fielddefaults.items(): oot = fields[mangled] ootype.addFields(self.lowleveltype, {mangled: (oot, impl)})