Пример #1
0
 def optimize_GUARD_CLASS(self, op):
     expectedclassbox = op.getarg(1)
     info = self.ensure_ptr_info_arg0(op)
     assert isinstance(expectedclassbox, Const)
     realclassbox = info.get_known_class(self.optimizer.cpu)
     if realclassbox is not None:
         if realclassbox.same_constant(expectedclassbox):
             return
         r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
         raise InvalidLoop('A GUARD_CLASS (%s) was proven to always fail' %
                           r)
     old_guard_op = info.get_last_guard(self.optimizer)
     if old_guard_op and not isinstance(old_guard_op.getdescr(),
                                        compile.ResumeAtPositionDescr):
         # there already has been a guard_nonnull or guard_class or
         # guard_nonnull_class on this value.
         if old_guard_op.getopnum() == rop.GUARD_NONNULL:
             # it was a guard_nonnull, which we replace with a
             # guard_nonnull_class.
             descr = compile.ResumeGuardDescr()
             op = old_guard_op.copy_and_change(
                 rop.GUARD_NONNULL_CLASS,
                 args=[old_guard_op.getarg(0),
                       op.getarg(1)],
                 descr=descr)
             # Note: we give explicitly a new descr for 'op'; this is why the
             # old descr must not be ResumeAtPositionDescr (checked above).
             # Better-safe-than-sorry but it should never occur: we should
             # not put in short preambles guard_nonnull and guard_class
             # on the same box.
             self.optimizer.replace_guard(op, info)
             return self.emit(op)
     return self.emit(op)
Пример #2
0
    def replace_old_guard_with_guard_value(self, op, info, old_guard_op):
        # there already has been a guard_nonnull or guard_class or
        # guard_nonnull_class on this value, which is rather silly.
        # This function replaces the original guard with a
        # guard_value.  Must be careful: doing so is unsafe if the
        # original guard checks for something inconsistent,
        # i.e. different than what it would give if the guard_value
        # passed (this is a rare case, but possible).  If we get
        # inconsistent results in this way, then we must not do the
        # replacement, otherwise we'd put guard_value up there but all
        # intermediate ops might be executed by assuming something
        # different, from the old guard that is now removed...

        c_value = op.getarg(1)
        if not c_value.nonnull():
            raise InvalidLoop('A GUARD_VALUE(..., NULL) follows some other '
                              'guard that it is not NULL')
        previous_classbox = info.get_known_class(self.optimizer.cpu)
        if previous_classbox is not None:
            expected_classbox = self.optimizer.cpu.cls_of_box(c_value)
            assert expected_classbox is not None
            if not previous_classbox.same_constant(
                    expected_classbox):
                r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
                raise InvalidLoop('A GUARD_VALUE (%s) was proven to '
                                  'always fail' % r)
        if not self.optimizer.can_replace_guards:
            return op
        descr = compile.ResumeGuardDescr()
        op = old_guard_op.copy_and_change(rop.GUARD_VALUE,
                         args=[old_guard_op.getarg(0), op.getarg(1)],
                         descr=descr)
        # Note: we give explicitly a new descr for 'op'; this is why the
        # old descr must not be ResumeAtPositionDescr (checked above).
        # Better-safe-than-sorry but it should never occur: we should
        # not put in short preambles guard_xxx and guard_value
        # on the same box.
        self.optimizer.replace_guard(op, info)
        # to be safe
        info.reset_last_guard_pos()
        return op