def _get_return_vars(self): rets = [] for blk in utils.itervalues(self.blocks): inst = blk.terminator if isinstance(inst, ir.Return): rets.append(inst.value) return rets
def seed_return(self, typ): """Seeding of return value is optional. """ for blk in utils.itervalues(self.blocks): inst = blk.terminator if isinstance(inst, ir.Return): self.typevars[inst.value.name].lock(typ)
def run(self): for inst in self._iter_inst(): fname = "op_%s" % inst.opname fn = getattr(self, fname, None) if fn is not None: fn(inst) elif inst.is_jump: # this catches e.g. try... except l = Loc(self.bytecode.func_id.filename, inst.lineno) if inst.opname in {"SETUP_EXCEPT", "SETUP_FINALLY"}: msg = "'try' block not supported until python3.7 or later" else: msg = "Use of unsupported opcode (%s) found" % inst.opname raise UnsupportedError(msg, loc=l) else: # Non-jump instructions are ignored pass # intentionally # Close all blocks for cur, nxt in zip(self.blockseq, self.blockseq[1:]): blk = self.blocks[cur] if not blk.outgoing_jumps and not blk.terminating: blk.outgoing_jumps[nxt] = 0 graph = CFGraph() for b in self.blocks: graph.add_node(b) for b in self.blocks.values(): for out, pops in b.outgoing_jumps.items(): graph.add_edge(b.offset, out, pops) graph.set_entry_point(min(self.blocks)) graph.process() self.graph = graph # Fill incoming for b in utils.itervalues(self.blocks): for out, pops in b.outgoing_jumps.items(): self.blocks[out].incoming_jumps[b.offset] = pops # Find liveblocks self.liveblocks = dict((i, self.blocks[i]) for i in self.graph.nodes()) for lastblk in reversed(self.blockseq): if lastblk in self.liveblocks: break else: raise AssertionError("No live block that exits!?") # Find backbone backbone = self.graph.backbone() # Filter out in loop blocks (Assuming no other cyclic control blocks) # This is to unavoid variable defined in loops to be considered as # function scope. inloopblocks = set() for b in self.blocks.keys(): if self.graph.in_loops(b): inloopblocks.add(b) self.backbone = backbone - inloopblocks
def run(self): for inst in self._iter_inst(): fname = "op_%s" % inst.opname fn = getattr(self, fname, None) if fn is not None: fn(inst) else: # this catches e.g. try... except if inst.is_jump: l = Loc(self.bytecode.func_id.filename, inst.lineno) msg = "Use of unsupported opcode (%s) found" % inst.opname raise UnsupportedError(msg, loc=l) # Close all blocks for cur, nxt in zip(self.blockseq, self.blockseq[1:]): blk = self.blocks[cur] if not blk.outgoing_jumps and not blk.terminating: blk.outgoing_jumps[nxt] = 0 graph = CFGraph() for b in self.blocks: graph.add_node(b) for b in self.blocks.values(): for out, pops in b.outgoing_jumps.items(): graph.add_edge(b.offset, out, pops) graph.set_entry_point(min(self.blocks)) graph.process() self.graph = graph # Fill incoming for b in utils.itervalues(self.blocks): for out, pops in b.outgoing_jumps.items(): self.blocks[out].incoming_jumps[b.offset] = pops # Find liveblocks self.liveblocks = dict((i, self.blocks[i]) for i in self.graph.nodes()) for lastblk in reversed(self.blockseq): if lastblk in self.liveblocks: break else: raise AssertionError("No live block that exits!?") # Find backbone backbone = self.graph.backbone() # Filter out in loop blocks (Assuming no other cyclic control blocks) # This is to unavoid variable defined in loops to be considered as # function scope. inloopblocks = set() for b in self.blocks.keys(): for s, e in self._loops: if s <= b < e: inloopblocks.add(b) self.backbone = backbone - inloopblocks
def get_return_type(self, typemap): rettypes = set() for blk in utils.itervalues(self.blocks): term = blk.terminator if isinstance(term, ir.Return): rettypes.add(typemap[term.value.name]) if rettypes: return self.context.unify_types(*rettypes) else: return types.none
def run(self): for inst in self._iter_inst(): fname = "op_%s" % inst.opname fn = getattr(self, fname, None) if fn is not None: fn(inst) else: assert not inst.is_jump, inst # Close all blocks for cur, nxt in zip(self.blockseq, self.blockseq[1:]): blk = self.blocks[cur] if not blk.outgoing_jumps and not blk.terminating: blk.outgoing_jumps[nxt] = 0 graph = CFGraph() for b in self.blocks: graph.add_node(b) for b in self.blocks.values(): for out, pops in b.outgoing_jumps.items(): graph.add_edge(b.offset, out, pops) graph.set_entry_point(min(self.blocks)) graph.process() self.graph = graph # Fill incoming for b in utils.itervalues(self.blocks): for out, pops in b.outgoing_jumps.items(): self.blocks[out].incoming_jumps[b.offset] = pops # Find liveblocks self.liveblocks = dict((i, self.blocks[i]) for i in self.graph.nodes()) for lastblk in reversed(self.blockseq): if lastblk in self.liveblocks: break else: raise AssertionError("No live block that exits!?") # Find backbone backbone = self.graph.backbone() # Filter out in loop blocks (Assuming no other cyclic control blocks) # This is to unavoid variable defined in loops to be considered as # function scope. inloopblocks = set() for b in self.blocks.keys(): for s, e in self._loops: if s <= b < e: inloopblocks.add(b) self.backbone = backbone - inloopblocks
def get_return_type(self, typemap): rettypes = set() for blk in utils.itervalues(self.blocks): term = blk.terminator if isinstance(term, ir.Return): rettypes.add(typemap[term.value.name]) if rettypes: unified = self.context.unify_types(*rettypes) if unified is types.pyobject: raise TypingError("Can't unify return type from the " "following types: %s" % ", ".join(sorted(map(str, rettypes)))) return unified else: return types.none
def get_return_type(self, typemap): rettypes = set() for blk in utils.itervalues(self.blocks): term = blk.terminator if isinstance(term, ir.Return): rettypes.add(typemap[term.value.name]) if types.none in rettypes: # Special case None return rettypes = rettypes - set([types.none]) if rettypes: unified = self.context.unify_types(*rettypes) return types.Optional(unified) else: return types.none elif rettypes: unified = self.context.unify_types(*rettypes) return unified else: return types.none
def run_block(self, blk): tempassign = {} removeset = set() for offset, inst in enumerate(blk.body): self.mark_asssignment(tempassign, offset, inst) for bag in utils.itervalues(tempassign): if len(bag) == 2: off1, off2 = bag first = blk.body[off1] second = blk.body[off2] inst = ir.Assign(value=first.value, target=second.target, loc=first.loc) # Replacement the second instruction blk.body[off2] = inst # Remove the first removeset.add(off1) # Remove from the highest offset to the lowest to preserve order for off in reversed(sorted(removeset)): del blk.body[off]
def get_state_token(self): """The algorithm is monotonic. It can only grow the typesets. The sum of all lengths of type sets is a cheap and accurate description of our progress. """ return sum(len(tv) for tv in utils.itervalues(self.typevars))
def __iter__(self): return utils.itervalues(self.table)
def build_constrain(self): for blk in utils.itervalues(self.blocks): for inst in blk.body: self.constrain_statement(inst)
def dump(self): for blk in utils.itervalues(self.infos): blk.dump()