Пример #1
0
    def eval_operation(self, operation):
        tracer = self.llinterpreter.tracer
        if tracer:
            tracer.dump(str(operation))
        ophandler = self.getoperationhandler(operation.opname)
        # XXX slighly unnice but an important safety check
        if operation.opname == 'direct_call':
            assert isinstance(operation.args[0], Constant)
        elif operation.opname == 'indirect_call':
            assert isinstance(operation.args[0], Variable)
        if getattr(ophandler, 'specialform', False):
            retval = ophandler(*operation.args)
        else:
            vals = [self.getval_or_subop(x) for x in operation.args]
            if getattr(ophandler, 'need_result_type', False):
                vals.insert(0, operation.result.concretetype)
            try:
                retval = ophandler(*vals)
            except LLException, e:
                # safety check check that the operation is allowed to raise that
                # exception
                if operation.opname in lloperation.LL_OPERATIONS:
                    canraise = lloperation.LL_OPERATIONS[
                        operation.opname].canraise
                    if Exception not in canraise:
                        exc = self.llinterpreter.find_exception(e)
                        for canraiseexc in canraise:
                            if issubclass(exc, canraiseexc):
                                break
                        else:
                            raise TypeError(
                                "the operation %s is not expected to raise %s"
                                % (operation, exc))

                # for exception-transformed graphs, store the LLException
                # into the exc_data used by this graph
                exc_data = self.llinterpreter.get_transformed_exc_data(
                    self.graph)
                if exc_data:
                    etype = e.args[0]
                    evalue = e.args[1]
                    exc_data.exc_type = etype
                    exc_data.exc_value = evalue
                    from pypy.translator import exceptiontransform
                    retval = exceptiontransform.error_value(
                        operation.result.concretetype)
                else:
                    raise
Пример #2
0
    def eval_operation(self, operation):
        tracer = self.llinterpreter.tracer
        if tracer:
            tracer.dump(str(operation))
        ophandler = self.getoperationhandler(operation.opname)
        # XXX slighly unnice but an important safety check
        if operation.opname == 'direct_call':
            assert isinstance(operation.args[0], Constant)
        elif operation.opname == 'indirect_call':
            assert isinstance(operation.args[0], Variable)
        if getattr(ophandler, 'specialform', False):
            retval = ophandler(*operation.args)
        else:
            vals = [self.getval_or_subop(x) for x in operation.args]
            if getattr(ophandler, 'need_result_type', False):
                vals.insert(0, operation.result.concretetype)
            try:
                retval = ophandler(*vals)
            except LLException, e:
                # safety check check that the operation is allowed to raise that
                # exception
                if operation.opname in lloperation.LL_OPERATIONS:
                    canraise = lloperation.LL_OPERATIONS[operation.opname].canraise
                    if Exception not in canraise:
                        exc = self.llinterpreter.find_exception(e)
                        for canraiseexc in canraise:
                            if issubclass(exc, canraiseexc):
                                break
                        else:
                            raise TypeError("the operation %s is not expected to raise %s" % (operation, exc))

                # for exception-transformed graphs, store the LLException
                # into the exc_data used by this graph
                exc_data = self.llinterpreter.get_transformed_exc_data(
                    self.graph)
                if exc_data:
                    etype = e.args[0]
                    evalue = e.args[1]
                    exc_data.exc_type  = etype
                    exc_data.exc_value = evalue
                    from pypy.translator import exceptiontransform
                    retval = exceptiontransform.error_value(
                        operation.result.concretetype)
                else:
                    raise
Пример #3
0
class LLFrame(object):
    def __init__(self, graph, args, llinterpreter):
        assert not graph or isinstance(graph, FunctionGraph)
        self.graph = graph
        self.args = args
        self.llinterpreter = llinterpreter
        self.heap = llinterpreter.heap
        self.bindings = {}
        self.curr_block = None
        self.curr_operation_index = 0
        self.alloca_objects = []

    # _______________________________________________________
    # variable setters/getters helpers

    def clear(self):
        self.bindings.clear()

    def fillvars(self, block, values):
        vars = block.inputargs
        assert len(vars) == len(values), (
            "block %s received %d args, expected %d" %
            (block, len(values), len(vars)))
        for var, val in zip(vars, values):
            self.setvar(var, val)

    def setvar(self, var, val):
        if var.concretetype is not lltype.Void:
            try:
                val = lltype.enforce(var.concretetype, val)
            except TypeError:
                assert False, "type error: input value of type:\n\n\t%r\n\n===> variable of type:\n\n\t%r\n" % (
                    lltype.typeOf(val), var.concretetype)
        assert isinstance(var, Variable)
        self.bindings[var] = val

    def setifvar(self, var, val):
        if isinstance(var, Variable):
            self.setvar(var, val)

    def getval(self, varorconst):
        try:
            val = varorconst.value
        except AttributeError:
            val = self.bindings[varorconst]
        if isinstance(val, ComputedIntSymbolic):
            val = val.compute_fn()
        if varorconst.concretetype is not lltype.Void:
            try:
                val = lltype.enforce(varorconst.concretetype, val)
            except TypeError:
                assert False, "type error: %r val from %r var/const" % (
                    lltype.typeOf(val), varorconst.concretetype)
        return val

    def getval_or_subop(self, varorsubop):
        from pypy.translator.oosupport.treebuilder import SubOperation
        if isinstance(varorsubop, SubOperation):
            self.eval_operation(varorsubop.op)
            resultval = self.getval(varorsubop.op.result)
            del self.bindings[varorsubop.op.result]  # XXX hack
            return resultval
        else:
            return self.getval(varorsubop)

    # _______________________________________________________
    # other helpers
    def getoperationhandler(self, opname):
        ophandler = getattr(self, 'op_' + opname, None)
        if ophandler is None:
            # try to import the operation from opimpl.py
            ophandler = lloperation.LL_OPERATIONS[opname].fold
            setattr(self.__class__, 'op_' + opname, staticmethod(ophandler))
        return ophandler

    # _______________________________________________________
    # evaling functions

    def eval(self):
        graph = self.graph
        tracer = self.llinterpreter.tracer
        if tracer:
            tracer.enter(graph)
        self.llinterpreter.frame_stack.append(self)
        try:
            try:
                nextblock = graph.startblock
                args = self.args
                while 1:
                    self.clear()
                    self.fillvars(nextblock, args)
                    nextblock, args = self.eval_block(nextblock)
                    if nextblock is None:
                        for obj in self.alloca_objects:
                            obj._obj._free()
                        return args
            except Exception:
                self.llinterpreter.traceback_frames.append(self)
                raise
        finally:
            leavingframe = self.llinterpreter.frame_stack.pop()
            assert leavingframe is self
            if tracer:
                tracer.leave()

    def eval_block(self, block):
        """ return (nextblock, values) tuple. If nextblock
            is None, values is the concrete return value.
        """
        self.curr_block = block
        catch_exception = block.exitswitch == c_last_exception
        e = None

        try:
            for i, op in enumerate(block.operations):
                self.curr_operation_index = i
                self.eval_operation(op)
        except LLException, e:
            if not (catch_exception and op is block.operations[-1]):
                raise

        # determine nextblock and/or return value
        if len(block.exits) == 0:
            # return block
            tracer = self.llinterpreter.tracer
            if len(block.inputargs) == 2:
                # exception
                if tracer:
                    tracer.dump('raise')
                etypevar, evaluevar = block.getvariables()
                etype = self.getval(etypevar)
                evalue = self.getval(evaluevar)
                # watch out, these are _ptr's
                raise LLException(etype, evalue)
            resultvar, = block.getvariables()
            result = self.getval(resultvar)
            exc_data = self.llinterpreter.get_transformed_exc_data(self.graph)
            if exc_data:
                # re-raise the exception set by this graph, if any
                etype = exc_data.exc_type
                if etype:
                    evalue = exc_data.exc_value
                    if tracer:
                        tracer.dump('raise')
                    exc_data.exc_type = lltype.typeOf(etype)._defl()
                    exc_data.exc_value = lltype.typeOf(evalue)._defl()
                    from pypy.translator import exceptiontransform
                    T = resultvar.concretetype
                    errvalue = exceptiontransform.error_value(T)
                    # check that the exc-transformed graph returns the error
                    # value when it returns with an exception set
                    assert result == errvalue
                    raise LLException(etype, evalue)
            if tracer:
                tracer.dump('return')
            return None, result
        elif block.exitswitch is None:
            # single-exit block
            assert len(block.exits) == 1
            link = block.exits[0]
        elif catch_exception:
            link = block.exits[0]
            if e:
                exdata = self.llinterpreter.typer.getexceptiondata()
                cls = e.args[0]
                inst = e.args[1]
                for link in block.exits[1:]:
                    assert issubclass(link.exitcase, py.builtin.BaseException)
                    if self.op_direct_call(exdata.fn_exception_match, cls,
                                           link.llexitcase):
                        self.setifvar(link.last_exception, cls)
                        self.setifvar(link.last_exc_value, inst)
                        break
                else:
                    # no handler found, pass on
                    raise e
        else:
            llexitvalue = self.getval(block.exitswitch)
            if block.exits[-1].exitcase == "default":
                defaultexit = block.exits[-1]
                nondefaultexits = block.exits[:-1]
                assert defaultexit.llexitcase is None
            else:
                defaultexit = None
                nondefaultexits = block.exits
            for link in nondefaultexits:
                if link.llexitcase == llexitvalue:
                    break  # found -- the result is in 'link'
            else:
                if defaultexit is None:
                    raise ValueError(
                        "exit case %r not found in the exit links "
                        "of %r" % (llexitvalue, block))
                else:
                    link = defaultexit
        return link.target, [self.getval(x) for x in link.args]
Пример #4
0
    def __init__(self, hrtyper, fnobj, can_raise):
        ll_func = fnobj._callable
        FUNCTYPE = lltype.typeOf(fnobj)
        nb_args = len(FUNCTYPE.ARGS)

        self.can_raise = can_raise

        # parse the oopspec and fill in the arguments
        operation_name, args = ll_func.oopspec.split('(', 1)
        assert args.endswith(')')
        args = args[:-1] + ','     # trailing comma to force tuple syntax
        if args.strip() == ',':
            args = '()'
        argnames = ll_func.func_code.co_varnames[:nb_args]
        d = dict(zip(argnames, [Index(n) for n in range(nb_args)]))
        self.argtuple = eval(args, d)
        # end of rather XXX'edly hackish parsing

        OOPARGTYPES = []
        arg_llsig_to_oopsig = {}
        for i, obj in enumerate(self.argtuple):
            if isinstance(obj, Index):
                arg_llsig_to_oopsig[obj.n] = i
                OOPARG = FUNCTYPE.ARGS[obj.n]
            else:
                OOPARG = lltype.typeOf(obj)
            OOPARGTYPES.append(OOPARG)

        self.residualargsources = []
        for i in range(nb_args):
            ARGTYPE = FUNCTYPE.ARGS[i]
            if ARGTYPE is not lltype.Void:
                self.residualargsources.append(arg_llsig_to_oopsig[i])

        RGenOp = hrtyper.RGenOp
        self.args_gv = [None] * nb_args
        fnptr = fnobj._as_ptr()
        self.gv_fnptr = RGenOp.constPrebuiltGlobal(fnptr)
        result_kind = RGenOp.kindToken(FUNCTYPE.RESULT)
        self.result_kind = result_kind
        if FUNCTYPE.RESULT is lltype.Void:
            self.errorbox = None
        else:
            error_value = exceptiontransform.error_value(FUNCTYPE.RESULT)
            self.errorbox = rvalue.redbox_from_prebuilt_value(RGenOp,
                                                              error_value)
        redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT)
        self.redboxbuilder = redboxbuilder
        self.sigtoken = RGenOp.sigToken(FUNCTYPE)

        if operation_name == 'newlist':
            typename, method = 'list', 'oop_newlist'
            SELFTYPE = FUNCTYPE.RESULT.TO
            self.is_method = False
        elif operation_name == 'newdict':
            typename, method = 'dict', 'oop_newdict'
            SELFTYPE = FUNCTYPE.RESULT.TO
            self.is_method = False
        else:
            typename, method = operation_name.split('.')
            method = 'oop_%s_%s' % (typename, method)
            SELFTYPE = FUNCTYPE.ARGS[self.argtuple[0].n].TO
            self.is_method = True

        vmodule = __import__('pypy.jit.timeshifter.v%s' % (typename,),
                             None, None, [method])
        self.typedesc = vmodule.TypeDesc(hrtyper, SELFTYPE)
        self.ll_handler = getattr(vmodule, method)
        self.couldfold = getattr(self.ll_handler, 'couldfold', False)

        if self.couldfold:
            oopargcheck = ll_func.oopargcheck    # required if couldfold=True
            # make a copy of the function, for specialization purposes
            oopargcheck = func_with_new_name(oopargcheck,
                                             'argcheck_%s' % (method,))
            ARGS = FUNCTYPE.ARGS
            residualargsources = self.residualargsources
            unrolling_ARGS = unrolling_iterable(ARGS)
            unrolling_OOPARGS = unrolling_iterable(enumerate(OOPARGTYPES))

            def do_call(jitstate, argboxes):
                oopargs = ()
                for i, ARG in unrolling_OOPARGS:
                    v = rvalue.ll_getvalue(argboxes[i], ARG)
                    oopargs += (v,)
                if not oopargcheck(*oopargs):
                    raise SegfaultException
                args = ()
                j = 0
                for ARG in unrolling_ARGS:
                    if ARG == lltype.Void:
                        v = None
                    else:
                        argsrc = residualargsources[j]
                        j = j + 1
                        v = oopargs[argsrc]
                    args += (v,)
                result = fnptr(*args)
                if FUNCTYPE.RESULT == lltype.Void:
                    return None
                return rvalue.ll_fromvalue(jitstate, result)

            self.do_call = do_call

        # hack! to avoid confusion between the .typedesc attribute
        # of oopspecdescs of different types (lists, dicts, etc.)
        # let's use different subclasses for the oopspecdesc too.
        self.__class__ = globals()['OopSpecDesc_%s' % typename]