def dynamic_deallocation_funcptr_for_type(self, TYPE): assert TYPE._gckind != 'cpy' if TYPE in self.dynamic_deallocator_funcptrs: return self.dynamic_deallocator_funcptrs[TYPE] #print_call_chain(self) rtti = get_rtti(TYPE) if rtti is None: p = self.static_deallocation_funcptr_for_type(TYPE) self.dynamic_deallocator_funcptrs[TYPE] = p return p queryptr = rtti._obj.query_funcptr if queryptr._obj in self.queryptr2dynamic_deallocator_funcptr: return self.queryptr2dynamic_deallocator_funcptr[queryptr._obj] RTTI_PTR = lltype.Ptr(lltype.RuntimeTypeInfo) QUERY_ARG_TYPE = lltype.typeOf(queryptr).TO.ARGS[0] gc_header_offset = self.gcheaderbuilder.size_gc_header HDRPTR = lltype.Ptr(self.HDR) def ll_dealloc(addr): # bump refcount to 1 gcheader = llmemory.cast_adr_to_ptr(addr - gc_header_offset, HDRPTR) gcheader.refcount = 1 v = llmemory.cast_adr_to_ptr(addr, QUERY_ARG_TYPE) rtti = queryptr(v) gcheader.refcount = 0 llop.gc_call_rtti_destructor(lltype.Void, rtti, addr) fptr = self.annotate_helper(ll_dealloc, [llmemory.Address], lltype.Void) self.dynamic_deallocator_funcptrs[TYPE] = fptr self.queryptr2dynamic_deallocator_funcptr[queryptr._obj] = fptr return fptr
def dynamic_deallocation_funcptr_for_type(self, TYPE): assert TYPE._gckind != "cpy" if TYPE in self.dynamic_deallocator_funcptrs: return self.dynamic_deallocator_funcptrs[TYPE] # print_call_chain(self) rtti = get_rtti(TYPE) if rtti is None: p = self.static_deallocation_funcptr_for_type(TYPE) self.dynamic_deallocator_funcptrs[TYPE] = p return p queryptr = rtti._obj.query_funcptr if queryptr._obj in self.queryptr2dynamic_deallocator_funcptr: return self.queryptr2dynamic_deallocator_funcptr[queryptr._obj] RTTI_PTR = lltype.Ptr(lltype.RuntimeTypeInfo) QUERY_ARG_TYPE = lltype.typeOf(queryptr).TO.ARGS[0] gc_header_offset = self.gcheaderbuilder.size_gc_header HDRPTR = lltype.Ptr(self.HDR) def ll_dealloc(addr): # bump refcount to 1 gcheader = llmemory.cast_adr_to_ptr(addr - gc_header_offset, HDRPTR) gcheader.refcount = 1 v = llmemory.cast_adr_to_ptr(addr, QUERY_ARG_TYPE) rtti = queryptr(v) gcheader.refcount = 0 llop.gc_call_rtti_destructor(lltype.Void, rtti, addr) fptr = self.annotate_helper(ll_dealloc, [llmemory.Address], lltype.Void) self.dynamic_deallocator_funcptrs[TYPE] = fptr self.queryptr2dynamic_deallocator_funcptr[queryptr._obj] = fptr return fptr
def make_finalizer_funcptr_for_type(self, TYPE): from pypy.rpython.memory.gctransform.support import get_rtti, type_contains_pyobjs rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, "destructor_funcptr"): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] destrgraph = destrptr._obj.graph else: return None, False assert not type_contains_pyobjs(TYPE), "not implemented" t = self.llinterp.typer.annotator.translator light = not FinalizerAnalyzer(t).analyze_light_finalizer(destrgraph) def ll_finalizer(addr, dummy): assert dummy == llmemory.NULL try: v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) self.llinterp.eval_graph(destrgraph, [v], recursive=True) except llinterp.LLException: raise RuntimeError("a finalizer raised an exception, shouldn't happen") return llmemory.NULL return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer), light
def make_custom_trace_funcptr_for_type(self, TYPE): from pypy.rpython.memory.gctransform.support import get_rtti, \ type_contains_pyobjs rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'custom_trace_funcptr'): return rtti._obj.custom_trace_funcptr else: return None
def make_custom_trace_funcptr_for_type(self, TYPE): from pypy.rpython.memory.gctransform.support import get_rtti, type_contains_pyobjs rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, "custom_trace_funcptr"): return rtti._obj.custom_trace_funcptr else: return None
def finalizer_funcptr_for_type(self, TYPE): if TYPE in self.finalizer_funcptrs: return self.finalizer_funcptrs[TYPE] rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] else: destrptr = None DESTR_ARG = None if type_contains_pyobjs(TYPE): if destrptr: raise Exception("can't mix PyObjects and __del__ with Boehm") static_body = '\n'.join( _static_deallocator_body_for_type('v', TYPE)) d = { 'pop_alive': LLTransformerOp(self.pop_alive), 'PTR_TYPE': lltype.Ptr(TYPE), 'cast_adr_to_ptr': llmemory.cast_adr_to_ptr } src = ("def ll_finalizer(addr):\n" " v = cast_adr_to_ptr(addr, PTR_TYPE)\n" "%s\n") % (static_body, ) exec src in d fptr = self.annotate_finalizer(d['ll_finalizer'], [llmemory.Address], lltype.Void) elif destrptr: EXC_INSTANCE_TYPE = self.translator.rtyper.exceptiondata.lltype_of_exception_value typename = TYPE.__name__ def ll_finalizer(addr): exc_instance = llop.gc_fetch_exception(EXC_INSTANCE_TYPE) v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) ll_call_destructor(destrptr, v, typename) llop.gc_restore_exception(lltype.Void, exc_instance) fptr = self.annotate_finalizer(ll_finalizer, [llmemory.Address], lltype.Void) else: fptr = lltype.nullptr(self.FINALIZER_PTR.TO) self.finalizer_funcptrs[TYPE] = fptr return fptr
def make_finalizer_funcptr_for_type(self, TYPE): rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] else: destrptr = None DESTR_ARG = None assert not type_contains_pyobjs(TYPE), "not implemented" if destrptr: def ll_finalizer(addr): v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) ll_call_destructor(destrptr, v) fptr = self.transformer.annotate_finalizer(ll_finalizer, [llmemory.Address], lltype.Void) else: fptr = lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO) return fptr
def make_finalizer_funcptr_for_type(self, TYPE): from pypy.rpython.memory.gctransform.support import get_rtti, \ type_contains_pyobjs rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] destrgraph = destrptr._obj.graph else: return lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO) assert not type_contains_pyobjs(TYPE), "not implemented" def ll_finalizer(addr): try: v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) self.llinterp.eval_graph(destrgraph, [v], recursive=True) except llinterp.LLException: raise RuntimeError( "a finalizer raised an exception, shouldn't happen") return llhelper(gctypelayout.GCData.FINALIZERTYPE, ll_finalizer)
def make_finalizer_funcptr_for_type(self, TYPE): rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] else: destrptr = None DESTR_ARG = None assert not type_contains_pyobjs(TYPE), "not implemented" if destrptr: def ll_finalizer(addr): v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) ll_call_destructor(destrptr, v) fptr = self.transformer.annotate_finalizer(ll_finalizer, [llmemory.Address], lltype.Void) else: fptr = lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO) return fptr
def finalizer_funcptr_for_type(self, TYPE): if TYPE in self.finalizer_funcptrs: return self.finalizer_funcptrs[TYPE] rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] else: destrptr = None DESTR_ARG = None if type_contains_pyobjs(TYPE): if destrptr: raise Exception("can't mix PyObjects and __del__ with Boehm") static_body = '\n'.join(_static_deallocator_body_for_type('v', TYPE)) d = {'pop_alive': LLTransformerOp(self.pop_alive), 'PTR_TYPE':lltype.Ptr(TYPE), 'cast_adr_to_ptr': llmemory.cast_adr_to_ptr} src = ("def ll_finalizer(addr):\n" " v = cast_adr_to_ptr(addr, PTR_TYPE)\n" "%s\n")%(static_body,) exec src in d fptr = self.annotate_finalizer(d['ll_finalizer'], [llmemory.Address], lltype.Void) elif destrptr: EXC_INSTANCE_TYPE = self.translator.rtyper.exceptiondata.lltype_of_exception_value typename = TYPE.__name__ def ll_finalizer(addr): exc_instance = llop.gc_fetch_exception(EXC_INSTANCE_TYPE) v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) ll_call_destructor(destrptr, v, typename) llop.gc_restore_exception(lltype.Void, exc_instance) fptr = self.annotate_finalizer(ll_finalizer, [llmemory.Address], lltype.Void) else: fptr = lltype.nullptr(self.FINALIZER_PTR.TO) self.finalizer_funcptrs[TYPE] = fptr return fptr
def make_finalizer_funcptr_for_type(self, TYPE): from pypy.rpython.memory.gctransform.support import get_rtti, \ type_contains_pyobjs rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] destrgraph = destrptr._obj.graph else: return lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO) assert not type_contains_pyobjs(TYPE), "not implemented" def ll_finalizer(addr): try: v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) self.llinterp.eval_graph(destrgraph, [v], recursive=True) except llinterp.LLException: raise RuntimeError( "a finalizer raised an exception, shouldn't happen") return llhelper(gctypelayout.GCData.FINALIZERTYPE, ll_finalizer)
def finalizer_funcptr_for_type(self, TYPE): if TYPE in self.finalizer_funcptrs: return self.finalizer_funcptrs[TYPE] rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] else: destrptr = None DESTR_ARG = None assert not type_contains_pyobjs(TYPE), "not implemented" if destrptr: def ll_finalizer(addr): v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) ll_call_destructor(destrptr, v) fptr = self.annotate_helper(ll_finalizer, [llmemory.Address], lltype.Void) else: fptr = lltype.nullptr(ADDRESS_VOID_FUNC) self.finalizer_funcptrs[TYPE] = fptr return fptr
def make_finalizer_funcptr_for_type(self, TYPE): from pypy.rpython.memory.gctransform.support import get_rtti, \ type_contains_pyobjs rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] destrgraph = destrptr._obj.graph else: return None, False assert not type_contains_pyobjs(TYPE), "not implemented" t = self.llinterp.typer.annotator.translator light = not FinalizerAnalyzer(t).analyze_light_finalizer(destrgraph) def ll_finalizer(addr, dummy): assert dummy == llmemory.NULL try: v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) self.llinterp.eval_graph(destrgraph, [v], recursive=True) except llinterp.LLException: raise RuntimeError( "a finalizer raised an exception, shouldn't happen") return llmemory.NULL return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer), light
def find_initializing_stores(collect_analyzer, graph): from pypy.objspace.flow.model import mkentrymap entrymap = mkentrymap(graph) # a bit of a hackish analysis: if a block contains a malloc and check that # the result is not zero, then the block following the True link will # usually initialize the newly allocated object result = {} def find_in_block(block, mallocvars): for i, op in enumerate(block.operations): if op.opname in ("cast_pointer", "same_as"): if op.args[0] in mallocvars: mallocvars[op.result] = True elif op.opname in ("setfield", "setarrayitem", "setinteriorfield"): TYPE = op.args[-1].concretetype if (op.args[0] in mallocvars and isinstance(TYPE, lltype.Ptr) and TYPE.TO._gckind == "gc"): result[op] = True else: if collect_analyzer.analyze(op): return for exit in block.exits: if len(entrymap[exit.target]) != 1: continue newmallocvars = {} for i, var in enumerate(exit.args): if var in mallocvars: newmallocvars[exit.target.inputargs[i]] = True if newmallocvars: find_in_block(exit.target, newmallocvars) mallocnum = 0 blockset = set(graph.iterblocks()) while blockset: block = blockset.pop() if len(block.operations) < 2: continue mallocop = block.operations[-2] checkop = block.operations[-1] if not (mallocop.opname == "malloc" and checkop.opname == "ptr_nonzero" and mallocop.result is checkop.args[0] and block.exitswitch is checkop.result): continue rtti = get_rtti(mallocop.args[0].value) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): continue exits = [exit for exit in block.exits if exit.llexitcase] if len(exits) != 1: continue exit = exits[0] if len(entrymap[exit.target]) != 1: continue try: index = exit.args.index(mallocop.result) except ValueError: continue target = exit.target mallocvars = {target.inputargs[index]: True} mallocnum += 1 find_in_block(target, mallocvars) #if result: # print "found %s initializing stores in %s" % (len(result), graph.name) return result
def static_deallocation_funcptr_for_type(self, TYPE): if TYPE in self.static_deallocator_funcptrs: return self.static_deallocator_funcptrs[TYPE] #print_call_chain(self) rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] else: destrptr = None DESTR_ARG = None if destrptr is None and not find_gc_ptrs_in_type(TYPE): #print repr(TYPE)[:80], 'is dealloc easy' p = self.no_pointer_dealloc_ptr.value self.static_deallocator_funcptrs[TYPE] = p return p if destrptr is not None: body = '\n'.join(_static_deallocator_body_for_type('v', TYPE, 3)) src = """ def ll_deallocator(addr): exc_instance = llop.gc_fetch_exception(EXC_INSTANCE_TYPE) try: v = cast_adr_to_ptr(addr, PTR_TYPE) gcheader = cast_adr_to_ptr(addr - gc_header_offset, HDRPTR) # refcount is at zero, temporarily bump it to 1: gcheader.refcount = 1 destr_v = cast_pointer(DESTR_ARG, v) ll_call_destructor(destrptr, destr_v) refcount = gcheader.refcount - 1 gcheader.refcount = refcount if refcount == 0: %s llop.gc_free(lltype.Void, addr) except: pass llop.gc_restore_exception(lltype.Void, exc_instance) pop_alive(exc_instance) # XXX layering of exceptiontransform versus gcpolicy """ % (body, ) else: call_del = None body = '\n'.join(_static_deallocator_body_for_type('v', TYPE)) src = ('def ll_deallocator(addr):\n v = cast_adr_to_ptr(addr, PTR_TYPE)\n' + body + '\n llop.gc_free(lltype.Void, addr)\n') d = {'pop_alive': LLTransformerOp(self.pop_alive), 'llop': llop, 'lltype': lltype, 'destrptr': destrptr, 'gc_header_offset': self.gcheaderbuilder.size_gc_header, 'cast_adr_to_ptr': llmemory.cast_adr_to_ptr, 'cast_pointer': lltype.cast_pointer, 'PTR_TYPE': lltype.Ptr(TYPE), 'DESTR_ARG': DESTR_ARG, 'EXC_INSTANCE_TYPE': self.translator.rtyper.exceptiondata.lltype_of_exception_value, 'll_call_destructor': ll_call_destructor, 'HDRPTR':lltype.Ptr(self.HDR)} exec src in d this = d['ll_deallocator'] fptr = self.annotate_helper(this, [llmemory.Address], lltype.Void) self.static_deallocator_funcptrs[TYPE] = fptr for p in find_gc_ptrs_in_type(TYPE): self.static_deallocation_funcptr_for_type(p.TO) return fptr
def static_deallocation_funcptr_for_type(self, TYPE): if TYPE in self.static_deallocator_funcptrs: return self.static_deallocator_funcptrs[TYPE] # print_call_chain(self) if TYPE._gckind == "cpy": return # you don't really have an RPython deallocator for PyObjects rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, "destructor_funcptr"): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] else: destrptr = None DESTR_ARG = None if destrptr is None and not find_gc_ptrs_in_type(TYPE): p = self.no_pointer_dealloc_ptr.value self.static_deallocator_funcptrs[TYPE] = p return p if destrptr is not None: body = "\n".join(_static_deallocator_body_for_type("v", TYPE, 3)) src = """ def ll_deallocator(addr): exc_instance = llop.gc_fetch_exception(EXC_INSTANCE_TYPE) try: v = cast_adr_to_ptr(addr, PTR_TYPE) gcheader = cast_adr_to_ptr(addr - gc_header_offset, HDRPTR) # refcount is at zero, temporarily bump it to 1: gcheader.refcount = 1 destr_v = cast_pointer(DESTR_ARG, v) ll_call_destructor(destrptr, destr_v) refcount = gcheader.refcount - 1 gcheader.refcount = refcount if refcount == 0: %s llop.%s_free(lltype.Void, addr) except: pass llop.gc_restore_exception(lltype.Void, exc_instance) pop_alive(exc_instance) # XXX layering of exceptiontransform versus gcpolicy """ % ( body, TYPE._gckind, ) else: call_del = None body = "\n".join(_static_deallocator_body_for_type("v", TYPE)) src = ( "def ll_deallocator(addr):\n v = cast_adr_to_ptr(addr, PTR_TYPE)\n" + body + "\n llop.%s_free(lltype.Void, addr)\n" % (TYPE._gckind,) ) d = { "pop_alive": LLTransformerOp(self.pop_alive), "llop": llop, "lltype": lltype, "destrptr": destrptr, "gc_header_offset": self.gcheaderbuilder.size_gc_header, "cast_adr_to_ptr": llmemory.cast_adr_to_ptr, "cast_pointer": lltype.cast_pointer, "PTR_TYPE": lltype.Ptr(TYPE), "DESTR_ARG": DESTR_ARG, "EXC_INSTANCE_TYPE": self.translator.rtyper.exceptiondata.lltype_of_exception_value, "ll_call_destructor": ll_call_destructor, "HDRPTR": lltype.Ptr(self.HDR), } exec src in d this = d["ll_deallocator"] fptr = self.annotate_finalizer(this, [llmemory.Address], lltype.Void) self.static_deallocator_funcptrs[TYPE] = fptr for p in find_gc_ptrs_in_type(TYPE): self.static_deallocation_funcptr_for_type(p.TO) return fptr
def static_deallocation_funcptr_for_type(self, TYPE): if TYPE in self.static_deallocator_funcptrs: return self.static_deallocator_funcptrs[TYPE] #print_call_chain(self) if TYPE._gckind == 'cpy': return # you don't really have an RPython deallocator for PyObjects rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] else: destrptr = None DESTR_ARG = None if destrptr is None and not find_gc_ptrs_in_type(TYPE): p = self.no_pointer_dealloc_ptr.value self.static_deallocator_funcptrs[TYPE] = p return p if destrptr is not None: body = '\n'.join(_static_deallocator_body_for_type('v', TYPE, 3)) src = """ def ll_deallocator(addr): exc_instance = llop.gc_fetch_exception(EXC_INSTANCE_TYPE) try: v = cast_adr_to_ptr(addr, PTR_TYPE) gcheader = cast_adr_to_ptr(addr - gc_header_offset, HDRPTR) # refcount is at zero, temporarily bump it to 1: gcheader.refcount = 1 destr_v = cast_pointer(DESTR_ARG, v) ll_call_destructor(destrptr, destr_v) refcount = gcheader.refcount - 1 gcheader.refcount = refcount if refcount == 0: %s llop.%s_free(lltype.Void, addr) except: pass llop.gc_restore_exception(lltype.Void, exc_instance) pop_alive(exc_instance) # XXX layering of exceptiontransform versus gcpolicy """ % (body, TYPE._gckind) else: call_del = None body = '\n'.join(_static_deallocator_body_for_type('v', TYPE)) src = ('def ll_deallocator(addr):\n v = cast_adr_to_ptr(addr, PTR_TYPE)\n' + body + '\n llop.%s_free(lltype.Void, addr)\n' % (TYPE._gckind,)) d = {'pop_alive': LLTransformerOp(self.pop_alive), 'llop': llop, 'lltype': lltype, 'destrptr': destrptr, 'gc_header_offset': self.gcheaderbuilder.size_gc_header, 'cast_adr_to_ptr': llmemory.cast_adr_to_ptr, 'cast_pointer': lltype.cast_pointer, 'PTR_TYPE': lltype.Ptr(TYPE), 'DESTR_ARG': DESTR_ARG, 'EXC_INSTANCE_TYPE': self.translator.rtyper.exceptiondata.lltype_of_exception_value, 'll_call_destructor': ll_call_destructor, 'HDRPTR':lltype.Ptr(self.HDR)} exec src in d this = d['ll_deallocator'] fptr = self.annotate_finalizer(this, [llmemory.Address], lltype.Void) self.static_deallocator_funcptrs[TYPE] = fptr for p in find_gc_ptrs_in_type(TYPE): self.static_deallocation_funcptr_for_type(p.TO) return fptr