Exemplo n.º 1
0
    def __exit__(self, *args):
        frame = self._get_context_frame()
        retcode = super(namespace, self).__exit__(*args)
        # funcode = copy.deepcopy(self.bytecode)
        funcode = copy.copy(self.bytecode)
        #  Ensure it's a properly formed func by always returning something
        funcode.append(bytecode.Instr('LOAD_CONST', None))
        funcode.append(bytecode.Instr('RETURN_VALUE'))
        #  Switch LOAD/STORE/DELETE_FAST/NAME to LOAD/STORE/DELETE_ATTR
        to_replace = []
        for i, instr in enumerate(funcode):
            repl = self._replace_opcode(instr, frame)
            if repl:
                to_replace.append((i, repl))
        offset = 0
        for i, repl in to_replace:
            funcode[i + offset:i + offset + 1] = repl
            offset += len(repl) - 1
        #  Create function object to do the manipulation
        funcode.argnames = ("_[namespace]", )
        funcode.argcount = 1
        funcode.name = "<withhack>"
        gs = self._get_context_frame().f_globals
        func = types.FunctionType(funcode.to_code(), gs)
        #  Execute bytecode in context of namespace
        retval = func(self.namespace)

        self._run_as_clause(self.namespace)

        return retcode
Exemplo n.º 2
0
    def __exit__(self, *args):
        self.test_frames = inspect.getouterframes(inspect.currentframe())
        # from IPython.core.debugger import set_trace; set_trace()

        retcode = super(CacheLocals, self).__exit__(*args)

        funcode = copy.copy(self.bytecode)
        funcode.append(bytecode.Instr('LOAD_CONST', None))
        funcode.append(bytecode.Instr('RETURN_VALUE'))
        frame = self._get_context_frame()
        change_lookups(funcode, locals_=frame.f_locals)

        # self.source = inspect.getsource(funcode.to_code())

        assigned_locals = {}
        for i, instr in enumerate(funcode):
            if getattr(instr, 'name', None) in ('STORE_FAST', 'STORE_NAME'):
                # TODO: Could we use the code leading up to a variable as a
                # hash?
                assigned_locals[instr.arg] = bytecode.Bytecode(funcode[:i + 1])

        self._get_cached(funcode.to_code(), assigned_locals)
        self.assigned_locals = assigned_locals

        return retcode
Exemplo n.º 3
0
    def __exit__(self, *args):
        frame = self._get_context_frame()
        retcode = super(CaptureFunction, self).__exit__(*args)
        funcode = copy.copy(self.bytecode)
        #  Ensure it's a properly formed func by always returning something
        funcode.append(bytecode.Instr('LOAD_CONST', None))
        funcode.append(bytecode.Instr('RETURN_VALUE'))
        change_lookups(funcode, args=self.__args, locals_=frame.f_locals)

        #  Create the resulting function object
        # funcode.args = self.__args
        # funcode.varargs = self.__varargs
        # funcode.varkwargs = self.__varkwargs
        funcode.name = self.__name
        funcode.argnames = self.__args
        funcode.argcount = len(self.__args)
        if self.__varargs:
            funcode.flags |= inspect.CO_VARARGS
            funcode.argcount -= 1
        if self.__varkwargs:
            funcode.flags |= inspect.CO_VARKEYWORDS
            funcode.argcount -= 1

        gs = self._get_context_frame().f_globals
        nm = self.__name
        defs = self.__argdefs
        self.function = types.FunctionType(funcode.to_code(), gs, nm, defs)
        return retcode
Exemplo n.º 4
0
    def _replace_opcode(
            self,
            instr,
            frame,
            *,
            _load=lambda i: [bytecode.Instr('LOAD_ATTR', i.arg)],
            _store=lambda i: [bytecode.Instr('STORE_ATTR', i.arg)],
            _delete=lambda i: [bytecode.Instr('DELETE_ATTR', i.arg)],
            _exc=AttributeError):
        Instr = bytecode.Instr
        Label = bytecode.Label

        if instr.name in (
                'STORE_FAST',
                'STORE_NAME',
        ):
            return [Instr('LOAD_FAST', "_[namespace]")] + _store(instr)
        if instr.name in (
                'DELETE_FAST',
                'DELETE_NAME',
        ):
            return [Instr('LOAD_FAST', "_[namespace]")] + _delete(instr)
        if instr.name in ('LOAD_FAST', 'LOAD_NAME', 'LOAD_GLOBAL',
                          'LOAD_DEREF'):
            excIn = Label()
            excOut = Label()
            end = Label()
            # try:
            #     x = namespace.<attr>
            # except AttributeError:
            #     x = load_name(frame, '<attr>')
            return [
                Instr('SETUP_EXCEPT', excIn),
                Instr('LOAD_FAST', "_[namespace]")
            ] + _load(instr) + [
                Instr('STORE_FAST', "_[ns_value]"),
                Instr('POP_BLOCK'),
                Instr('JUMP_FORWARD', end), excIn,
                Instr('DUP_TOP'),
                Instr('LOAD_CONST', _exc),
                Instr('COMPARE_OP', bytecode.Compare.EXC_MATCH),
                Instr('POP_JUMP_IF_FALSE', excOut),
                Instr('POP_TOP'),
                Instr('POP_TOP'),
                Instr('POP_TOP'),
                Instr('LOAD_CONST', load_name),
                Instr('LOAD_CONST', frame),
                Instr('LOAD_CONST', instr.arg),
                Instr('CALL_FUNCTION', 2),
                Instr('STORE_FAST', "_[ns_value]"),
                Instr('POP_EXCEPT'),
                Instr('JUMP_FORWARD', end), excOut,
                Instr('END_FINALLY'), end,
                Instr('LOAD_FAST', "_[ns_value]")
            ]
        return None
Exemplo n.º 5
0
    def try_squash_raise(self):
        """ A context manager for squashing tracebacks.

        The code written during this context will be wrapped so that
        any exception raised will appear to have been generated from
        the code, rather than any function called by the code.

        """
        exc_label = bc.Label()
        end_label = bc.Label()
        op_code = "SETUP_FINALLY" if PY38 else "SETUP_EXCEPT"
        self.code_ops.append(
            bc.Instr(op_code, exc_label),         # TOS
        )
        yield
        self.code_ops.extend([                           # TOS
            bc.Instr("POP_BLOCK"),                       # TOS
            bc.Instr("JUMP_FORWARD", end_label),         # TOS
            exc_label,                                   # TOS -> tb -> val -> exc
            bc.Instr("ROT_THREE"),                       # TOS -> exc -> tb -> val
            bc.Instr("ROT_TWO"),                         # TOS -> exc -> val -> tb
            bc.Instr("POP_TOP"),                         # TOS -> exc -> val
            bc.Instr("RAISE_VARARGS", 2),                # TOS
            bc.Instr("JUMP_FORWARD", end_label),         # TOS
            bc.Instr("END_FINALLY"),                     # TOS
            end_label,                                   # TOS
        ])
Exemplo n.º 6
0
    def build_tuple(self, n=0):
        """ Build a tuple from items on the TOS.

        """
        if n == 0:
            self.code_ops.append(                       # TOS
                bc.Instr("LOAD_CONST", ()),             # TOS -> tuple
            )
        else:
            self.code_ops.append(                       # TOS
                bc.Instr("BUILD_TUPLE", n),             # TOS -> tuple
            )
Exemplo n.º 7
0
    def _run_as_clause(self, value):
        """
        Run the as clause, setting the target expression to `value`

        This handles arbitrary as clause expressions, like

            with somehack as d['item'][i].foo().bar:
                pass
        """
        assert self._as_clause

        if len(self._as_clause) == 1:
            first = self._as_clause[0]
            # store_fast has to be handled specially
            if first.name == 'STORE_FAST':
                self._set_context_locals({first.arg: value})
                return
            # pop_top is a no-op
            elif first.name == 'POP_TOP':
                return

        # if somehow there's a STORE_FAST in there, it's not going to work
        if any(instr.name == 'STORE_FAST' for instr in self._as_clause):
            raise NotImplementedError("Cannot handle this as clause")

        frame = self._get_context_frame()

        # prepend a LOAD_CONST with a dummy value
        dummy = object()
        code = copy.copy(self._as_clause)
        code[:0] = [bytecode.Instr('LOAD_CONST', dummy)]
        code.extend([
            bytecode.Instr('LOAD_CONST', None),
            bytecode.Instr('RETURN_VALUE')
        ])

        # configure the object
        code.argcount = 0
        code.name = '<as clause>'
        code.flags &= ~inspect.CO_NEWLOCALS

        # fiddle with variable lookups
        change_lookups(code, locals_=frame.f_locals)

        # now swap out the constant (which would be rejected by to_concrete_bytecode)
        concrete_code = code.to_concrete_bytecode()
        concrete_code.consts[concrete_code.consts.index(dummy)] = value

        # run the assignment in the context frame
        raw_code = concrete_code.to_code()
        exec(raw_code, frame.f_globals, frame.f_locals)
Exemplo n.º 8
0
def run_in_dynamic_scope(code, global_vars):
    """Wrap functions defined in operators/decl func to run them in the proper
    dynamic scope.

    This will also rewrite the function to convert each LOAD_GLOBAL opcode
    into a LOAD_NAME opcode, unless the associated name is known to have been
    made global via the 'global' keyword.

    Parameters
    ----------
    code : bytecode.Bytecode
        Code object in which functions are defined.

    """
    # Code generator used to modify the bytecode
    cg = CodeGenerator()
    fetch_helpers(cg)

    # Scan all ops to detect function call after GET_ITER
    for instr in code:
        if not isinstance(instr, bc.Instr):
            cg.code_ops.append(instr)
            continue
        i_name, i_arg = instr.name, instr.arg
        if isinstance(i_arg, CodeType):
            # Allow to pass the dynamic scope as locals. There is no need
            # to copy it as internal variables are stored in fast locals
            # and hence does not affect the scope content.
            inner = bc.Bytecode.from_code(i_arg)
            inner.flags ^= (inner.flags & bc.CompilerFlags.NEWLOCALS)
            # Set the NESTED flag since even though we may have obtained the
            # outer code from an expr it will run as a function.
            inner.flags |= bc.CompilerFlags.NESTED
            run_in_dynamic_scope(inner, global_vars)
            inner.update_flags()
            i_arg = inner.to_code()
        elif any(i_name == make_fun_op for make_fun_op in _MAKE_FUNC):
            cg.code_ops.append(bc.Instr(i_name, i_arg))  # func
            load_helper(cg, 'wrap_func')  # func -> wrap
            cg.rot_two()  # wrap -> func
            cg.load_global('__scope__')  # wrap -> func -> scope
            cg.call_function(2)  # wrapped
            continue

        cg.code_ops.append(bc.Instr(i_name, i_arg))

    del code[:]
    code.extend(cg.code_ops)
    rewrite_globals_access(code, global_vars)
    code.update_flags()
Exemplo n.º 9
0
    def rot_three(self):
        """ Rotate the three values on the TOS.

        """
        self.code_ops.append(                           # TOS -> val_1 -> val_2 -> val_3
            bc.Instr("ROT_THREE"),                      # TOS -> val_3 -> val_1 -> val_2
        )
Exemplo n.º 10
0
    def rot_two(self):
        """ Rotate the two values on the TOS.

        """
        self.code_ops.append(                           # TOS -> val_1 -> val_2
            bc.Instr("ROT_TWO"),                        # TOS -> val_2 -> val_1
        )
Exemplo n.º 11
0
    def pop_top(self):
        """ Pop the value from the TOS.

        """
        self.code_ops.append(                           # TOS -> value
            bc.Instr("POP_TOP"),                        # TOS
        )
Exemplo n.º 12
0
    def make_function(self, n_defaults=0):
        """ Make a function from a code object on the TOS.

        """
        self.code_ops.append(                           # TOS -> qual_name -> code -> defaults
            bc.Instr("MAKE_FUNCTION", n_defaults),      # TOS -> func
        )
Exemplo n.º 13
0
    def load_build_class(self):
        """ Build a class from the top 3 stack items.

        """
        self.code_ops.append(                           # TOS
            bc.Instr("LOAD_BUILD_CLASS"),               # TOS -> builtins.__build_class__
        )
Exemplo n.º 14
0
    def delete_fast(self, name):
        """ Delete a named fast local variable.

        """
        self.code_ops.append(                           # TOS
            bc.Instr("DELETE_FAST", name),                     # TOS
        )
Exemplo n.º 15
0
    def store_attr(self, name):
        """ Store the value at 2nd as an attr on 1st.

        """
        self.code_ops.append(                           # TOS -> val -> obj
            bc.Instr("STORE_ATTR", name),               # TOS
        )
Exemplo n.º 16
0
    def build_map(self, n=0):
        """ Build a map and store it onto the TOS.

        """
        self.code_ops.append(                           # TOS
            bc.Instr("BUILD_MAP", n),                   # TOS -> map
        )
Exemplo n.º 17
0
    def dup_top(self):
        """ Duplicate the value on the TOS.

        """
        self.code_ops.append(                           # TOS -> value
            bc.Instr("DUP_TOP"),                        # TOS -> value -> value
        )
Exemplo n.º 18
0
    def binary_add(self):
        """ Multiple the 2 items on the TOS.

        """
        self.code_ops.append(                           # TOS -> val_1 -> val_2
            bc.Instr("BINARY_ADD"),                     # TOS -> retval
        )
Exemplo n.º 19
0
    def binary_multiply(self):
        """ Multiple the 2 items on the TOS.

        """
        self.code_ops.append(                           # TOS -> val_1 -> val_2
            bc.Instr("BINARY_MULTIPLY"),                # TOS -> retval
        )
Exemplo n.º 20
0
    def binary_subscr(self):
        """ Subscript the #2 item with the TOS.

        """
        self.code_ops.append(                           # TOS -> obj -> idx
            bc.Instr("BINARY_SUBSCR"),                  # TOS -> value
        )
Exemplo n.º 21
0
    def return_value(self):
        """ Return the value from the TOS.

        """
        self.code_ops.append(                           # TOS -> value
            bc.Instr("RETURN_VALUE"),                   # TOS
        )
Exemplo n.º 22
0
    def unpack_sequence(self, n):
        """ Unpack the sequence on the TOS.

        """
        self.code_ops.append(                           # TOS -> obj
            bc.Instr("UNPACK_SEQUENCE", n),             # TOS -> val_n -> val_2 -> val_1
        )
Exemplo n.º 23
0
    def store_fast(self, name):
        """ Store the TOS as a fast local.

        """
        self.code_ops.append(                           # TOS -> value
            bc.Instr("STORE_FAST", name),               # TOS
        )
Exemplo n.º 24
0
    def store_name(self, name):
        """ Store the TOS under name.

        """
        self.code_ops.append(                           # TOS -> value
            bc.Instr("STORE_NAME", name),             # TOS
        )
Exemplo n.º 25
0
    def store_subscr(self):
        """ Store the index/value pair on the TOS into the 3rd item.

        """
        self.code_ops.append(                           # TOS -> value -> obj -> index
            bc.Instr("STORE_SUBSCR"),                   # TOS
        )
Exemplo n.º 26
0
    def delete_global(self, name):
        """ Delete a named global variable.

        """
        self.code_ops.append(                           # TOS
            bc.Instr("DELETE_GLOBAL", name),            # TOS
        )
Exemplo n.º 27
0
    def load_attr(self, name):
        """ Load an attribute from the object on TOS.

        """
        self.code_ops.append(                           # TOS -> obj
            bc.Instr("LOAD_ATTR", name),                # TOS -> value
        )
Exemplo n.º 28
0
    def store_global(self, name):
        """ Store the TOS as a global.

        """
        self.code_ops.append(                           # TOS -> value
            bc.Instr("STORE_GLOBAL", name),             # TOS
        )
Exemplo n.º 29
0
    def build_list(self, n=0):
        """ Build a list from items on the TOS.

        """
        self.code_ops.append(                           # TOS
            bc.Instr("BUILD_LIST", n),                  # TOS -> list
        )
Exemplo n.º 30
0
    def load_const(self, const):
        """ Load a const value onto the TOS.

        """
        self.code_ops.append(                           # TOS
            bc.Instr("LOAD_CONST", const),              # TOS -> value
        )