Exemplo n.º 1
0
    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
Exemplo n.º 2
0
 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)
Exemplo n.º 3
0
 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))
Exemplo n.º 4
0
 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)
Exemplo n.º 5
0
 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)
Exemplo n.º 6
0
 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)
Exemplo n.º 7
0
 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)
Exemplo n.º 8
0
 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()
Exemplo n.º 9
0
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
Exemplo n.º 10
0
 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))
Exemplo n.º 11
0
 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))