def genswitch(self, block, v_exitswitch, false, true): block.exitswitch = v_exitswitch link_f = Link([], false) link_f.exitcase = False link_t = Link([], true) link_t.exitcase = True block.recloseblock(link_f, link_t)
def go_to_if(self, block, target, v_finished_flag): block.exitswitch = v_finished_flag [link_f] = block.exits link_t = Link([self.c_dummy], target) link_f.exitcase = False link_t.exitcase = True block.recloseblock(link_f, link_t)
def get_resume_point_link(self, block): try: return self.resumepoints[block] except KeyError: resumeblock = Block([]) redcount = 0 greencount = 0 newvars = [] for v in block.inputargs: if v.concretetype is lltype.Void: v1 = self.c_dummy elif self.hannotator.binding(v).is_green(): c = inputconst(lltype.Signed, greencount) v1 = self.genop(resumeblock, 'restore_green', [c], result_like = v) greencount += 1 else: c = inputconst(lltype.Signed, redcount) v1 = self.genop(resumeblock, 'restore_local', [c], result_like = v) redcount += 1 newvars.append(v1) resumeblock.closeblock(Link(newvars, block)) reenter_link = Link([], resumeblock) N = len(self.resumepoints) reenter_link.exitcase = N self.resumepoints[block] = reenter_link return reenter_link
def generic_exception_matching(self, afterblock, copiedexceptblock): #XXXXX don't look: insert blocks that do exception matching #for the cases where direct matching did not work exc_match = Constant( self.translator.rtyper.getexceptiondata().fn_exception_match) exc_match.concretetype = typeOf(exc_match.value) blocks = [] for i, link in enumerate(afterblock.exits[1:]): etype = copyvar(None, copiedexceptblock.inputargs[0]) evalue = copyvar(None, copiedexceptblock.inputargs[1]) passon_vars = self.passon_vars(i) block = Block([etype, evalue] + passon_vars) res = Variable() res.concretetype = Bool cexitcase = Constant(link.llexitcase) cexitcase.concretetype = typeOf(cexitcase.value) args = [exc_match, etype, cexitcase] block.operations.append(SpaceOperation("direct_call", args, res)) block.exitswitch = res linkargs = self.find_args_in_exceptional_case(link, link.target, etype, evalue, afterblock, passon_vars) l = Link(linkargs, link.target) l.prevblock = block l.exitcase = True l.llexitcase = True block.closeblock(l) if i > 0: l = Link(blocks[-1].inputargs, block) l.exitcase = False l.llexitcase = False blocks[-1].recloseblock(l, *blocks[-1].exits) blocks.append(block) blocks[-1].recloseblock(*blocks[-1].exits[:1]) blocks[-1].operations = [] blocks[-1].exitswitch = None blocks[-1].exits[0].exitcase = None del blocks[-1].exits[0].llexitcase linkargs = copiedexceptblock.inputargs copiedexceptblock.recloseblock(Link(linkargs, blocks[0])) copiedexceptblock.operations += self.generate_keepalive(linkargs)
def handle_after_residual_call_details(self, block, pos, newops, blockset, withexc, oop = False): dopts = {'withexc': withexc, 'oop': oop } copts = Constant(dopts, lltype.Void) v_flags = self.genop(newops, 'after_residual_call', [copts], resulttype=lltype.Signed, red=True) residual_fetch_index = len(newops) self.genop(newops, 'residual_fetch', [v_flags, copts]) residual_fetch_pos = pos+residual_fetch_index block.operations[pos:pos+1] = newops link_t = split_block(self.hannotator, block, residual_fetch_pos) nextblock = link_t.target blockset[nextblock] = False i_flags = link_t.args.index(v_flags) reds, greens = self.sort_by_color(link_t.args) self.genop(block, 'save_locals', reds) SPLIT_FOR_ZERO = False if SPLIT_FOR_ZERO: promoteblock = Block([copyvar(self.hannotator, v) for v in link_t.args]) link_f = Link(link_t.args, promoteblock) promoteblock.recloseblock(Link(promoteblock.inputargs, nextblock)) blockset[promoteblock] = False v_flags2 = promoteblock.inputargs[i_flags] else: promoteblock = block v_flags2 = v_flags # if there is no global merge point, this 'promote' will actually # always see a constant red box v_finished_flag = self.genop(promoteblock, 'promote', [v_flags2], resulttype = lltype.Bool) self.go_to_dispatcher_if(promoteblock, v_finished_flag) if SPLIT_FOR_ZERO: c_zero = inputconst(lltype.Signed, 0) link_t.args = link_t.args[:] link_t.args[i_flags] = c_zero resumepoint = self.get_resume_point(promoteblock) c_resumepoint = inputconst(lltype.Signed, resumepoint) v_is_zero = self.genop(block, 'int_eq', [v_flags, c_zero], resulttype=lltype.Bool, red=True) v_is_zero = self.genop(block, 'split', [v_is_zero, c_resumepoint] + greens, resulttype = lltype.Bool) block.exitswitch = v_is_zero link_t.exitcase = True link_f.exitcase = False block.recloseblock(link_f, link_t)
def insert_integer_search(self, block, cases, defaultlink, blockset, range_start, range_stop): # fix the exit of the 'block' to check for the given remaining # 'cases', knowing that if we get there then the value must # be contained in range(range_start, range_stop). if not cases: assert defaultlink is not None block.exitswitch = None block.recloseblock(Link(defaultlink.args, defaultlink.target)) elif len(cases) == 1 and (defaultlink is None or range_start == range_stop-1): block.exitswitch = None block.recloseblock(cases.values()[0]) else: intvalues = cases.keys() intvalues.sort() if len(intvalues) <= 3: # not much point in being clever with no more than 3 cases intval = intvalues[-1] remainingcases = cases.copy() link = remainingcases.pop(intval) c_intval = inputconst(lltype.Signed, intval) v = self.genop(block, 'int_eq', [block.exitswitch, c_intval], resulttype=lltype.Bool, red=True) link.exitcase = True link.llexitcase = True falseblock = Block([]) falseblock.exitswitch = block.exitswitch blockset[falseblock] = False falselink = Link([], falseblock) falselink.exitcase = False falselink.llexitcase = False block.exitswitch = v block.recloseblock(falselink, link) if defaultlink is None or intval == range_stop-1: range_stop = intval self.insert_integer_search(falseblock, remainingcases, defaultlink, blockset, range_start, range_stop) else: intval = intvalues[len(intvalues) // 2] c_intval = inputconst(lltype.Signed, intval) v = self.genop(block, 'int_ge', [block.exitswitch, c_intval], resulttype=lltype.Bool, red=True) falseblock = Block([]) falseblock.exitswitch = block.exitswitch trueblock = Block([]) trueblock.exitswitch = block.exitswitch blockset[falseblock] = False blockset[trueblock] = False falselink = Link([], falseblock) falselink.exitcase = False falselink.llexitcase = False truelink = Link([], trueblock) truelink.exitcase = True truelink.llexitcase = True block.exitswitch = v block.recloseblock(falselink, truelink) falsecases = {} truecases = {} for intval1, link1 in cases.items(): if intval1 < intval: falsecases[intval1] = link1 else: truecases[intval1] = link1 self.insert_integer_search(falseblock, falsecases, defaultlink, blockset, range_start, intval) self.insert_integer_search(trueblock, truecases, defaultlink, blockset, intval, range_stop)
def tweak_generator_body_graph(Entry, graph): # First, always run simplify_graph in order to reduce the number of # variables passed around simplify_graph(graph) # assert graph.startblock.operations[0].opname == 'generator_mark' graph.startblock.operations.pop(0) # insert_empty_startblock(None, graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) v0 = Variable(); v1 = Variable() stopblock.operations = [ SpaceOperation('simple_call', [Constant(StopIteration)], v0), SpaceOperation('type', [v0], v1), ] stopblock.closeblock(Link([v1, v0], graph.exceptblock)) # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: exit.args = [] exit.target = stopblock assert block is not stopblock for index in range(len(block.operations)-1, -1, -1): op = block.operations[index] if op.opname == 'yield': [v_yielded_value] = op.args del block.operations[index] newlink = split_block(None, block, index) newblock = newlink.target # class Resume(AbstractPosition): _immutable_ = True block = newblock Resume.__name__ = 'Resume%d' % len(mappings) mappings.append(Resume) varnames = get_variable_names(newlink.args) # _insert_reads(newblock, varnames) # v_resume = Variable('resume') block.operations.append( SpaceOperation('simple_call', [Constant(Resume)], v_resume)) for i, name in enumerate(varnames): block.operations.append( SpaceOperation('setattr', [v_resume, Constant(name), newlink.args[i]], Variable())) v_pair = Variable('pair') block.operations.append( SpaceOperation('newtuple', [v_resume, v_yielded_value], v_pair)) newlink.args = [v_pair] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: v_check = Variable() block.operations.append( SpaceOperation('simple_call', [Constant(isinstance), block.inputargs[0], Constant(Resume)], v_check)) block.exitswitch = v_check link1 = Link([block.inputargs[0]], Resume.block) link1.exitcase = True nextblock = Block([Variable('entry')]) link2 = Link([block.inputargs[0]], nextblock) link2.exitcase = False block.closeblock(link1, link2) block = nextblock block.closeblock(Link([Constant(AssertionError), Constant(AssertionError("bad generator class"))], graph.exceptblock)) graph.startblock = regular_entry_block graph.signature = Signature(['entry']) graph.defaults = () checkgraph(graph) eliminate_empty_blocks(graph)
def tweak_generator_body_graph(Entry, graph): # First, always run simplify_graph in order to reduce the number of # variables passed around simplify_graph(graph) # assert graph.startblock.operations[0].opname == 'generator_mark' graph.startblock.operations.pop(0) # insert_empty_startblock(None, graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) v0 = Variable() v1 = Variable() stopblock.operations = [ SpaceOperation('simple_call', [Constant(StopIteration)], v0), SpaceOperation('type', [v0], v1), ] stopblock.closeblock(Link([v1, v0], graph.exceptblock)) # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: exit.args = [] exit.target = stopblock assert block is not stopblock for index in range(len(block.operations) - 1, -1, -1): op = block.operations[index] if op.opname == 'yield': [v_yielded_value] = op.args del block.operations[index] newlink = split_block(None, block, index) newblock = newlink.target # class Resume(AbstractPosition): _immutable_ = True block = newblock Resume.__name__ = 'Resume%d' % len(mappings) mappings.append(Resume) varnames = get_variable_names(newlink.args) # _insert_reads(newblock, varnames) # v_resume = Variable('resume') block.operations.append( SpaceOperation('simple_call', [Constant(Resume)], v_resume)) for i, name in enumerate(varnames): block.operations.append( SpaceOperation( 'setattr', [v_resume, Constant(name), newlink.args[i]], Variable())) v_pair = Variable('pair') block.operations.append( SpaceOperation('newtuple', [v_resume, v_yielded_value], v_pair)) newlink.args = [v_pair] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: v_check = Variable() block.operations.append( SpaceOperation( 'simple_call', [Constant(isinstance), block.inputargs[0], Constant(Resume)], v_check)) block.exitswitch = v_check link1 = Link([block.inputargs[0]], Resume.block) link1.exitcase = True nextblock = Block([Variable('entry')]) link2 = Link([block.inputargs[0]], nextblock) link2.exitcase = False block.closeblock(link1, link2) block = nextblock block.closeblock( Link([ Constant(AssertionError), Constant(AssertionError("bad generator class")) ], graph.exceptblock)) graph.startblock = regular_entry_block graph.signature = Signature(['entry']) graph.defaults = () checkgraph(graph) eliminate_empty_blocks(graph)