def get_ll_pyobjectptr(self, rtyper): from pypy.rpython.rclass import getinstancerepr emulated_cls = self.instance rpython_cls = emulated_cls._rpython_class_ classdef = rtyper.annotator.bookkeeper.getuniqueclassdef(rpython_cls) r_inst = getinstancerepr(rtyper, classdef) return build_pytypeobject(r_inst)
def externalvsinternal(rtyper, item_repr): # -> external_item_repr, (internal_)item_repr from pypy.rpython import rclass if (isinstance(item_repr, rclass.AbstractInstanceRepr) and getattr(item_repr, 'gcflavor', 'gc') == 'gc'): return item_repr, rclass.getinstancerepr(rtyper, None) else: return item_repr, item_repr
def setup_meta_instance(self, meta_instance, rsubcls): if self.classdef is None: rinstance = getinstancerepr(self.rtyper, rsubcls.classdef) meta_instance.class_ = ootype.runtimeClass(rinstance.lowleveltype) else: # setup class attributes: for each attribute name at the level # of 'self', look up its value in the subclass rsubcls def assign(mangled_name, value): if isinstance(value, flowmodel.Constant) and isinstance(value.value, staticmethod): value = flowmodel.Constant(value.value.__get__(42)) # staticmethod => bare function llvalue = r.convert_desc_or_const(value) setattr(meta_instance, mangled_name, llvalue) # extra PBC attributes for (access_set, attr), (mangled_name, r) in self.pbcfields.items(): if rsubcls.classdef.classdesc not in access_set.descs: continue # only for the classes in the same pbc access set if r.lowleveltype is ootype.Void: continue attrvalue = rsubcls.classdef.classdesc.read_attribute(attr, None) if attrvalue is not None: assign(mangled_name, attrvalue) # then initialize the 'super' portion of the vtable self.rbase.setup_meta_instance(meta_instance, rsubcls)
def __init__(self, rtyper, classdef, gcflavor='ignored'): AbstractInstanceRepr.__init__(self, rtyper, classdef) self.baserepr = None if self.classdef is None: self.lowleveltype = OBJECT else: b = self.classdef.basedef if b is not None: self.baserepr = getinstancerepr(rtyper, b) b = self.baserepr.lowleveltype else: b = OBJECT if hasattr(classdef.classdesc.pyobj, '_rpython_hints'): hints = classdef.classdesc.pyobj._rpython_hints else: hints = {} hints = self._check_for_immutable_hints(hints) self.lowleveltype = ootype.Instance(classdef.name, b, {}, {}, _hints=hints) self.iprebuiltinstances = identity_dict() self.object_type = self.lowleveltype self.gcflavor = gcflavor
def setup_vtable(self, vtable, rsubcls): """Initialize the 'self' portion of the 'vtable' belonging to the given subclass.""" if self.classdef is None: # initialize the 'subclassrange_*' and 'name' fields if rsubcls.classdef is not None: #vtable.parenttypeptr = rsubcls.rbase.getvtable() vtable.subclassrange_min = rsubcls.classdef.minid vtable.subclassrange_max = rsubcls.classdef.maxid else: #for the root class vtable.subclassrange_min = 0 vtable.subclassrange_max = sys.maxint rinstance = getinstancerepr(self.rtyper, rsubcls.classdef) rinstance.setup() if rinstance.gcflavor == 'gc': vtable.rtti = getRuntimeTypeInfo(rinstance.object_type) if rsubcls.classdef is None: name = 'object' else: name = rsubcls.classdef.shortname vtable.name = alloc_array_name(name) if hasattr(rsubcls.classdef, 'my_instantiate_graph'): graph = rsubcls.classdef.my_instantiate_graph vtable.instantiate = self.rtyper.getcallable(graph) #else: the classdef was created recently, so no instantiate() # could reach it else: # setup class attributes: for each attribute name at the level # of 'self', look up its value in the subclass rsubcls def assign(mangled_name, value): if isinstance(value, Constant) and isinstance( value.value, staticmethod): value = Constant(value.value.__get__( 42)) # staticmethod => bare function llvalue = r.convert_desc_or_const(value) setattr(vtable, mangled_name, llvalue) mro = list(rsubcls.classdef.getmro()) for fldname in self.clsfields: mangled_name, r = self.clsfields[fldname] if r.lowleveltype is Void: continue value = rsubcls.classdef.classdesc.read_attribute( fldname, None) if value is not None: assign(mangled_name, value) # extra PBC attributes for (access_set, attr), (mangled_name, r) in self.pbcfields.items(): if rsubcls.classdef.classdesc not in access_set.descs: continue # only for the classes in the same pbc access set if r.lowleveltype is Void: continue attrvalue = rsubcls.classdef.classdesc.read_attribute( attr, None) if attrvalue is not None: assign(mangled_name, attrvalue) # then initialize the 'super' portion of the vtable self.rbase.setup_vtable(vtable.super, rsubcls)
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 __init__(self, rtyper, s_pbc): self.rtyper = rtyper self.s_pbc = s_pbc if s_pbc.isNone(): raise TyperError("unsupported: variable of type " "bound-method-object or None") mdescs = s_pbc.descriptions.keys() methodname = mdescs[0].name classdef = mdescs[0].selfclassdef flags = mdescs[0].flags for mdesc in mdescs[1:]: if mdesc.name != methodname: raise TyperError("cannot find a unique name under which the " "methods can be found: %r" % ( mdescs,)) if mdesc.flags != flags: raise TyperError("inconsistent 'flags': %r versus %r" % ( mdesc.flags, flags)) classdef = classdef.commonbase(mdesc.selfclassdef) if classdef is None: raise TyperError("mixing methods coming from instances of " "classes with no common base: %r" % (mdescs,)) self.methodname = methodname self.classdef = classdef.locate_attribute(methodname) # the low-level representation is just the bound 'self' argument. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags) self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef) self.lowleveltype = self.r_im_self.lowleveltype
def __init__(self, rtyper, s_pbc): self.rtyper = rtyper self.s_pbc = s_pbc if s_pbc.isNone(): raise TyperError("unsupported: variable of type " "bound-method-object or None") mdescs = s_pbc.descriptions.keys() methodname = mdescs[0].name classdef = mdescs[0].selfclassdef flags = mdescs[0].flags for mdesc in mdescs[1:]: if mdesc.name != methodname: raise TyperError("cannot find a unique name under which the " "methods can be found: %r" % (mdescs, )) if mdesc.flags != flags: raise TyperError("inconsistent 'flags': %r versus %r" % (mdesc.flags, flags)) classdef = classdef.commonbase(mdesc.selfclassdef) if classdef is None: raise TyperError("mixing methods coming from instances of " "classes with no common base: %r" % (mdescs, )) self.methodname = methodname self.classdef = classdef.locate_attribute(methodname) # the low-level representation is just the bound 'self' argument. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags) self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef) self.lowleveltype = self.r_im_self.lowleveltype
def gettype_from_unboxed(self, llops, vinst): unboxedclass_repr = getclassrepr(self.rtyper, self.unboxedclassdef) cunboxedcls = inputconst(CLASSTYPE, unboxedclass_repr.getvtable()) if self.is_parent: # If the lltype of vinst shows that it cannot be a tagged value, # we can directly read the typeptr. Otherwise, call a helper that # checks if the tag bit is set in the pointer. unboxedinstance_repr = getinstancerepr(self.rtyper, self.unboxedclassdef) try: lltype.castable(unboxedinstance_repr.lowleveltype, vinst.concretetype) except lltype.InvalidCast: can_be_tagged = False else: can_be_tagged = True vinst = llops.genop('cast_pointer', [vinst], resulttype=self.common_repr()) if can_be_tagged: return llops.gendirectcall(ll_unboxed_getclass, vinst, cunboxedcls) else: ctypeptr = inputconst(lltype.Void, 'typeptr') return llops.genop('getfield', [vinst, ctypeptr], resulttype=CLASSTYPE) else: return cunboxedcls
def gettype_from_unboxed(self, llops, vinst, can_be_none=False): unboxedclass_repr = getclassrepr(self.rtyper, self.unboxedclassdef) cunboxedcls = inputconst(CLASSTYPE, unboxedclass_repr.getvtable()) if self.is_parent: # If the lltype of vinst shows that it cannot be a tagged value, # we can directly read the typeptr. Otherwise, call a helper that # checks if the tag bit is set in the pointer. unboxedinstance_repr = getinstancerepr(self.rtyper, self.unboxedclassdef) try: lltype.castable(unboxedinstance_repr.lowleveltype, vinst.concretetype) except lltype.InvalidCast: can_be_tagged = False else: can_be_tagged = True vinst = llops.genop('cast_pointer', [vinst], resulttype=self.common_repr()) if can_be_tagged: if can_be_none: func = ll_unboxed_getclass_canbenone else: func = ll_unboxed_getclass return llops.gendirectcall(func, vinst, cunboxedcls) elif can_be_none: return llops.gendirectcall(ll_inst_type, vinst) else: ctypeptr = inputconst(lltype.Void, 'typeptr') return llops.genop('getfield', [vinst, ctypeptr], resulttype = CLASSTYPE) else: return cunboxedcls
def setup_meta_instance(self, meta_instance, rsubcls): if self.classdef is None: rinstance = getinstancerepr(self.rtyper, rsubcls.classdef) meta_instance.class_ = ootype.runtimeClass(rinstance.lowleveltype) else: # setup class attributes: for each attribute name at the level # of 'self', look up its value in the subclass rsubcls def assign(mangled_name, value): if isinstance(value, flowmodel.Constant) and isinstance( value.value, staticmethod): value = flowmodel.Constant(value.value.__get__( 42)) # staticmethod => bare function llvalue = r.convert_desc_or_const(value) setattr(meta_instance, mangled_name, llvalue) # extra PBC attributes for (access_set, attr), (mangled_name, r) in self.pbcfields.items(): if rsubcls.classdef.classdesc not in access_set.descs: continue # only for the classes in the same pbc access set if r.lowleveltype is ootype.Void: continue attrvalue = rsubcls.classdef.classdesc.read_attribute( attr, None) if attrvalue is not None: assign(mangled_name, attrvalue) # then initialize the 'super' portion of the vtable self.rbase.setup_meta_instance(meta_instance, rsubcls)
def getruntime(self, expected_type): if expected_type == ootype.Class: rinstance = getinstancerepr(self.rtyper, self.classdef) return ootype.runtimeClass(rinstance.lowleveltype) else: assert ootype.isSubclass(expected_type, META) meta = self.get_meta_instance(cast_to_root_meta=False) return ootype.ooupcast(expected_type, meta)
def rtype_method_get(self, hop): r_object = getinstancerepr(self.rtyper, None) v_d, v_key = hop.inputargs(self, r_object) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_get, v_d, v_key) v_result = hop.genop("cast_pointer", [v_result], resulttype=hop.r_result.lowleveltype) return v_result
def rtype_method_set(self, hop): r_object = getinstancerepr(self.rtyper, None) v_d, v_key, v_value = hop.inputargs(self, r_object, r_object) hop.exception_cannot_occur() if hop.args_s[2].is_constant() and hop.args_s[2].const is None: hop.gendirectcall(ll_set_null, v_d, v_key) else: hop.gendirectcall(ll_set, v_d, v_key, v_value)
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. 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 if llfields is None: llfields = [] attrs = self.classdef.attrs.items() attrs.sort() 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 llfields.append((mangled_name, r.lowleveltype)) # # hash() support if self.rtyper.needs_hash_support(self.classdef): from pypy.rpython import rint fields['_hash_cache_'] = 'hash_cache', rint.signed_repr llfields.append(('hash_cache', Signed)) self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef, self.gcflavor) self.rbase.setup() # # PyObject wrapper support if self.has_wrapper and '_wrapper_' not in self.rbase.allinstancefields: fields['_wrapper_'] = 'wrapper', pyobj_repr llfields.append(('wrapper', Ptr(PyObject))) MkStruct = lltype.STRUCT_BY_FLAVOR[LLFLAVOR[self.gcflavor]] if adtmeths is None: adtmeths = {} if hints is None: hints = {} if '_immutable_' in self.classdef.classdesc.classdict: hints = hints.copy() hints['immutable'] = True object_type = MkStruct(self.classdef.name, ('super', self.rbase.object_type), hints=hints, adtmeths=adtmeths, *llfields) self.object_type.become(object_type) allinstancefields.update(self.rbase.allinstancefields) allinstancefields.update(fields) self.fields = fields self.allinstancefields = allinstancefields if self.gcflavor in RTTIFLAVORS: attachRuntimeTypeInfo(self.object_type)
def setup_vtable(self, vtable, rsubcls): """Initialize the 'self' portion of the 'vtable' belonging to the given subclass.""" if self.classdef is None: # initialize the 'subclassrange_*' and 'name' fields if rsubcls.classdef is not None: #vtable.parenttypeptr = rsubcls.rbase.getvtable() vtable.subclassrange_min = rsubcls.classdef.minid vtable.subclassrange_max = rsubcls.classdef.maxid else: #for the root class vtable.subclassrange_min = 0 vtable.subclassrange_max = sys.maxint rinstance = getinstancerepr(self.rtyper, rsubcls.classdef) rinstance.setup() if rinstance.gcflavor in RTTIFLAVORS: vtable.rtti = getRuntimeTypeInfo(rinstance.object_type) if rsubcls.classdef is None: name = 'object' else: name = rsubcls.classdef.shortname vtable.name = malloc(Array(Char), len(name)+1, immortal=True) for i in range(len(name)): vtable.name[i] = name[i] vtable.name[len(name)] = '\x00' if hasattr(rsubcls.classdef, 'my_instantiate_graph'): graph = rsubcls.classdef.my_instantiate_graph vtable.instantiate = self.rtyper.getcallable(graph) #else: the classdef was created recently, so no instantiate() # could reach it else: # setup class attributes: for each attribute name at the level # of 'self', look up its value in the subclass rsubcls def assign(mangled_name, value): if isinstance(value, Constant) and isinstance(value.value, staticmethod): value = Constant(value.value.__get__(42)) # staticmethod => bare function llvalue = r.convert_desc_or_const(value) setattr(vtable, mangled_name, llvalue) mro = list(rsubcls.classdef.getmro()) for fldname in self.clsfields: mangled_name, r = self.clsfields[fldname] if r.lowleveltype is Void: continue value = rsubcls.classdef.classdesc.read_attribute(fldname, None) if value is not None: assign(mangled_name, value) # extra PBC attributes for (access_set, attr), (mangled_name, r) in self.pbcfields.items(): if rsubcls.classdef.classdesc not in access_set.descs: continue # only for the classes in the same pbc access set if r.lowleveltype is Void: continue attrvalue = rsubcls.classdef.classdesc.read_attribute(attr, None) if attrvalue is not None: assign(mangled_name, attrvalue) # then initialize the 'super' portion of the vtable self.rbase.setup_vtable(vtable.super, rsubcls)
def get_ll_pyobjectptr(self, rtyper): from pypy.rpython.rclass import getinstancerepr wrapperobj = self.instance rpython_obj = get_rpython_data(wrapperobj) rpython_cls = rpython_obj.__class__ classdef = rtyper.annotator.bookkeeper.getuniqueclassdef(rpython_cls) r_inst = getinstancerepr(rtyper, classdef) pyobj = r_inst.convert_const(rpython_obj) return lltype.cast_pointer(PyObjPtr, pyobj)
def redispatch_call(self, hop, call_args): s_instance = hop.s_result r_instance = hop.r_result if len(self.s_pbc.descriptions) == 1: # instantiating a single class if self.lowleveltype is not Void: assert 0, "XXX None-or-1-class instantation not implemented" assert isinstance(s_instance, annmodel.SomeInstance) classdef = s_instance.classdef s_init = classdef.classdesc.s_read_attribute('__init__') v_init = Constant("init-func-dummy") # this value not really used if (isinstance(s_init, annmodel.SomeImpossibleValue) and classdef.classdesc.is_exception_class() and classdef.has_no_attrs()): # special case for instanciating simple built-in # exceptions: always return the same prebuilt instance, # and ignore any arguments passed to the contructor. r_instance = rclass.getinstancerepr(hop.rtyper, classdef) example = r_instance.get_reusable_prebuilt_instance() hop.exception_cannot_occur() return hop.inputconst(r_instance.lowleveltype, example) v_instance = rclass.rtype_new_instance(hop.rtyper, classdef, hop.llops, hop) if isinstance(v_instance, tuple): v_instance, must_call_init = v_instance if not must_call_init: return v_instance else: # instantiating a class from multiple possible classes vtypeptr = hop.inputarg(self, arg=0) try: access_set, r_class = self.get_access_set('__init__') except rclass.MissingRTypeAttribute: s_init = annmodel.s_ImpossibleValue else: s_init = access_set.s_value v_init = r_class.getpbcfield(vtypeptr, access_set, '__init__', hop.llops) v_instance = self._instantiate_runtime_class( hop, vtypeptr, r_instance) if isinstance(s_init, annmodel.SomeImpossibleValue): assert hop.nb_args == 1, ("arguments passed to __init__, " "but no __init__!") hop.exception_cannot_occur() else: hop2 = self.replace_class_with_inst_arg(hop, v_instance, s_instance, call_args) hop2.v_s_insertfirstarg(v_init, s_init) # add 'initfunc' hop2.s_result = annmodel.s_None hop2.r_result = self.rtyper.getrepr(hop2.s_result) # now hop2 looks like simple_call(initfunc, instance, args...) hop2.dispatch() return v_instance
def specialize_call(self, hop): from pypy.rpython.rclass import getinstancerepr s_cls = hop.args_s[1] assert s_cls.is_constant() [classdesc] = s_cls.descriptions classdef = classdesc.getuniqueclassdef() r_inst = getinstancerepr(hop.rtyper, classdef) cpytype = build_pytypeobject(r_inst) return hop.inputconst(PyObjPtr, cpytype)
def specialize_call(self, hop): from pypy.rpython.rclass import getinstancerepr s_cls = hop.args_s[0] assert s_cls.is_constant() [classdesc] = s_cls.descriptions classdef = classdesc.getuniqueclassdef() r_inst = getinstancerepr(hop.rtyper, classdef) vinst = r_inst.new_instance(hop.llops, v_cpytype = hop.args_v[1]) return vinst
def redispatch_call(self, hop, call_args): s_instance = hop.s_result r_instance = hop.r_result if len(self.s_pbc.descriptions) == 1: # instantiating a single class if self.lowleveltype is not Void: assert 0, "XXX None-or-1-class instantation not implemented" assert isinstance(s_instance, annmodel.SomeInstance) classdef = s_instance.classdef s_init = classdef.classdesc.s_read_attribute('__init__') v_init = Constant("init-func-dummy") # this value not really used if (isinstance(s_init, annmodel.SomeImpossibleValue) and classdef.classdesc.is_exception_class() and classdef.has_no_attrs()): # special case for instanciating simple built-in # exceptions: always return the same prebuilt instance, # and ignore any arguments passed to the contructor. r_instance = rclass.getinstancerepr(hop.rtyper, classdef) example = r_instance.get_reusable_prebuilt_instance() hop.exception_cannot_occur() return hop.inputconst(r_instance.lowleveltype, example) v_instance = rclass.rtype_new_instance(hop.rtyper, classdef, hop.llops, hop) if isinstance(v_instance, tuple): v_instance, must_call_init = v_instance if not must_call_init: return v_instance else: # instantiating a class from multiple possible classes vtypeptr = hop.inputarg(self, arg=0) try: access_set, r_class = self.get_access_set('__init__') except rclass.MissingRTypeAttribute: s_init = annmodel.s_ImpossibleValue else: s_init = access_set.s_value v_init = r_class.getpbcfield(vtypeptr, access_set, '__init__', hop.llops) v_instance = self._instantiate_runtime_class(hop, vtypeptr, r_instance) if isinstance(s_init, annmodel.SomeImpossibleValue): assert hop.nb_args == 1, ("arguments passed to __init__, " "but no __init__!") hop.exception_cannot_occur() else: hop2 = self.replace_class_with_inst_arg( hop, v_instance, s_instance, call_args) hop2.v_s_insertfirstarg(v_init, s_init) # add 'initfunc' hop2.s_result = annmodel.s_None hop2.r_result = self.rtyper.getrepr(hop2.s_result) # now hop2 looks like simple_call(initfunc, instance, args...) hop2.dispatch() return v_instance
def _instantiate_runtime_class(self, hop, v_meta, r_instance): classdef = hop.s_result.classdef c_class_ = hop.inputconst(ootype.Void, "class_") v_class = hop.genop('oogetfield', [v_meta, c_class_], resulttype=ootype.Class) resulttype = getinstancerepr(hop.rtyper, classdef).lowleveltype v_instance = hop.genop('runtimenew', [v_class], resulttype=resulttype) c_meta = hop.inputconst(ootype.Void, "meta") hop.genop('oosetfield', [v_instance, c_meta, v_meta], resulttype=ootype.Void) return v_instance
def __init__(self, rtyper): self.make_standard_exceptions(rtyper) # (NB. rclass identifies 'Exception' and 'object') r_type = rclass.getclassrepr(rtyper, None) r_instance = rclass.getinstancerepr(rtyper, None) r_type.setup() r_instance.setup() self.r_exception_type = r_type self.r_exception_value = r_instance self.lltype_of_exception_type = r_type.lowleveltype self.lltype_of_exception_value = r_instance.lowleveltype
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. 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 if llfields is None: llfields = [] attrs = self.classdef.attrs.items() attrs.sort() 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 llfields.append((mangled_name, r.lowleveltype)) # # hash() support if self.rtyper.needs_hash_support(self.classdef): from pypy.rpython import rint fields['_hash_cache_'] = 'hash_cache', rint.signed_repr llfields.append(('hash_cache', Signed)) 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 = {} if '_immutable_' in self.classdef.classdesc.classdict: hints = hints.copy() hints['immutable'] = True object_type = MkStruct(self.classdef.name, ('super', self.rbase.object_type), hints=hints, adtmeths=adtmeths, *llfields) self.object_type.become(object_type) allinstancefields.update(self.rbase.allinstancefields) allinstancefields.update(fields) self.fields = fields self.allinstancefields = allinstancefields if self.gcflavor == 'gc': attachRuntimeTypeInfo(self.object_type)
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. 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 if llfields is None: llfields = [] attrs = self.classdef.attrs.items() attrs.sort() 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 llfields.append((mangled_name, r.lowleveltype)) 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) object_type = MkStruct(self.classdef.name, ('super', self.rbase.object_type), hints=hints, adtmeths=adtmeths, *llfields) self.object_type.become(object_type) allinstancefields.update(self.rbase.allinstancefields) allinstancefields.update(fields) self.fields = fields self.allinstancefields = allinstancefields if self.gcflavor == 'gc': attachRuntimeTypeInfo(self.object_type)
def __init__(self, translator, entrypoint, stackless_gc=False, assert_unwind=False): self.translator = translator self.stackless_gc = stackless_gc self.frametyper = FrameTyper(stackless_gc, self) self.masterarray1 = [] self.curr_graph = None self.signaturecodes = [{} for RETTYPE in frame.STORAGE_TYPES] # self.signaturecodes[n] is a dict {ARGTYPES: signature_index} # where n is the return type as an index in STORAGE_TYPES. # the signature_index is an arbitrary number but it encodes # the type of the result, i.e. # n == (signature_index & storage_type_bitmask) bk = translator.annotator.bookkeeper self.unwind_exception_type = getinstancerepr( self.translator.rtyper, bk.getuniqueclassdef(code.UnwindException)).lowleveltype self.analyzer = StacklessAnalyzer(translator, stackless_gc) # the point of this little dance is to not annotate # code.global_state.masterarray as a constant. data_classdef = bk.getuniqueclassdef(code.StacklessData) data_classdef.generalize_attr( 'masterarray', annmodel.SomePtr(lltype.Ptr(frame.FRAME_INFO_ARRAY))) mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) l2a = annmodel.lltype_to_annotation if assert_unwind: def slp_entry_point(argv): try: r = entrypoint(argv) except code.UnwindException, u: code.slp_main_loop(u.depth) return code.global_state.retval_long else: assert False, "entrypoint never unwound the stack" return r
def convert_const(self, weakdict): if not isinstance(weakdict, RWeakValueDictionary): raise TyperError("expected an RWeakValueDictionary: %r" % (weakdict,)) try: key = Constant(weakdict) return self.dict_cache[key] except KeyError: self.setup() l_dict = self.ll_new_weakdict() self.dict_cache[key] = l_dict bk = self.rtyper.annotator.bookkeeper classdef = bk.getuniqueclassdef(weakdict._valueclass) r_value = getinstancerepr(self.rtyper, classdef) for dictkey, dictvalue in weakdict._dict.items(): llkey = self.r_key.convert_const(dictkey) llvalue = r_value.convert_const(dictvalue) if llvalue: llvalue = lltype.cast_pointer(rclass.OBJECTPTR, llvalue) self.ll_set_nonnull(l_dict, llkey, llvalue) return l_dict
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.keys()[0] graph = funcdesc.getuniquegraph() 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.type_for_typeptr[vtable._obj] = self.lowleveltype.TO self.rtyper.lltype2vtable[self.lowleveltype.TO] = vtable
def _setup_repr_final(self): if self.gcflavor in RTTIFLAVORS: 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.keys()[0] graph = funcdesc.getuniquegraph() 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)
def convert_const(self, weakdict): if not isinstance(weakdict, RWeakValueDictionary): raise TyperError("expected an RWeakValueDictionary: %r" % (weakdict, )) try: key = Constant(weakdict) return self.dict_cache[key] except KeyError: self.setup() l_dict = self.ll_new_weakdict() self.dict_cache[key] = l_dict bk = self.rtyper.annotator.bookkeeper classdef = bk.getuniqueclassdef(weakdict._valueclass) r_value = getinstancerepr(self.rtyper, classdef) for dictkey, dictvalue in weakdict._dict.items(): llkey = self.r_key.convert_const(dictkey) llvalue = r_value.convert_const(dictvalue) if llvalue: llvalue = lltype.cast_pointer(rclass.OBJECTPTR, llvalue) self.ll_set_nonnull(l_dict, llkey, llvalue) return l_dict
def _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.keys()[0] graph = funcdesc.getuniquegraph() 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)
def __init__(self, rtyper, classdef, gcflavor='ignored'): AbstractInstanceRepr.__init__(self, rtyper, classdef) self.baserepr = None if self.classdef is None: self.lowleveltype = OBJECT else: b = self.classdef.basedef if b is not None: self.baserepr = getinstancerepr(rtyper, b) b = self.baserepr.lowleveltype else: b = OBJECT if hasattr(classdef.classdesc.pyobj, '_rpython_hints'): hints = classdef.classdesc.pyobj._rpython_hints else: hints = {} self.lowleveltype = ootype.Instance(classdef.name, b, {}, {}, _hints = hints) self.prebuiltinstances = {} # { id(x): (x, _ptr) } self.object_type = self.lowleveltype self.gcflavor = gcflavor
def __init__(self, rtyper, classdef, gcflavor='ignored'): AbstractInstanceRepr.__init__(self, rtyper, classdef) self.baserepr = None if self.classdef is None: self.lowleveltype = OBJECT else: b = self.classdef.basedef if b is not None: self.baserepr = getinstancerepr(rtyper, b) b = self.baserepr.lowleveltype else: b = OBJECT if hasattr(classdef.classdesc.pyobj, '_rpython_hints'): hints = classdef.classdesc.pyobj._rpython_hints else: hints = {} hints = self._check_for_immutable_hints(hints) self.lowleveltype = ootype.Instance(classdef.name, b, {}, {}, _hints = hints) self.iprebuiltinstances = identity_dict() self.object_type = self.lowleveltype self.gcflavor = gcflavor
def __init__(self, rtyper, s_pbc): self.rtyper = rtyper self.s_pbc = s_pbc if s_pbc.isNone(): raise TyperError("unsupported: variable of type " "bound-method-object or None") mdescs = s_pbc.descriptions.keys() methodname = mdescs[0].name classdef = mdescs[0].selfclassdef flags = mdescs[0].flags for mdesc in mdescs[1:]: if mdesc.name != methodname: raise TyperError("cannot find a unique name under which the " "methods can be found: %r" % ( mdescs,)) if mdesc.flags != flags: raise TyperError("inconsistent 'flags': %r versus %r" % ( mdesc.flags, flags)) classdef = classdef.commonbase(mdesc.selfclassdef) if classdef is None: raise TyperError("mixing methods coming from instances of " "classes with no common base: %r" % (mdescs,)) self.methodname = methodname # for ootype, the right thing to do is to always keep the most precise # type of the instance, while for lltype we want to cast it to the # type where the method is actually defined. See also # test_rclass.test_method_specialized_with_subclass and # rtyper.attach_methods_to_subclasses if self.rtyper.type_system.name == 'ootypesystem': self.classdef = classdef else: self.classdef = classdef.locate_attribute(methodname) # the low-level representation is just the bound 'self' argument. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags) self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef) self.lowleveltype = self.r_im_self.lowleveltype
def __init__(self, rtyper, s_pbc): self.rtyper = rtyper self.s_pbc = s_pbc if s_pbc.isNone(): raise TyperError("unsupported: variable of type " "bound-method-object or None") mdescs = s_pbc.descriptions.keys() methodname = mdescs[0].name classdef = mdescs[0].selfclassdef flags = mdescs[0].flags for mdesc in mdescs[1:]: if mdesc.name != methodname: raise TyperError("cannot find a unique name under which the " "methods can be found: %r" % (mdescs, )) if mdesc.flags != flags: raise TyperError("inconsistent 'flags': %r versus %r" % (mdesc.flags, flags)) classdef = classdef.commonbase(mdesc.selfclassdef) if classdef is None: raise TyperError("mixing methods coming from instances of " "classes with no common base: %r" % (mdescs, )) self.methodname = methodname # for ootype, the right thing to do is to always keep the most precise # type of the instance, while for lltype we want to cast it to the # type where the method is actually defined. See also # test_rclass.test_method_specialized_with_subclass and # rtyper.attach_methods_to_subclasses if self.rtyper.type_system.name == 'ootypesystem': self.classdef = classdef else: self.classdef = classdef.locate_attribute(methodname) # the low-level representation is just the bound 'self' argument. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags) self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef) self.lowleveltype = self.r_im_self.lowleveltype
def __init__(self, rtyper, classdef, gcflavor='ignored'): AbstractInstanceRepr.__init__(self, rtyper, classdef) self.baserepr = None if self.classdef is None: self.lowleveltype = OBJECT else: b = self.classdef.basedef if b is not None: self.baserepr = getinstancerepr(rtyper, b) b = self.baserepr.lowleveltype else: b = OBJECT if hasattr(classdef.classdesc.pyobj, '_rpython_hints'): hints = classdef.classdesc.pyobj._rpython_hints else: hints = {} self.lowleveltype = ootype.Instance(classdef.name, b, {}, {}, _hints=hints) self.prebuiltinstances = {} # { id(x): (x, _ptr) } self.object_type = self.lowleveltype self.gcflavor = gcflavor
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)})
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)})
annmodel.s_None), llmemory.Address: mixlevelannotator.constfunc( code.resume_after_addr, [s_StatePtr, annmodel.SomeAddress()], annmodel.s_None), SAVED_REFERENCE: mixlevelannotator.constfunc( code.resume_after_ref, [s_StatePtr, annmodel.SomePtr(SAVED_REFERENCE)], annmodel.s_None), } exception_def = bk.getuniqueclassdef(Exception) self.resume_after_raising_ptr = mixlevelannotator.constfunc( code.resume_after_raising, [s_StatePtr, annmodel.SomeInstance(exception_def)], annmodel.s_None) self.exception_type = getinstancerepr( self.translator.rtyper, exception_def).lowleveltype def set_back_pointer(frame, back): frame.f_back = back if back: frame.f_depth = back.f_depth + 1 else: frame.f_depth = 0 self.set_back_pointer_ptr = mixlevelannotator.constfunc( set_back_pointer, [s_hdrptr, s_hdrptr], annmodel.s_None) mixlevelannotator.finish() s_global_state = bk.immutablevalue(code.global_state)
def specialize_call(self, hop): r_generic_object = getinstancerepr(hop.rtyper, None) [v] = hop.inputargs(r_generic_object) # might generate a cast_pointer return v
def _instantiate_runtime_class(self, hop, v_class, r_instance): classdef = hop.s_result.classdef resulttype = getinstancerepr(hop.rtyper, classdef).lowleveltype # convert v_class from META to ootype.Class if necessary: v_class = get_type_repr(hop.rtyper).fromclasstype(v_class, hop.llops) return hop.genop('runtimenew', [v_class], resulttype=resulttype)
def get_standard_ll_exc_instance(self, rtyper, clsdef): rclass = rtyper.type_system.rclass r_inst = rclass.getinstancerepr(rtyper, clsdef) example = r_inst.get_reusable_prebuilt_instance() example = self.cast_exception(self.lltype_of_exception_value, example) return example
v = llops.genop('cast_pointer', [v], resulttype = r_ins2.lowleveltype) return v else: return NotImplemented def rtype_is_((r_ins1, r_ins2), hop): if r_ins1.gcflavor != r_ins2.gcflavor: # obscure logic, the is can be true only if both are None v_ins1, v_ins2 = hop.inputargs(r_ins1.common_repr(), r_ins2.common_repr()) return hop.gendirectcall(ll_both_none, v_ins1, v_ins2) if r_ins1.classdef is None or r_ins2.classdef is None: basedef = None else: basedef = r_ins1.classdef.commonbase(r_ins2.classdef) r_ins = getinstancerepr(r_ins1.rtyper, basedef, r_ins1.gcflavor) return pairtype(Repr, Repr).rtype_is_(pair(r_ins, r_ins), hop) rtype_eq = rtype_is_ def rtype_ne(rpair, hop): v = rpair.rtype_eq(hop) return hop.genop("bool_not", [v], resulttype=Bool) # # _________________________ Conversions for CPython _________________________ # part I: wrapping, destructor, preserving object identity def call_destructor(thing, repr): ll_call_destructor(thing, repr)
def common_repr(self): # -> object or nongcobject reprs return getinstancerepr(self.rtyper, None, self.gcflavor)
def _setup_repr(self, llfields=None, hints=None): if hints: self.lowleveltype._hints.update(hints) 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 = {} 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 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() 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.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)
resulttype=r_ins2.lowleveltype) return v else: return NotImplemented def rtype_is_((r_ins1, r_ins2), hop): if r_ins1.gcflavor != r_ins2.gcflavor: # obscure logic, the is can be true only if both are None v_ins1, v_ins2 = hop.inputargs(r_ins1.common_repr(), r_ins2.common_repr()) return hop.gendirectcall(ll_both_none, v_ins1, v_ins2) if r_ins1.classdef is None or r_ins2.classdef is None: basedef = None else: basedef = r_ins1.classdef.commonbase(r_ins2.classdef) r_ins = getinstancerepr(r_ins1.rtyper, basedef, r_ins1.gcflavor) return pairtype(Repr, Repr).rtype_is_(pair(r_ins, r_ins), hop) rtype_eq = rtype_is_ def rtype_ne(rpair, hop): v = rpair.rtype_eq(hop) return hop.genop("bool_not", [v], resulttype=Bool) # ____________________________________________________________ # # Low-level implementation of operations on classes and instances # doesn't work for non-gc stuff!
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, 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 pypy.rpython.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