Beispiel #1
0
 def _emit_operation(self, op):
     assert not rop.is_call_pure(op.getopnum())
     orig_op = op
     op = self.get_box_replacement(op)
     if op.is_constant():
         return # can happen e.g. if we postpone the operation that becomes
         # constant
     # XXX kill, requires thinking
     #op = self.replace_op_with(op, op.opnum)
     for i in range(op.numargs()):
         arg = self.force_box(op.getarg(i))
         op.setarg(i, arg)
     self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS)
     if rop.is_guard(op.opnum):
         assert isinstance(op, GuardResOp)
         self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS)
         pendingfields = self.pendingfields
         self.pendingfields = None
         if self.replaces_guard and orig_op in self.replaces_guard:
             self.replace_guard_op(self.replaces_guard[orig_op], op)
             del self.replaces_guard[orig_op]
             return
         else:
             op = self.emit_guard_operation(op, pendingfields)
     elif op.can_raise():
         self.exception_might_have_happened = True
     opnum = op.opnum
     if ((rop.has_no_side_effect(opnum) or rop.is_guard(opnum) or
          rop.is_jit_debug(opnum) or
          rop.is_ovf(opnum)) and not self.is_call_pure_pure_canraise(op)):
         pass
     else:
         self._last_guard_op = None
     self._really_emitted_operation = op
     self._newoperations.append(op)
Beispiel #2
0
 def next(self):
     opnum = self._next()
     if oparity[opnum] == -1:
         argnum = self._next()
     else:
         argnum = oparity[opnum]
     args = []
     for i in range(argnum):
         args.append(self._untag(self._next()))
     descr_index = -1
     if opwithdescr[opnum]:
         descr_index = self._next()
         if descr_index == 0 or rop.is_guard(opnum):
             descr = None
         else:
             if descr_index < self.all_descr_len + 1:
                 descr = self.metainterp_sd.all_descrs[descr_index - 1]
             else:
                 descr = self.trace._descrs[descr_index - self.all_descr_len - 1]
     else:
         descr = None
     res = ResOperation(opnum, args, descr=descr)
     if rop.is_guard(opnum):
         assert isinstance(res, GuardResOp)
         res.rd_resume_position = descr_index
     if res.type != 'v':
         self._cache[self._index] = res
         self._index += 1
     self._count += 1
     return res
Beispiel #3
0
 def emit_op(self, op):
     op = self.get_box_replacement(op)
     orig_op = op
     replaced = False
     opnum = op.getopnum()
     keep = (opnum == rop.JIT_DEBUG)
     for i in range(op.numargs()):
         orig_arg = op.getarg(i)
         arg = self.get_box_replacement(orig_arg)
         if isinstance(arg, ConstPtr) and bool(arg.value) and not keep:
             arg = self.remove_constptr(arg)
         if orig_arg is not arg:
             if not replaced:
                 op = op.copy_and_change(opnum)
                 orig_op.set_forwarded(op)
                 replaced = True
             op.setarg(i, arg)
     if rop.is_guard(opnum):
         if not replaced:
             op = op.copy_and_change(opnum)
             orig_op.set_forwarded(op)
         op.setfailargs(
             [self.get_box_replacement(a, True) for a in op.getfailargs()])
     if rop.is_guard(opnum) or opnum == rop.FINISH:
         llref = cast_instance_to_gcref(op.getdescr())
         self.gcrefs_output_list.append(llref)
     self._newops.append(op)
Beispiel #4
0
 def emit_op(self, op):
     op = self.get_box_replacement(op)
     orig_op = op
     replaced = False
     opnum = op.getopnum()
     keep = (opnum == rop.JIT_DEBUG)
     for i in range(op.numargs()):
         orig_arg = op.getarg(i)
         arg = self.get_box_replacement(orig_arg)
         if isinstance(arg, ConstPtr) and bool(arg.value) and not keep:
             arg = self.remove_constptr(arg)
         if orig_arg is not arg:
             if not replaced:
                 op = op.copy_and_change(opnum)
                 orig_op.set_forwarded(op)
                 replaced = True
             op.setarg(i, arg)
     if rop.is_guard(opnum):
         if not replaced:
             op = op.copy_and_change(opnum)
             orig_op.set_forwarded(op)
         op.setfailargs([self.get_box_replacement(a, True)
                         for a in op.getfailargs()])
     if rop.is_guard(opnum) or opnum == rop.FINISH:
         llref = cast_instance_to_gcref(op.getdescr())
         self.gcrefs_output_list.append(llref)
     self._newops.append(op)
Beispiel #5
0
def user_loop_bail_fast_path(loop, warmstate):
    """ In a fast path over the trace loop: try to prevent vecopt
        of spending time on a loop that will most probably fail.
    """

    resop_count = 0 # the count of operations minus debug_merge_points
    vector_instr = 0
    guard_count = 0
    at_least_one_array_access = True
    for i,op in enumerate(loop.operations):
        if rop.is_jit_debug(op.opnum):
            continue

        if op.vector >= 0 and not rop.is_guard(op.opnum):
            vector_instr += 1

        resop_count += 1

        if op.is_primitive_array_access():
            at_least_one_array_access = True

        if rop.is_call(op.opnum) or rop.is_call_assembler(op.opnum):
            return True

        if rop.is_guard(op.opnum):
            guard_count += 1

    if not at_least_one_array_access:
        return True

    return False
Beispiel #6
0
 def _emit_operation(self, op):
     assert not rop.is_call_pure(op.getopnum())
     orig_op = op
     op = self.get_box_replacement(op)
     if op.is_constant():
         return  # can happen e.g. if we postpone the operation that becomes
         # constant
     # XXX kill, requires thinking
     #op = self.replace_op_with(op, op.opnum)
     for i in range(op.numargs()):
         arg = self.force_box(op.getarg(i))
         op.setarg(i, arg)
     self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS)
     if rop.is_guard(op.opnum):
         assert isinstance(op, GuardResOp)
         self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS)
         pendingfields = self.pendingfields
         self.pendingfields = None
         if self.replaces_guard and orig_op in self.replaces_guard:
             self.replace_guard_op(self.replaces_guard[orig_op], op)
             del self.replaces_guard[orig_op]
             return
         else:
             op = self.emit_guard_operation(op, pendingfields)
     opnum = op.opnum
     if ((rop.has_no_side_effect(opnum) or rop.is_guard(opnum)
          or rop.is_jit_debug(opnum) or rop.is_ovf(opnum))
             and not self.is_call_pure_pure_canraise(op)):
         pass
     else:
         self._last_guard_op = None
     self._really_emitted_operation = op
     self._newoperations.append(op)
     self._emittedoperations[op] = None
Beispiel #7
0
 def next(self):
     opnum = self._next()
     if oparity[opnum] == -1:
         argnum = self._next()
     else:
         argnum = oparity[opnum]
     args = []
     for i in range(argnum):
         args.append(self._untag(self._next()))
     descr_index = -1
     if opwithdescr[opnum]:
         descr_index = self._next()
         if descr_index == 0 or rop.is_guard(opnum):
             descr = None
         else:
             if descr_index < self.all_descr_len + 1:
                 descr = self.metainterp_sd.all_descrs[descr_index - 1]
             else:
                 descr = self.trace._descrs[descr_index - self.all_descr_len - 1]
     else:
         descr = None
     res = ResOperation(opnum, args, descr=descr)
     if rop.is_guard(opnum):
         assert isinstance(res, GuardResOp)
         res.rd_resume_position = descr_index
     if res.type != 'v':
         self._cache[self._index] = res
         self._index += 1
     self._count += 1
     return res
Beispiel #8
0
    def build_dependencies(self):
        """ This is basically building the definition-use chain and saving this
            information in a graph structure. This is the same as calculating
            the reaching definitions and the 'looking back' whenever it is used.

            Write After Read, Write After Write dependencies are not possible,
            the operations are in SSA form
        """
        tracker = DefTracker(self)
        #
        label_pos = 0
        jump_pos = len(self.nodes)-1
        intformod = IntegralForwardModification(self.memory_refs, self.index_vars,
                                                self.comparison_vars, self.invariant_vars)
        # pass 1
        for i,node in enumerate(self.nodes):
            op = node.op
            if rop.is_always_pure(op.opnum):
                node.setpriority(1)
            if rop.is_guard(op.opnum):
                node.setpriority(2)
            # the label operation defines all operations at the
            # beginning of the loop

            intformod.inspect_operation(op,node)
            # definition of a new variable
            if op.type != 'v':
                # In SSA form. Modifications get a new variable
                tracker.define(op, node)
            # usage of defined variables
            if rop.is_always_pure(op.opnum) or rop.is_final(op.opnum):
                # normal case every arguments definition is set
                for arg in op.getarglist():
                    tracker.depends_on_arg(arg, node)
            elif rop.is_guard(op.opnum):
                if node.exits_early():
                    pass
                else:
                    # consider cross iterations?
                    if len(self.guards) > 0:
                        last_guard = self.guards[-1]
                        last_guard.edge_to(node, failarg=True, label="guardorder")
                    for nonpure in tracker.non_pure:
                        nonpure.edge_to(node, failarg=True, label="nonpure")
                    tracker.non_pure = []
                self.guards.append(node)
                self.build_guard_dependencies(node, tracker)
            else:
                self.build_non_pure_dependencies(node, tracker)
Beispiel #9
0
    def build_dependencies(self):
        """ This is basically building the definition-use chain and saving this
            information in a graph structure. This is the same as calculating
            the reaching definitions and the 'looking back' whenever it is used.

            Write After Read, Write After Write dependencies are not possible,
            the operations are in SSA form
        """
        tracker = DefTracker(self)
        #
        label_pos = 0
        jump_pos = len(self.nodes)-1
        intformod = IntegralForwardModification(self.memory_refs, self.index_vars,
                                                self.comparison_vars, self.invariant_vars)
        # pass 1
        for i,node in enumerate(self.nodes):
            op = node.op
            if rop.is_always_pure(op.opnum):
                node.setpriority(1)
            if rop.is_guard(op.opnum):
                node.setpriority(2)
            # the label operation defines all operations at the
            # beginning of the loop

            intformod.inspect_operation(op,node)
            # definition of a new variable
            if op.type != 'v':
                # In SSA form. Modifications get a new variable
                tracker.define(op, node)
            # usage of defined variables
            if rop.is_always_pure(op.opnum) or rop.is_final(op.opnum):
                # normal case every arguments definition is set
                for arg in op.getarglist():
                    tracker.depends_on_arg(arg, node)
            elif rop.is_guard(op.opnum):
                if node.exits_early():
                    pass
                else:
                    # consider cross iterations?
                    if len(self.guards) > 0:
                        last_guard = self.guards[-1]
                        last_guard.edge_to(node, failarg=True, label="guardorder")
                    for nonpure in tracker.non_pure:
                        nonpure.edge_to(node, failarg=True, label="nonpure")
                    tracker.non_pure = []
                self.guards.append(node)
                self.build_guard_dependencies(node, tracker)
            else:
                self.build_non_pure_dependencies(node, tracker)
Beispiel #10
0
 def is_always_pure(self, exclude_first=False, exclude_last=False):
     last = len(self.path)-1
     count = len(self.path)
     i = 0
     if exclude_first:
         i += 1
     if exclude_last:
         count -= 1
     while i < count: 
         node = self.path[i]
         if node.is_imaginary():
             i += 1
             continue
         op = node.getoperation()
         if rop.is_guard(op.opnum):
             descr = op.getdescr()
             if not descr:
                 return False
             assert isinstance(descr, AbstractFailDescr)
             if not descr.exits_early():
                 return False
         elif not rop.is_always_pure(op.opnum):
             return False
         i += 1
     return True
Beispiel #11
0
 def is_always_pure(self, exclude_first=False, exclude_last=False):
     last = len(self.path)-1
     count = len(self.path)
     i = 0
     if exclude_first:
         i += 1
     if exclude_last:
         count -= 1
     while i < count: 
         node = self.path[i]
         if node.is_imaginary():
             i += 1
             continue
         op = node.getoperation()
         if rop.is_guard(op.opnum):
             descr = op.getdescr()
             if not descr:
                 return False
             assert isinstance(descr, AbstractFailDescr)
             if not descr.exits_early():
                 return False
         elif not rop.is_always_pure(op.opnum):
             return False
         i += 1
     return True
Beispiel #12
0
def compute_vars_longevity(inputargs, operations):
    # compute a dictionary that maps variables to index in
    # operations that is a "last-time-seen"

    # returns a pair longevity/useful. Non-useful variables are ones that
    # never appear in the assembler or it does not matter if they appear on
    # stack or in registers. Main example is loop arguments that go
    # only to guard operations or to jump or to finish
    last_used = {}
    last_real_usage = {}
    for i in range(len(operations) - 1, -1, -1):
        op = operations[i]
        if op.type != "v":
            if op not in last_used and rop.has_no_side_effect(op.opnum):
                continue
        opnum = op.getopnum()
        for j in range(op.numargs()):
            arg = op.getarg(j)
            if isinstance(arg, Const):
                continue
            if arg not in last_used:
                last_used[arg] = i
            if opnum != rop.JUMP and opnum != rop.LABEL:
                if arg not in last_real_usage:
                    last_real_usage[arg] = i
        if rop.is_guard(op.opnum):
            for arg in op.getfailargs():
                if arg is None:  # hole
                    continue
                assert not isinstance(arg, Const)
                if arg not in last_used:
                    last_used[arg] = i
    #
    longevity = {}
    for i, arg in enumerate(operations):
        if arg.type != "v" and arg in last_used:
            assert not isinstance(arg, Const)
            assert i < last_used[arg]
            longevity[arg] = (i, last_used[arg])
            del last_used[arg]
    for arg in inputargs:
        assert not isinstance(arg, Const)
        if arg not in last_used:
            longevity[arg] = (-1, -1)
        else:
            longevity[arg] = (0, last_used[arg])
            del last_used[arg]
    assert len(last_used) == 0

    if not we_are_translated():
        produced = {}
        for arg in inputargs:
            produced[arg] = None
        for op in operations:
            for arg in op.getarglist():
                if not isinstance(arg, Const):
                    assert arg in produced
            produced[op] = None

    return longevity, last_real_usage
Beispiel #13
0
def compute_vars_longevity(inputargs, operations):
    # compute a dictionary that maps variables to index in
    # operations that is a "last-time-seen"

    # returns a pair longevity/useful. Non-useful variables are ones that
    # never appear in the assembler or it does not matter if they appear on
    # stack or in registers. Main example is loop arguments that go
    # only to guard operations or to jump or to finish
    last_used = {}
    last_real_usage = {}
    for i in range(len(operations) - 1, -1, -1):
        op = operations[i]
        if op.type != 'v':
            if op not in last_used and rop.has_no_side_effect(op.opnum):
                continue
        opnum = op.getopnum()
        for j in range(op.numargs()):
            arg = op.getarg(j)
            if isinstance(arg, Const):
                continue
            if arg not in last_used:
                last_used[arg] = i
            if opnum != rop.JUMP and opnum != rop.LABEL:
                if arg not in last_real_usage:
                    last_real_usage[arg] = i
        if rop.is_guard(op.opnum):
            for arg in op.getfailargs():
                if arg is None:  # hole
                    continue
                assert not isinstance(arg, Const)
                if arg not in last_used:
                    last_used[arg] = i
    #
    longevity = {}
    for i, arg in enumerate(operations):
        if arg.type != 'v' and arg in last_used:
            assert not isinstance(arg, Const)
            assert i < last_used[arg]
            longevity[arg] = (i, last_used[arg])
            del last_used[arg]
    for arg in inputargs:
        assert not isinstance(arg, Const)
        if arg not in last_used:
            longevity[arg] = (-1, -1)
        else:
            longevity[arg] = (0, last_used[arg])
            del last_used[arg]
    assert len(last_used) == 0

    if not we_are_translated():
        produced = {}
        for arg in inputargs:
            produced[arg] = None
        for op in operations:
            for arg in op.getarglist():
                if not isinstance(arg, Const):
                    assert arg in produced
            produced[op] = None

    return longevity, last_real_usage
Beispiel #14
0
 def next(self):
     opnum = self._next()
     argnum = oparity[opnum]
     if argnum == -1:
         argnum = self._next()
     if not (0 <= oparity[opnum] <= 3):
         args = []
         for i in range(argnum):
             args.append(self._untag(self._next()))
         res = ResOperation(opnum, args)
     else:
         cls = opclasses[opnum]
         res = cls()
         argnum = oparity[opnum]
         if argnum == 0:
             pass
         elif argnum == 1:
             res.setarg(0, self._untag(self._next()))
         elif argnum == 2:
             res.setarg(0, self._untag(self._next()))
             res.setarg(1, self._untag(self._next()))
         else:
             assert argnum == 3
             res.setarg(0, self._untag(self._next()))
             res.setarg(1, self._untag(self._next()))
             res.setarg(2, self._untag(self._next()))
     descr_index = -1
     if opwithdescr[opnum]:
         descr_index = self._next()
         if descr_index == 0 or rop.is_guard(opnum):
             descr = None
         else:
             if descr_index < self.all_descr_len + 1:
                 descr = self.metainterp_sd.all_descrs[descr_index - 1]
             else:
                 descr = self.trace._descrs[descr_index -
                                            self.all_descr_len - 1]
             res.setdescr(descr)
         if rop.is_guard(opnum):  # all guards have descrs
             assert isinstance(res, GuardResOp)
             res.rd_resume_position = descr_index
     if res.type != 'v':
         self._cache[self._index] = res
         self._index += 1
     self._count += 1
     return res
Beispiel #15
0
def compute_vars_longevity(inputargs, operations):
    # compute a dictionary that maps variables to Lifetime information
    # if a variable is not in the dictionary, it's operation is dead because
    # it's side-effect-free and the result is unused
    longevity = {}
    for i in range(len(operations) - 1, -1, -1):
        op = operations[i]
        opnum = op.getopnum()
        if op not in longevity:
            if op.type != 'v' and rop.has_no_side_effect(opnum):
                # result not used, operation has no side-effect, it can be
                # removed
                continue
            longevity[op] = Lifetime(definition_pos=i, last_usage=i)
        else:
            longevity[op].definition_pos = i
        for j in range(op.numargs()):
            arg = op.getarg(j)
            if isinstance(arg, Const):
                continue
            if arg not in longevity:
                lifetime = longevity[arg] = Lifetime(last_usage=i)
            else:
                lifetime = longevity[arg]
            if opnum != rop.JUMP and opnum != rop.LABEL:
                if lifetime.real_usages is None:
                    lifetime.real_usages = []
                lifetime.real_usages.append(i)
        if rop.is_guard(op.opnum):
            for arg in op.getfailargs():
                if arg is None:  # hole
                    continue
                assert not isinstance(arg, Const)
                if arg not in longevity:
                    longevity[arg] = Lifetime(last_usage=i)
    #
    for arg in inputargs:
        assert not isinstance(arg, Const)
        if arg not in longevity:
            longevity[arg] = Lifetime(-1, -1)

    if not we_are_translated():
        produced = {}
        for arg in inputargs:
            produced[arg] = None
        for op in operations:
            for arg in op.getarglist():
                if not isinstance(arg, Const):
                    assert arg in produced
            produced[op] = None
    for lifetime in longevity.itervalues():
        if lifetime.real_usages is not None:
            lifetime.real_usages.reverse()
        if not we_are_translated():
            lifetime._check_invariants()

    return LifetimeManager(longevity)
Beispiel #16
0
 def next_element_update_live_range(self, index, liveranges):
     opnum = self._next()
     if oparity[opnum] == -1:
         argnum = self._next()
     else:
         argnum = oparity[opnum]
     for i in range(argnum):
         tagged = self._next()
         tag, v = untag(tagged)
         if tag == TAGBOX:
             liveranges[v] = index
     if opclasses[opnum].type != "v":
         liveranges[index] = index
     if opwithdescr[opnum]:
         descr_index = self._next()
         if rop.is_guard(opnum):
             update_liveranges(self.trace._snapshots[descr_index], index, liveranges)
     if opclasses[opnum].type != "v":
         return index + 1
     return index
Beispiel #17
0
 def next_element_update_live_range(self, index, liveranges):
     opnum = self._next()
     if oparity[opnum] == -1:
         argnum = self._next()
     else:
         argnum = oparity[opnum]
     for i in range(argnum):
         tagged = self._next()
         tag, v = untag(tagged)
         if tag == TAGBOX:
             liveranges[v] = index
     if opclasses[opnum].type != 'v':
         liveranges[index] = index
     if opwithdescr[opnum]:
         descr_index = self._next()
         if rop.is_guard(opnum):
             update_liveranges(self.trace._snapshots[descr_index], index, 
                               liveranges)
     if opclasses[opnum].type != 'v':
         return index + 1
     return index
Beispiel #18
0
 def emitting_operation(self, op):
     if rop.has_no_side_effect(op.opnum):
         return
     if rop.is_ovf(op.opnum):
         return
     if rop.is_guard(op.opnum):
         self.optimizer.pendingfields = (self.force_lazy_sets_for_guard())
         return
     opnum = op.getopnum()
     if (opnum == rop.SETFIELD_GC or  # handled specially
             opnum == rop.SETFIELD_RAW or  # no effect on GC struct/array
             opnum == rop.SETARRAYITEM_GC or  # handled specially
             opnum == rop.SETARRAYITEM_RAW or  # no effect on GC struct
             opnum == rop.SETINTERIORFIELD_RAW or  # no effect on GC struct
             opnum == rop.RAW_STORE or  # no effect on GC struct
             opnum == rop.STRSETITEM or  # no effect on GC struct/array
             opnum == rop.UNICODESETITEM or  # no effect on GC struct/array
             opnum == rop.DEBUG_MERGE_POINT or  # no effect whatsoever
             opnum == rop.JIT_DEBUG or  # no effect whatsoever
             opnum == rop.ENTER_PORTAL_FRAME or  # no effect whatsoever
             opnum == rop.LEAVE_PORTAL_FRAME or  # no effect whatsoever
             opnum == rop.COPYSTRCONTENT or  # no effect on GC struct/array
             opnum == rop.COPYUNICODECONTENT
             or  # no effect on GC struct/array
             opnum
             == rop.CHECK_MEMORY_ERROR):  # may only abort the whole loop
         return
     if rop.is_call(op.opnum):
         if rop.is_call_assembler(op.getopnum()):
             self._seen_guard_not_invalidated = False
         else:
             effectinfo = op.getdescr().get_extra_info()
             if effectinfo.check_can_invalidate():
                 self._seen_guard_not_invalidated = False
             if not effectinfo.has_random_effects():
                 self.force_from_effectinfo(effectinfo)
                 return
     self.force_all_lazy_sets()
     self.clean_caches()
Beispiel #19
0
def convert_loop_to_trace(loop, metainterp_sd, skip_last=False):
    from rpython.jit.metainterp.opencoder import Trace
    from rpython.jit.metainterp.test.test_opencoder import FakeFrame
    from rpython.jit.metainterp import history, resume

    def get(a):
        if isinstance(a, history.Const):
            return a
        return mapping[a]

    class jitcode:
        index = 200

    inputargs = [
        pick_cls(inparg)(i) for i, inparg in enumerate(loop.inputargs)
    ]
    mapping = {}
    for one, two in zip(loop.inputargs, inputargs):
        mapping[one] = two
    trace = Trace(inputargs, metainterp_sd)
    ops = loop.operations
    if skip_last:
        ops = ops[:-1]
    for op in ops:
        newpos = trace.record_op(op.getopnum(),
                                 [get(arg) for arg in op.getarglist()],
                                 op.getdescr())
        if rop.is_guard(op.getopnum()):
            failargs = []
            if op.getfailargs():
                failargs = [get(arg) for arg in op.getfailargs()]
            frame = FakeFrame(100, jitcode, failargs)
            resume.capture_resumedata([frame], None, [], trace)
        if op.type != 'v':
            newop = pick_cls(op)(newpos)
            mapping[op] = newop
    trace._mapping = mapping  # for tests
    return trace
Beispiel #20
0
 def emitting_operation(self, op):
     if rop.has_no_side_effect(op.opnum):
         return
     if rop.is_ovf(op.opnum):
         return
     if rop.is_guard(op.opnum):
         self.optimizer.pendingfields = (
             self.force_lazy_sets_for_guard())
         return
     opnum = op.getopnum()
     if (opnum == rop.SETFIELD_GC or          # handled specially
         opnum == rop.SETFIELD_RAW or         # no effect on GC struct/array
         opnum == rop.SETARRAYITEM_GC or      # handled specially
         opnum == rop.SETARRAYITEM_RAW or     # no effect on GC struct
         opnum == rop.SETINTERIORFIELD_RAW or # no effect on GC struct
         opnum == rop.RAW_STORE or            # no effect on GC struct
         opnum == rop.STRSETITEM or           # no effect on GC struct/array
         opnum == rop.UNICODESETITEM or       # no effect on GC struct/array
         opnum == rop.DEBUG_MERGE_POINT or    # no effect whatsoever
         opnum == rop.JIT_DEBUG or            # no effect whatsoever
         opnum == rop.ENTER_PORTAL_FRAME or   # no effect whatsoever
         opnum == rop.LEAVE_PORTAL_FRAME or   # no effect whatsoever
         opnum == rop.COPYSTRCONTENT or       # no effect on GC struct/array
         opnum == rop.COPYUNICODECONTENT or   # no effect on GC struct/array
         opnum == rop.CHECK_MEMORY_ERROR):    # may only abort the whole loop
         return
     if rop.is_call(op.opnum):
         if rop.is_call_assembler(op.getopnum()):
             self._seen_guard_not_invalidated = False
         else:
             effectinfo = op.getdescr().get_extra_info()
             if effectinfo.check_can_invalidate():
                 self._seen_guard_not_invalidated = False
             if not effectinfo.has_random_effects():
                 self.force_from_effectinfo(effectinfo)
                 return
     self.force_all_lazy_sets()
     self.clean_caches()
Beispiel #21
0
def convert_loop_to_trace(loop, metainterp_sd, skip_last=False):
    from rpython.jit.metainterp.opencoder import Trace
    from rpython.jit.metainterp.test.test_opencoder import FakeFrame
    from rpython.jit.metainterp import history, resume

    def get(a):
        if isinstance(a, history.Const):
            return a
        return mapping[a]

    class jitcode:
        index = 200

    inputargs = [pick_cls(inparg)(i) for i, inparg in
                 enumerate(loop.inputargs)]
    mapping = {}
    for one, two in zip(loop.inputargs, inputargs):
        mapping[one] = two
    trace = Trace(inputargs, metainterp_sd)
    ops = loop.operations
    if skip_last:
        ops = ops[:-1]
    for op in ops:
        newpos = trace.record_op(op.getopnum(), [get(arg) for arg in 
            op.getarglist()], op.getdescr())
        if rop.is_guard(op.getopnum()):
            failargs = []
            if op.getfailargs():
                failargs = [get(arg) for arg in op.getfailargs()]
            frame = FakeFrame(100, jitcode, failargs)
            resume.capture_resumedata([frame], None, [], trace)
        if op.type != 'v':
            newop = pick_cls(op)(newpos)
            mapping[op] = newop
    trace._mapping = mapping # for tests
    return trace
Beispiel #22
0
Datei: util.py Projekt: Mu-L/pypy
def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={},
                 text_right=None):
    # try to use the full width of the terminal to display the list
    # unfortunately, does not work with the default capture method of py.test
    # (which is fd), you you need to use either -s or --capture=sys, else you
    # get the standard 80 columns width
    totwidth = py.io.get_terminal_width()
    width = totwidth / 2 - 1
    print ' Comparing lists '.center(totwidth, '-')
    text_right = text_right or 'expected'
    memo = {}
    print '%s| %s' % ('optimized'.center(width), text_right.center(width))
    for op1, op2 in itertools.izip_longest(oplist1, oplist2, fillvalue=''):
        if op1:
            txt1 = op1.repr(memo)
        else:
            txt1 = ''
        if op2:
            txt2 = op2.repr(memo)
        else:
            txt2 = ''
        while txt1 or txt2:
            part1 = txt1[:width]
            part2 = txt2[:width]
            if part1 == part2:
                sep = '| '
            else:
                sep = '<>'
            print '%s%s%s' % (part1.ljust(width), sep, part2)
            txt1 = txt1[width:]
            txt2 = txt2[width:]
    print '-' * totwidth

    for i_count, (op1, op2) in enumerate(zip(oplist1, oplist2)):
        assert op1.getopnum() == op2.getopnum()
        assert op1.numargs() == op2.numargs()
        for i in range(op1.numargs()):
            x = op1.getarg(i)
            y = op2.getarg(i)
            assert x.same_box(remap.get(y, y))
            assert x.same_shape(remap.get(y, y))
        if op2 in remap:
            assert op1.same_box(remap[op2])
        else:
            if op1.type != 'v':
                remap[op2] = op1
        if (op1.getopnum() not in [rop.JUMP, rop.LABEL, rop.FINISH] and
            not rop.is_guard(op1.getopnum())):
            assert op1.getdescr() == op2.getdescr()
        if op1.getfailargs() or op2.getfailargs():
            assert len(op1.getfailargs()) == len(op2.getfailargs())
            if strict_fail_args:
                for x, y in zip(op1.getfailargs(), op2.getfailargs()):
                    if x is None:
                        assert remap.get(y, y) is None
                    else:
                        assert x.same_box(remap.get(y, y))
                        assert x.same_shape(remap.get(y, y))
            else:
                fail_args1 = set(op1.getfailargs())
                fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()])
                for x in fail_args1:
                    for y in fail_args2:
                        if x.same_box(y):
                            fail_args2.remove(y)
                            break
                    else:
                        assert False

    assert len(oplist1) == len(oplist2)
    return True
Beispiel #23
0
 def rewrite(self, operations, gcrefs_output_list):
     # we can only remember one malloc since the next malloc can possibly
     # collect; but we can try to collapse several known-size mallocs into
     # one, both for performance and to reduce the number of write
     # barriers.  We do this on each "basic block" of operations, which in
     # this case means between CALLs or unknown-size mallocs.
     #
     self.gcrefs_output_list = gcrefs_output_list
     self.gcrefs_map = None
     self.gcrefs_recently_loaded = None
     operations = self.remove_bridge_exception(operations)
     self._changed_op = None
     for i in range(len(operations)):
         op = operations[i]
         assert op.get_forwarded() is None
         if op.getopnum() == rop.DEBUG_MERGE_POINT:
             continue
         if op is self._changed_op:
             op = self._changed_op_to
         # ---------- GC_LOAD/STORE transformations --------------
         if self.transform_to_gc_load(op):
             continue
         # ---------- turn NEWxxx into CALL_MALLOC_xxx ----------
         if rop.is_malloc(op.opnum):
             self.handle_malloc_operation(op)
             continue
         if (rop.is_guard(op.opnum) or
                 self.could_merge_with_next_guard(op, i, operations)):
             self.emit_pending_zeros()
         elif rop.can_malloc(op.opnum):
             self.emitting_an_operation_that_can_collect()
         elif op.getopnum() == rop.LABEL:
             self.emit_label()
         # ---------- write barriers ----------
         if self.gc_ll_descr.write_barrier_descr is not None:
             if op.getopnum() == rop.SETFIELD_GC:
                 self.consider_setfield_gc(op)
                 self.handle_write_barrier_setfield(op)
                 continue
             if op.getopnum() == rop.SETINTERIORFIELD_GC:
                 self.handle_write_barrier_setinteriorfield(op)
                 continue
             if op.getopnum() == rop.SETARRAYITEM_GC:
                 self.consider_setarrayitem_gc(op)
                 self.handle_write_barrier_setarrayitem(op)
                 continue
         else:
             # this is dead code, but in case we have a gc that does
             # not have a write barrier and does not zero memory, we would
             # need to clal it
             if op.getopnum() == rop.SETFIELD_GC:
                 self.consider_setfield_gc(op)
             elif op.getopnum() == rop.SETARRAYITEM_GC:
                 self.consider_setarrayitem_gc(op)
         # ---------- call assembler -----------
         if OpHelpers.is_call_assembler(op.getopnum()):
             self.handle_call_assembler(op)
             continue
         if op.getopnum() == rop.JUMP or op.getopnum() == rop.FINISH:
             self.emit_pending_zeros()
         #
         self.emit_op(op)
     return self._newops
Beispiel #24
0
 def rewrite(self, operations, gcrefs_output_list):
     # we can only remember one malloc since the next malloc can possibly
     # collect; but we can try to collapse several known-size mallocs into
     # one, both for performance and to reduce the number of write
     # barriers.  We do this on each "basic block" of operations, which in
     # this case means between CALLs or unknown-size mallocs.
     #
     self.gcrefs_output_list = gcrefs_output_list
     self.gcrefs_map = None
     self.gcrefs_recently_loaded = None
     operations = self.remove_bridge_exception(operations)
     self._changed_op = None
     for i in range(len(operations)):
         op = operations[i]
         if op.get_forwarded():
             msg = '[rewrite] operations at %d has forwarded info %s\n' % (
                 i, op.repr({}))
             if we_are_translated():
                 llop.debug_print(lltype.Void, msg)
             raise NotImplementedError(msg)
         if op.getopnum() == rop.DEBUG_MERGE_POINT:
             continue
         if op is self._changed_op:
             op = self._changed_op_to
         # ---------- GC_LOAD/STORE transformations --------------
         if self.transform_to_gc_load(op):
             continue
         # ---------- turn NEWxxx into CALL_MALLOC_xxx ----------
         if rop.is_malloc(op.opnum):
             self.handle_malloc_operation(op)
             continue
         if (rop.is_guard(op.opnum)
                 or self.could_merge_with_next_guard(op, i, operations)):
             self.emit_pending_zeros()
         elif rop.can_malloc(op.opnum):
             self.emitting_an_operation_that_can_collect()
         elif op.getopnum() == rop.LABEL:
             self.emit_label()
         # ---------- write barriers ----------
         if self.gc_ll_descr.write_barrier_descr is not None:
             if op.getopnum() == rop.SETFIELD_GC:
                 self.consider_setfield_gc(op)
                 self.handle_write_barrier_setfield(op)
                 continue
             if op.getopnum() == rop.SETINTERIORFIELD_GC:
                 self.handle_write_barrier_setinteriorfield(op)
                 continue
             if op.getopnum() == rop.SETARRAYITEM_GC:
                 self.consider_setarrayitem_gc(op)
                 self.handle_write_barrier_setarrayitem(op)
                 continue
         else:
             # this is dead code, but in case we have a gc that does
             # not have a write barrier and does not zero memory, we would
             # need to call it
             if op.getopnum() == rop.SETFIELD_GC:
                 self.consider_setfield_gc(op)
             elif op.getopnum() == rop.SETARRAYITEM_GC:
                 self.consider_setarrayitem_gc(op)
         # ---------- call assembler -----------
         if OpHelpers.is_call_assembler(op.getopnum()):
             self.handle_call_assembler(op)
             continue
         if op.getopnum() == rop.JUMP or op.getopnum() == rop.FINISH:
             self.emit_pending_zeros()
         #
         self.emit_op(op)
     return self._newops
Beispiel #25
0
def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={},
                 text_right=None):
    # try to use the full width of the terminal to display the list
    # unfortunately, does not work with the default capture method of py.test
    # (which is fd), you you need to use either -s or --capture=sys, else you
    # get the standard 80 columns width
    totwidth = py.io.get_terminal_width()
    width = totwidth / 2 - 1
    print ' Comparing lists '.center(totwidth, '-')
    text_right = text_right or 'expected'
    memo = {}
    print '%s| %s' % ('optimized'.center(width), text_right.center(width))
    for op1, op2 in itertools.izip_longest(oplist1, oplist2, fillvalue=''):
        if op1:
            txt1 = op1.repr(memo)
        else:
            txt1 = ''
        if op2:
            txt2 = op2.repr(memo)
        else:
            txt2 = ''
        while txt1 or txt2:
            part1 = txt1[:width]
            part2 = txt2[:width]
            if part1 == part2:
                sep = '| '
            else:
                sep = '<>'
            print '%s%s%s' % (part1.ljust(width), sep, part2)
            txt1 = txt1[width:]
            txt2 = txt2[width:]
    print '-' * totwidth

    for i_count, (op1, op2) in enumerate(zip(oplist1, oplist2)):
        assert op1.getopnum() == op2.getopnum()
        assert op1.numargs() == op2.numargs()
        for i in range(op1.numargs()):
            x = op1.getarg(i)
            y = op2.getarg(i)
            assert x.same_box(remap.get(y, y))
            assert x.same_shape(remap.get(y, y))
        if op2 in remap:
            assert op1.same_box(remap[op2])
        else:
            if op1.type != 'v':
                remap[op2] = op1
        if (op1.getopnum() not in [rop.JUMP, rop.LABEL, rop.FINISH] and
            not rop.is_guard(op1.getopnum())):
            assert op1.getdescr() == op2.getdescr()
        if op1.getfailargs() or op2.getfailargs():
            assert len(op1.getfailargs()) == len(op2.getfailargs())
            if strict_fail_args:
                for x, y in zip(op1.getfailargs(), op2.getfailargs()):
                    if x is None:
                        assert remap.get(y, y) is None
                    else:
                        assert x.same_box(remap.get(y, y))
                        assert x.same_shape(remap.get(y, y))
            else:
                fail_args1 = set(op1.getfailargs())
                fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()])
                for x in fail_args1:
                    for y in fail_args2:
                        if x.same_box(y):
                            fail_args2.remove(y)
                            break
                    else:
                        assert False

    assert len(oplist1) == len(oplist2)
    return True