def flowin(self, graph, block): try: i = 0 while i < len(block.operations): op = block.operations[i] with self.bookkeeper.at_position((graph, block, i)): new_ops = op.transform(self) if new_ops is not None: block.operations[i:i+1] = new_ops if not new_ops: continue new_ops[-1].result = op.result op = new_ops[0] self.consider_op(op) i += 1 except BlockedInference as e: if e.op is block.raising_op: # this is the case where the last operation of the block will # always raise an exception which is immediately caught by # an exception handler. We then only follow the exceptional # branches. exits = [link for link in block.exits if link.exitcase is not None] elif e.op.opname in ('simple_call', 'call_args', 'next'): # XXX warning, keep the name of the call operations in sync # with the flow object space. These are the operations for # which it is fine to always raise an exception. We then # swallow the BlockedInference and that's it. # About 'next': see test_annotate_iter_empty_container(). return else: # other cases are problematic (but will hopefully be solved # later by reflowing). Throw the BlockedInference up to # processblock(). e.opindex = i raise except annmodel.HarmlesslyBlocked: return except annmodel.AnnotatorError as e: # note that UnionError is a subclass e.source = gather_error(self, graph, block, i) raise else: # dead code removal: don't follow all exits if the exitswitch # is known exits = block.exits if isinstance(block.exitswitch, Variable): s_exitswitch = self.binding(block.exitswitch) if s_exitswitch.is_constant(): exits = [link for link in exits if link.exitcase == s_exitswitch.const] if block.canraise: op = block.raising_op s_exception = self.get_exception(op) for link in exits: case = link.exitcase if case is None: self.follow_link(graph, link, {}) continue if s_exception == s_ImpossibleValue: break s_case = SomeInstance(self.bookkeeper.getuniqueclassdef(case)) s_matching_exc = intersection(s_exception, s_case) if s_matching_exc != s_ImpossibleValue: self.follow_raise_link(graph, link, s_matching_exc) s_exception = difference(s_exception, s_case) else: if isinstance(block.exitswitch, Variable): knowntypedata = getattr( block.exitswitch.annotation, "knowntypedata", {}) else: knowntypedata = {} for link in exits: constraints = knowntypedata.get(link.exitcase, {}) self.follow_link(graph, link, constraints) if block in self.notify: # reflow from certain positions when this block is done for callback in self.notify[block]: if isinstance(callback, tuple): self.reflowfromposition(callback) # callback is a position else: callback()
def flowin(self, graph, block): try: for i, op in enumerate(block.operations): self.bookkeeper.enter((graph, block, i)) try: self.consider_op(op) finally: self.bookkeeper.leave() except BlockedInference as e: if (e.op is block.operations[-1] and block.exitswitch == c_last_exception): # this is the case where the last operation of the block will # always raise an exception which is immediately caught by # an exception handler. We then only follow the exceptional # branches. exits = [link for link in block.exits if link.exitcase is not None] elif e.op.opname in ('simple_call', 'call_args', 'next'): # XXX warning, keep the name of the call operations in sync # with the flow object space. These are the operations for # which it is fine to always raise an exception. We then # swallow the BlockedInference and that's it. # About 'next': see test_annotate_iter_empty_container(). return else: # other cases are problematic (but will hopefully be solved # later by reflowing). Throw the BlockedInference up to # processblock(). e.opindex = i raise except annmodel.HarmlesslyBlocked: return except annmodel.AnnotatorError as e: # note that UnionError is a subclass e.source = gather_error(self, graph, block, i) raise else: # dead code removal: don't follow all exits if the exitswitch # is known exits = block.exits if isinstance(block.exitswitch, Variable): s_exitswitch = self.bindings[block.exitswitch] if s_exitswitch.is_constant(): exits = [link for link in exits if link.exitcase == s_exitswitch.const] # filter out those exceptions which cannot # occour for this specific, typed operation. if block.exitswitch == c_last_exception: op = block.operations[-1] if op.dispatch == 2: arg1 = self.binding(op.args[0]) arg2 = self.binding(op.args[1]) binop = getattr(pair(arg1, arg2), op.opname, None) can_only_throw = annmodel.read_can_only_throw(binop, arg1, arg2) elif op.dispatch == 1: arg1 = self.binding(op.args[0]) opname = op.opname if opname == 'contains': opname = 'op_contains' unop = getattr(arg1, opname, None) can_only_throw = annmodel.read_can_only_throw(unop, arg1) else: can_only_throw = None if can_only_throw is not None: candidates = can_only_throw candidate_exits = exits exits = [] for link in candidate_exits: case = link.exitcase if case is None: exits.append(link) continue covered = [c for c in candidates if issubclass(c, case)] if covered: exits.append(link) candidates = [c for c in candidates if c not in covered] # mapping (exitcase, variable) -> s_annotation # that can be attached to booleans, exitswitches knowntypedata = getattr(self.bindings.get(block.exitswitch), "knowntypedata", {}) for link in exits: self.follow_link(graph, link, knowntypedata) if block in self.notify: # reflow from certain positions when this block is done for callback in self.notify[block]: if isinstance(callback, tuple): self.reflowfromposition(callback) # callback is a position else: callback()
def flowin(self, graph, block): try: for i, op in enumerate(block.operations): self.bookkeeper.enter((graph, block, i)) try: self.consider_op(op) finally: self.bookkeeper.leave() except BlockedInference as e: if (e.op is block.operations[-1] and block.exitswitch == c_last_exception): # this is the case where the last operation of the block will # always raise an exception which is immediately caught by # an exception handler. We then only follow the exceptional # branches. exits = [ link for link in block.exits if link.exitcase is not None ] elif e.op.opname in ('simple_call', 'call_args', 'next'): # XXX warning, keep the name of the call operations in sync # with the flow object space. These are the operations for # which it is fine to always raise an exception. We then # swallow the BlockedInference and that's it. # About 'next': see test_annotate_iter_empty_container(). return else: # other cases are problematic (but will hopefully be solved # later by reflowing). Throw the BlockedInference up to # processblock(). e.opindex = i raise except annmodel.HarmlesslyBlocked: return except annmodel.AnnotatorError as e: # note that UnionError is a subclass e.source = gather_error(self, graph, block, i) raise else: # dead code removal: don't follow all exits if the exitswitch # is known exits = block.exits if isinstance(block.exitswitch, Variable): s_exitswitch = self.binding(block.exitswitch) if s_exitswitch.is_constant(): exits = [ link for link in exits if link.exitcase == s_exitswitch.const ] # filter out those exceptions which cannot # occour for this specific, typed operation. if block.exitswitch == c_last_exception: op = block.operations[-1] can_only_throw = op.get_can_only_throw(self) if can_only_throw is not None: candidates = can_only_throw candidate_exits = exits exits = [] for link in candidate_exits: case = link.exitcase if case is None: exits.append(link) continue covered = [c for c in candidates if issubclass(c, case)] if covered: exits.append(link) candidates = [ c for c in candidates if c not in covered ]
def flowin(self, graph, block): try: i = 0 while i < len(block.operations): op = block.operations[i] with self.bookkeeper.at_position((graph, block, i)): new_ops = op.transform(self) if new_ops is not None: block.operations[i:i + 1] = new_ops if not new_ops: continue new_ops[-1].result = op.result op = new_ops[0] self.consider_op(op) i += 1 except BlockedInference as e: if e.op is block.raising_op: # this is the case where the last operation of the block will # always raise an exception which is immediately caught by # an exception handler. We then only follow the exceptional # branches. exits = [ link for link in block.exits if link.exitcase is not None ] elif e.op.opname in ('simple_call', 'call_args', 'next'): # XXX warning, keep the name of the call operations in sync # with the flow object space. These are the operations for # which it is fine to always raise an exception. We then # swallow the BlockedInference and that's it. # About 'next': see test_annotate_iter_empty_container(). return else: # other cases are problematic (but will hopefully be solved # later by reflowing). Throw the BlockedInference up to # processblock(). e.opindex = i raise except annmodel.HarmlesslyBlocked: return except annmodel.AnnotatorError as e: # note that UnionError is a subclass e.source = gather_error(self, graph, block, i) if self.keepgoing: self.errors.append(e) self.failed_blocks.add(block) return raise else: # dead code removal: don't follow all exits if the exitswitch # is known exits = block.exits if isinstance(block.exitswitch, Variable): s_exitswitch = self.binding(block.exitswitch) if s_exitswitch.is_constant(): exits = [ link for link in exits if link.exitcase == s_exitswitch.const ] if block.canraise: op = block.raising_op s_exception = self.get_exception(op) for link in exits: case = link.exitcase if case is None: self.follow_link(graph, link, {}) continue if s_exception == s_ImpossibleValue: break s_case = SomeInstance(self.bookkeeper.getuniqueclassdef(case)) s_matching_exc = intersection(s_exception, s_case) if s_matching_exc != s_ImpossibleValue: self.follow_raise_link(graph, link, s_matching_exc) s_exception = difference(s_exception, s_case)
def flowin(self, graph, block): try: i = 0 while i < len(block.operations): op = block.operations[i] with self.bookkeeper.at_position((graph, block, i)): new_ops = op.transform(self) if new_ops is not None: block.operations[i : i + 1] = new_ops if not new_ops: continue new_ops[-1].result = op.result op = new_ops[0] self.consider_op(op) i += 1 except BlockedInference as e: if e.op is block.raising_op: # this is the case where the last operation of the block will # always raise an exception which is immediately caught by # an exception handler. We then only follow the exceptional # branches. exits = [link for link in block.exits if link.exitcase is not None] elif e.op.opname in ("simple_call", "call_args", "next"): # XXX warning, keep the name of the call operations in sync # with the flow object space. These are the operations for # which it is fine to always raise an exception. We then # swallow the BlockedInference and that's it. # About 'next': see test_annotate_iter_empty_container(). return else: # other cases are problematic (but will hopefully be solved # later by reflowing). Throw the BlockedInference up to # processblock(). e.opindex = i raise except annmodel.HarmlesslyBlocked: return except annmodel.AnnotatorError as e: # note that UnionError is a subclass e.source = gather_error(self, graph, block, i) raise else: # dead code removal: don't follow all exits if the exitswitch # is known exits = block.exits if isinstance(block.exitswitch, Variable): s_exitswitch = self.binding(block.exitswitch) if s_exitswitch.is_constant(): exits = [link for link in exits if link.exitcase == s_exitswitch.const] # filter out those exceptions which cannot # occour for this specific, typed operation. if block.canraise: op = block.raising_op can_only_throw = op.get_can_only_throw(self) if can_only_throw is not None: candidates = can_only_throw candidate_exits = exits exits = [] for link in candidate_exits: case = link.exitcase if case is None: exits.append(link) continue covered = [c for c in candidates if issubclass(c, case)] if covered: exits.append(link) candidates = [c for c in candidates if c not in covered] # mapping (exitcase, variable) -> s_annotation # that can be attached to booleans, exitswitches knowntypedata = {} if isinstance(block.exitswitch, Variable): knowntypedata = getattr(self.binding(block.exitswitch), "knowntypedata", {}) for link in exits: self.follow_link(graph, link, knowntypedata) if block in self.notify: # reflow from certain positions when this block is done for callback in self.notify[block]: if isinstance(callback, tuple): self.reflowfromposition(callback) # callback is a position else: callback()