Exemplo n.º 1
0
class LLOp(object):
    def __init__(self,
                 sideeffects=True,
                 canfold=False,
                 canraise=(),
                 pyobj=False,
                 canmallocgc=False,
                 canrun=False,
                 oo=False,
                 tryfold=False):
        # self.opname = ... (set afterwards)

        if canfold:
            sideeffects = False

        # The operation has no side-effects: it can be removed
        # if its result is not used
        self.sideeffects = sideeffects

        # Can be safely constant-folded: no side-effects
        #  and always gives the same result for given args
        self.canfold = canfold

        # Can *try* to fold the operation, but it may raise on you
        self.tryfold = tryfold or canfold

        # Exceptions that can be raised
        self.canraise = canraise
        assert isinstance(canraise, tuple)

        assert not canraise or not canfold

        # The operation manipulates PyObjects
        self.pyobj = pyobj

        # The operation can go a GC malloc
        self.canmallocgc = canmallocgc
        if canmallocgc:
            if (MemoryError not in self.canraise
                    and Exception not in self.canraise):
                self.canraise += (MemoryError, )

        # The operation can be run directly with __call__
        self.canrun = canrun or canfold

        # The operation belongs to the ootypesystem
        self.oo = oo

    # __________ make the LLOp instances callable from LL helpers __________

    __name__ = property(lambda self: 'llop_' + self.opname)

    def __call__(self, RESULTTYPE, *args):
        # llop is meant to be rtyped and not called directly, unless it is
        # a canfold=True operation
        fold = self.fold
        if getattr(fold, 'need_result_type', False):
            val = fold(RESULTTYPE, *args)
        else:
            val = fold(*args)
        if RESULTTYPE is not lltype.Void:
            val = lltype.enforce(RESULTTYPE, val)
        return val

    def get_fold_impl(self):
        global lltype  #  <- lazy import hack, worth an XXX
        from pypy.rpython.lltypesystem import lltype
        if self.canrun:
            if self.oo:
                from pypy.rpython.ootypesystem.ooopimpl import get_op_impl
            else:
                from pypy.rpython.lltypesystem.opimpl import get_op_impl
            op_impl = get_op_impl(self.opname)
        else:
            error = TypeError("cannot constant-fold operation %r" %
                              (self.opname, ))

            def op_impl(*args):
                raise error

        # cache the implementation function into 'self'
        self.fold = op_impl
        return op_impl

    fold = roproperty(get_fold_impl)

    def is_pure(self, args_v):
        if self.canfold:  # canfold => pure operation
            return True
        if self is llop.debug_assert:  # debug_assert is pure enough
            return True
        # reading from immutable (lltype)
        if self is llop.getfield or self is llop.getarrayitem:
            field = getattr(args_v[1], 'value', None)
            return args_v[0].concretetype.TO._immutable_field(field)
        # reading from immutable (ootype) (xxx what about arrays?)
        if self is llop.oogetfield:
            field = getattr(args_v[1], 'value', None)
            return args_v[0].concretetype._immutable_field(field)
        # default
        return False

    def __repr__(self):
        return '<LLOp %s>' % (getattr(self, 'opname', '?'), )
Exemplo n.º 2
0
class FunctionGraph(object):
    __slots__ = ['startblock', 'returnblock', 'exceptblock', '__dict__']

    def __init__(self, name, startblock, return_var=None):
        self.name = name  # function name (possibly mangled already)
        self.startblock = startblock
        # build default returnblock
        self.returnblock = Block([return_var or Variable()])
        self.returnblock.operations = ()
        self.returnblock.exits = ()
        # block corresponding to exception results
        self.exceptblock = Block([
            Variable('etype'),  # exception class
            Variable('evalue')
        ])  # exception value
        self.exceptblock.operations = ()
        self.exceptblock.exits = ()
        self.tag = None

    def getargs(self):
        return self.startblock.inputargs

    def getreturnvar(self):
        return self.returnblock.inputargs[0]

    def getsource(self):
        from pypy.tool.sourcetools import getsource
        func = self.func  # can raise AttributeError
        src = getsource(self.func)
        if src is None:
            raise AttributeError('source not found')
        return src

    source = roproperty(getsource)

    def getstartline(self):
        return self.func.func_code.co_firstlineno

    startline = roproperty(getstartline)

    def getfilename(self):
        return self.func.func_code.co_filename

    filename = roproperty(getfilename)

    def __str__(self):
        if hasattr(self, 'func'):
            return nice_repr_for_func(self.func, self.name)
        else:
            return self.name

    def __repr__(self):
        return '<FunctionGraph of %s at 0x%x>' % (self, uid(self))

    def iterblocks(self):
        block = self.startblock
        yield block
        seen = {block: True}
        stack = list(block.exits[::-1])
        while stack:
            block = stack.pop().target
            if block not in seen:
                yield block
                seen[block] = True
                stack += block.exits[::-1]

    def iterlinks(self):
        block = self.startblock
        seen = {block: True}
        stack = list(block.exits[::-1])
        while stack:
            link = stack.pop()
            yield link
            block = link.target
            if block not in seen:
                seen[block] = True
                stack += block.exits[::-1]

    def iterblockops(self):
        for block in self.iterblocks():
            for op in block.operations:
                yield block, op

    def show(self, t=None):
        from pypy.translator.tool.graphpage import FlowGraphPage
        FlowGraphPage(t, [self]).display()