def kill_assertion_link(graph, link): block = link.prevblock exits = list(block.exits) if len(exits) <= 1: return False remove_condition = len(exits) == 2 if block.exitswitch == c_last_exception: if link is exits[0]: return False # cannot remove the non-exceptional path else: if block.exitswitch.concretetype is not lltype.Bool: # a switch remove_condition = False else: # common case: if <cond>: raise AssertionError # turn it into a debug_assert operation assert remove_condition newops = LowLevelOpList() if link.exitcase: v = newops.genop('bool_not', [block.exitswitch], resulttype=lltype.Bool) else: v = block.exitswitch msg = "assertion failed in %s" % (graph.name, ) c_msg = inputconst(lltype.Void, msg) newops.genop('debug_assert', [v, c_msg]) block.operations.extend(newops) exits.remove(link) if remove_condition: # condition no longer necessary block.exitswitch = None exits[0].exitcase = None exits[0].llexitcase = None block.recloseblock(*exits) return True
def kill_assertion_link(graph, link): block = link.prevblock exits = list(block.exits) if len(exits) <= 1: return False remove_condition = len(exits) == 2 if block.canraise: if link is exits[0]: return False # cannot remove the non-exceptional path else: if block.exitswitch.concretetype is not lltype.Bool: # a switch remove_condition = False else: # common case: if <cond>: raise AssertionError # turn it into a debug_assert operation assert remove_condition newops = LowLevelOpList() if link.exitcase: v = newops.genop('bool_not', [block.exitswitch], resulttype=lltype.Bool) else: v = block.exitswitch msg = "assertion failed in %s" % (graph.name,) c_msg = inputconst(lltype.Void, msg) newops.genop('debug_assert', [v, c_msg]) block.operations.extend(newops) exits.remove(link) if remove_condition: # condition no longer necessary block.exitswitch = None exits[0].exitcase = None exits[0].llexitcase = None block.recloseblock(*exits) return True
def transform_graph(self, graph): if graph in self.minimal_transform: if self.minimalgctransformer: self.minimalgctransformer.transform_graph(graph) self.minimal_transform.remove(graph) return if graph in self.seen_graphs: return self.seen_graphs.add(graph) self.links_to_split = {} # link -> vars to pop_alive across the link # for sanity, we need an empty block at the start of the graph inserted_empty_startblock = False if not starts_with_empty_block(graph): insert_empty_startblock(graph) inserted_empty_startblock = True is_borrowed = self.compute_borrowed_vars(graph) try: for block in graph.iterblocks(): self.transform_block(block, is_borrowed) except GCTransformError as e: e.args = ('[function %s]: %s' % (graph.name, e.message),) raise for link, livecounts in self.links_to_split.iteritems(): llops = LowLevelOpList() for var, livecount in livecounts.iteritems(): for i in range(livecount): self.pop_alive(var, llops) for i in range(-livecount): self.push_alive(var, llops) if llops: if link.prevblock.exitswitch is None: link.prevblock.operations.extend(llops) else: insert_empty_block(link, llops) # remove the empty block at the start of the graph, which should # still be empty (but let's check) if starts_with_empty_block(graph) and inserted_empty_startblock: old_startblock = graph.startblock graph.startblock = graph.startblock.exits[0].target checkgraph(graph) self.links_to_split = None v = Variable('vanishing_exc_value') v.concretetype = self.get_lltype_of_exception_value() llops = LowLevelOpList() self.pop_alive(v, llops) graph.exc_cleanup = (v, list(llops)) return is_borrowed # xxx for tests only
def transform_block(self, block, is_borrowed): llops = LowLevelOpList() self.curr_block = block self.livevars = [ var for var in block.inputargs if var_needsgc(var) and not is_borrowed(var) ] allvars = [var for var in block.getvariables() if var_needsgc(var)] self.var_last_needed_in = dict.fromkeys(allvars, 0) for i, op in enumerate(block.operations): for var in op.args: if not var_needsgc(var): continue self.var_last_needed_in[var] = i for link in block.exits: for var in link.args: if not var_needsgc(var): continue self.var_last_needed_in[var] = len(block.operations) + 1 for i, op in enumerate(block.operations): hop = GcHighLevelOp(self, op, i, llops) hop.dispatch() if len(block.exits) != 0: # i.e not the return block assert not block.canraise deadinallexits = set(self.livevars) for link in block.exits: deadinallexits.difference_update(set(link.args)) for var in deadinallexits: self.pop_alive(var, llops) for link in block.exits: livecounts = dict.fromkeys( set(self.livevars) - deadinallexits, 1) for v, v2 in zip(link.args, link.target.inputargs): if is_borrowed(v2): continue if v in livecounts: livecounts[v] -= 1 elif var_needsgc(v): # 'v' is typically a Constant here, but it can be # a borrowed variable going into a non-borrowed one livecounts[v] = -1 self.links_to_split[link] = livecounts block.operations[:] = llops self.livevars = None self.var_last_needed_in = None self.curr_block = None
def write_barrier_check(spaceop, needs_write_barrier=True): t = TranslationContext() t.buildannotator().build_types(lambda x:x, [SomeInteger()]) t.buildrtyper().specialize() transformer = WriteBarrierTransformer(t) llops = LowLevelOpList() hop = GcHighLevelOp(transformer, spaceop, 0, llops) hop.dispatch() found = False print spaceop, '======>' for op in llops: print '\t', op if op.opname == 'direct_call': found = True assert found == needs_write_barrier
def generate_exception_match(self, oplist, var_etype, const_etype): # generate the content of rclass.ll_issubclass(_const) from rpython.rtyper.rtyper import LowLevelOpList from rpython.rtyper.lltypesystem import lltype from rpython.flowspace.model import Constant, Variable, SpaceOperation llops = LowLevelOpList(None) field = llops.genop( 'getfield', [var_etype, llops.genvoidconst('subclassrange_min')], lltype.Signed) res = llops.genop('int_between', [ llops.genconst(const_etype.value.subclassrange_min), field, llops.genconst(const_etype.value.subclassrange_max), ], lltype.Bool) oplist.extend(llops) return res