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 self.blocks.values(): 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 op_CALL_FUNCTION_EX(self, state, inst): if inst.arg & 1: errmsg = "CALL_FUNCTION_EX with **kwargs not supported" raise UnsupportedError(errmsg) vararg = state.pop() func = state.pop() res = state.make_temp() state.append(inst, func=func, vararg=vararg, res=res) state.push(res)
def dispatch(self, state): inst = state.get_inst() _logger.debug("dispatch pc=%s, inst=%s", state._pc, inst) _logger.debug("stack %s", state._stack) fn = getattr(self, "op_{}".format(inst.opname), None) if fn is not None: fn(state, inst) else: msg = "Use of unsupported opcode (%s) found" % inst.opname raise UnsupportedError(msg, loc=self.get_debug_loc(inst.lineno))
def _guard_with_as(self, current_inst): """Checks if the next instruction after a SETUP_WITH is something other than a POP_TOP, if it is something else it'll be some sort of store which is not supported (this corresponds to `with CTXMGR as VAR(S)`).""" if current_inst.opname == "SETUP_WITH": next_op = self.bytecode[current_inst.next].opname if next_op != "POP_TOP": msg = ("The 'with (context manager) as " "(variable):' construct is not " "supported.") raise UnsupportedError(msg)
def op_POP_EXCEPT(self, state, inst): blk = state.pop_block() if blk['kind'] not in {BlockKind('EXCEPT'), BlockKind('FINALLY')}: raise UnsupportedError( "POP_EXCEPT got an unexpected block: {}".format(blk['kind']), loc=self.get_debug_loc(inst.lineno), ) state.pop() state.pop() state.pop() # Forces a new block state.fork(pc=inst.next)
def op_FORMAT_VALUE(self, state, inst): """ FORMAT_VALUE(flags): flags argument specifies format spec which is not supported yet. Currently, we just call str() on the value. Pops a value from stack and pushes results back. Required for supporting f-strings. https://docs.python.org/3/library/dis.html#opcode-FORMAT_VALUE """ if inst.arg != 0: msg = "format spec in f-strings not supported yet" raise UnsupportedError(msg, loc=self.get_debug_loc(inst.lineno)) value = state.pop() strvar = state.make_temp() res = state.make_temp() state.append(inst, value=value, res=res, strvar=strvar) state.push(res)
def op_CALL_FUNCTION_EX(self, state, inst): if inst.arg & 1 and PYVERSION != (3, 10): errmsg = "CALL_FUNCTION_EX with **kwargs not supported" raise UnsupportedError(errmsg) if inst.arg & 1: varkwarg = state.pop() else: varkwarg = None vararg = state.pop() func = state.pop() res = state.make_temp() state.append(inst, func=func, vararg=vararg, varkwarg=varkwarg, res=res) state.push(res)
def op_RAISE_VARARGS(self, state, inst): in_exc_block = any([ state.get_top_block("EXCEPT") is not None, state.get_top_block("FINALLY") is not None ]) if inst.arg == 0: exc = None if in_exc_block: raise UnsupportedError( "The re-raising of an exception is not yet supported.", loc=self.get_debug_loc(inst.lineno), ) elif inst.arg == 1: exc = state.pop() else: raise ValueError("Multiple argument raise is not supported.") state.append(inst, exc=exc) state.terminate()
def order_by_target_specificity(target, templates, fnkey=''): """This orders the given templates from most to least specific against the current "target". "fnkey" is an indicative typing key for use in the exception message in the case that there's no usable templates for the current "target". """ # No templates... return early! if templates == []: return [] from numba.core.target_extension import target_registry # fish out templates that are specific to the target if a target is # specified DEFAULT_TARGET = 'generic' usable = [] for ix, temp_cls in enumerate(templates): # ? Need to do something about this next line md = getattr(temp_cls, "metadata", {}) hw = md.get('target', DEFAULT_TARGET) if hw is not None: hw_clazz = target_registry[hw] if target.inherits_from(hw_clazz): usable.append((temp_cls, hw_clazz, ix)) # sort templates based on target specificity def key(x): return target.__mro__.index(x[1]) order = [x[0] for x in sorted(usable, key=key)] if not order: msg = (f"Function resolution cannot find any matches for function " f"'{fnkey}' for the current target: '{target}'.") from numba.core.errors import UnsupportedError raise UnsupportedError(msg) return order
def handle_unknown_opcode(self, info, inst): raise UnsupportedError("Use of unknown opcode '{}'".format( inst.opname), loc=Loc(filename=self.bytecode.func_id.filename, line=inst.lineno))
def op_POP_FINALLY(self, state, inst): # we don't emulate the exact stack behavior if inst.arg != 0: msg = ('Unsupported use of a bytecode related to try..finally' ' or a with-context') raise UnsupportedError(msg, loc=self.get_debug_loc(inst.lineno))