def test_del_inheritance(self): from rpython.rlib import rgc class State: pass s = State() s.a_dels = 0 s.b_dels = 0 class A(object): def __del__(self): s.a_dels += 1 class B(A): def __del__(self): s.b_dels += 1 class C(A): pass def f(): A() B() C() A() B() C() rgc.collect() return s.a_dels * 10 + s.b_dels res = f() assert res == 42 t = TranslationContext() t.buildannotator().build_types(f, []) t.buildrtyper().specialize() graph = graphof(t, f) TYPEA = graph.startblock.operations[0].args[0].value RTTIA = getRuntimeTypeInfo(TYPEA) TYPEB = graph.startblock.operations[3].args[0].value RTTIB = getRuntimeTypeInfo(TYPEB) TYPEC = graph.startblock.operations[6].args[0].value RTTIC = getRuntimeTypeInfo(TYPEC) queryptra = RTTIA._obj.query_funcptr # should not raise queryptrb = RTTIB._obj.query_funcptr # should not raise queryptrc = RTTIC._obj.query_funcptr # should not raise destrptra = RTTIA._obj.destructor_funcptr destrptrb = RTTIB._obj.destructor_funcptr destrptrc = RTTIC._obj.destructor_funcptr assert destrptra == destrptrc assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None
def find_malloc_creps(graph, adi, translator, malloc_graphs): # mapping from malloc creation point to graphs that it flows into malloc_creps = {} # find all mallocs that don't escape for block, op in graph.iterblockops(): if op.opname == "malloc": STRUCT = op.args[0].value # must not remove mallocs of structures that have a RTTI with a destructor flags = op.args[1].value if flags != {"flavor": "gc"}: continue try: destr_ptr = lltype.getRuntimeTypeInfo(STRUCT)._obj.destructor_funcptr if destr_ptr: continue except (ValueError, AttributeError): pass varstate = adi.getstate(op.result) assert len(varstate.creation_points) == 1 crep, = varstate.creation_points if not crep.escapes and not crep.returns: malloc_creps[crep] = {} if op.opname == "direct_call": called_graph = get_graph(op.args[0], translator) if called_graph not in malloc_graphs: continue varstate = adi.getstate(op.result) assert len(varstate.creation_points) == 1 crep, = varstate.creation_points if not crep.escapes and not crep.returns: malloc_creps[crep] = {} return malloc_creps
def get_rtti(TYPE): if isinstance(TYPE, lltype.RttiStruct): try: return lltype.getRuntimeTypeInfo(TYPE) except ValueError: pass return None
def RTTI_dtor(self, STRUCT): try: destr_ptr = lltype.getRuntimeTypeInfo(STRUCT)._obj.destructor_funcptr if destr_ptr: return True except (ValueError, AttributeError): pass return False
def check_no_destructor(self): STRUCT = self.MALLOCTYPE try: rttiptr = lltype.getRuntimeTypeInfo(STRUCT) except ValueError: return # ok destr_ptr = getattr(rttiptr._obj, 'destructor_funcptr', None) if destr_ptr: raise CannotRemoveThisType
def setup_vtable(self, vtable, rsubcls): """Initialize the 'self' portion of the 'vtable' belonging to the given subclass.""" if self.classdef is None: vtable.hash = hash(rsubcls) # 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 test_runtime_type_info(): S = lltype.GcStruct('s', ('x', lltype.Signed), rtti=True) def ll_example(p): return (lltype.runtime_type_info(p), lltype.runtime_type_info(p) == lltype.getRuntimeTypeInfo(S)) assert ll_example(lltype.malloc(S)) == (lltype.getRuntimeTypeInfo(S), True) s, t = ll_rtype(ll_example, [SomePtr(lltype.Ptr(S))]) assert s == annmodel.SomeTuple([SomePtr(lltype.Ptr(lltype.RuntimeTypeInfo)), annmodel.SomeBool()])
def can_remove(op): S = op.args[0].value if op.args[1].value != {'flavor': 'gc'}: return False try: # cannot remove if there is a destructor destr_ptr = lltype.getRuntimeTypeInfo(S)._obj.destructor_funcptr if destr_ptr: return False except (ValueError, AttributeError): pass return True
def test_runtime_type_info(): S = lltype.GcStruct('s', ('x', lltype.Signed), rtti=True) def ll_example(p): return (lltype.runtime_type_info(p), lltype.runtime_type_info(p) == lltype.getRuntimeTypeInfo(S)) assert ll_example(lltype.malloc(S)) == (lltype.getRuntimeTypeInfo(S), True) s, t = ll_rtype(ll_example, [SomePtr(lltype.Ptr(S))]) assert s == annmodel.SomeTuple( [SomePtr(lltype.Ptr(lltype.RuntimeTypeInfo)), annmodel.SomeBool()])
def computegcinfo(self, gcpolicy): # let the gcpolicy do its own setup self.gcinfo = None # unless overwritten below rtti = None STRUCT = self.STRUCT if isinstance(STRUCT, RttiStruct): try: rtti = getRuntimeTypeInfo(STRUCT) except ValueError: pass if self.varlength is None: gcpolicy.struct_setup(self, rtti) return self.gcinfo
def test__del__(self): class A(object): def __init__(self): self.a = 2 def __del__(self): self.a = 3 def f(): a = A() return a.a t = TranslationContext() t.buildannotator().build_types(f, []) t.buildrtyper().specialize() graph = graphof(t, f) TYPE = graph.startblock.operations[0].args[0].value RTTI = getRuntimeTypeInfo(TYPE) RTTI._obj.query_funcptr # should not raise destrptr = RTTI._obj.destructor_funcptr assert destrptr is not None
def fill_vtable_root(self, vtable): """Initialize the head of the vtable.""" # initialize the 'subclassrange_*' and 'name' fields if self.classdef is not None: vtable.subclassrange_min = self.classdef.minid vtable.subclassrange_max = self.classdef.maxid else: # for the root class vtable.subclassrange_min = 0 vtable.subclassrange_max = sys.maxint rinstance = getinstancerepr(self.rtyper, self.classdef) rinstance.setup() if rinstance.gcflavor == 'gc': vtable.rtti = getRuntimeTypeInfo(rinstance.object_type) if self.classdef is None: name = 'object' else: name = self.classdef.shortname vtable.name = alloc_array_name(name) if hasattr(self.classdef, 'my_instantiate_graph'): graph = self.classdef.my_instantiate_graph vtable.instantiate = self.rtyper.getcallable(graph)
def fill_vtable_root(self, vtable): """Initialize the head of the vtable.""" vtable.hash = hash(self) # initialize the 'subclassrange_*' and 'name' fields if self.classdef is not None: #vtable.parenttypeptr = self.rbase.getvtable() vtable.subclassrange_min = self.classdef.minid vtable.subclassrange_max = self.classdef.maxid else: # for the root class vtable.subclassrange_min = 0 vtable.subclassrange_max = sys.maxint rinstance = getinstancerepr(self.rtyper, self.classdef) rinstance.setup() if rinstance.gcflavor == 'gc': vtable.rtti = getRuntimeTypeInfo(rinstance.object_type) if self.classdef is None: name = 'object' else: name = self.classdef.shortname vtable.name = alloc_array_name(name) if hasattr(self.classdef, 'my_instantiate_graph'): graph = self.classdef.my_instantiate_graph vtable.instantiate = self.rtyper.getcallable(graph)
def type_info_S(s): return lltype.getRuntimeTypeInfo(S)
def ll_example(p): return (lltype.runtime_type_info(p), lltype.runtime_type_info(p) == lltype.getRuntimeTypeInfo(S))
def getRuntimeTypeInfo(T): assert T.is_constant() return immutablevalue(lltype.getRuntimeTypeInfo(T.const))
def type_info_T(p): return lltype.getRuntimeTypeInfo(T)
def setup_vtable(self, vtable, rsubcls): """Initialize the 'self' portion of the 'vtable' belonging to the given subclass.""" if self.classdef is None: vtable.hash = hash(rsubcls) # 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)