Ejemplo n.º 1
0
    def _optimize_call_arrayop(self, op, source_box, dest_box,
                               source_start_box, dest_start_box, length_box):
        length = self.get_constant_box(length_box)
        if length and length.getint() == 0:
            return True  # 0-length arraycopy or arraymove

        source_info = getptrinfo(source_box)
        dest_info = getptrinfo(dest_box)
        source_start_box = self.get_constant_box(source_start_box)
        dest_start_box = self.get_constant_box(dest_start_box)
        extrainfo = op.getdescr().get_extra_info()
        if (source_start_box and dest_start_box and length and
            ((dest_info and dest_info.is_virtual()) or length.getint() <= 8)
                and ((source_info and source_info.is_virtual())
                     or length.getint() <= 8)
                and extrainfo.single_write_descr_array
                is not None):  #<-sanity check
            source_start = source_start_box.getint()
            dest_start = dest_start_box.getint()
            arraydescr = extrainfo.single_write_descr_array
            if arraydescr.is_array_of_structs():
                return False  # not supported right now

            index_current = 0
            index_delta = +1
            index_stop = length.getint()
            if (source_box is dest_box and  # ARRAYMOVE only
                    source_start < dest_start):  # iterate in reverse order
                index_current = index_stop - 1
                index_delta = -1
                index_stop = -1

            # XXX fish fish fish
            while index_current != index_stop:
                index = index_current
                index_current += index_delta
                assert index >= 0
                if source_info and source_info.is_virtual():
                    val = source_info.getitem(arraydescr, index + source_start)
                else:
                    opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
                    newop = ResOperation(
                        opnum, [source_box,
                                ConstInt(index + source_start)],
                        descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
                    val = newop
                if val is None:
                    continue
                if dest_info and dest_info.is_virtual():
                    dest_info.setitem(arraydescr, index + dest_start,
                                      get_box_replacement(dest_box), val)
                else:
                    newop = ResOperation(
                        rop.SETARRAYITEM_GC,
                        [dest_box, ConstInt(index + dest_start), val],
                        descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
            return True
        return False
Ejemplo n.º 2
0
    def _optimize_CALL_ARRAYCOPY(self, op):
        length = self.get_constant_box(op.getarg(5))
        if length and length.getint() == 0:
            return None  # 0-length arraycopy

        source_info = getptrinfo(op.getarg(1))
        dest_info = getptrinfo(op.getarg(2))
        source_start_box = self.get_constant_box(op.getarg(3))
        dest_start_box = self.get_constant_box(op.getarg(4))
        extrainfo = op.getdescr().get_extra_info()
        if (source_start_box and dest_start_box and length and
            ((dest_info and dest_info.is_virtual()) or length.getint() <= 8)
                and ((source_info and source_info.is_virtual())
                     or length.getint() <= 8)
                and extrainfo.single_write_descr_array
                is not None):  #<-sanity check
            source_start = source_start_box.getint()
            dest_start = dest_start_box.getint()
            arraydescr = extrainfo.single_write_descr_array
            if arraydescr.is_array_of_structs():
                return self.emit(op)  # not supported right now

            # XXX fish fish fish
            for index in range(length.getint()):
                if source_info and source_info.is_virtual():
                    val = source_info.getitem(arraydescr, index + source_start)
                else:
                    opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
                    newop = ResOperation(
                        opnum, [op.getarg(1),
                                ConstInt(index + source_start)],
                        descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
                    val = newop
                if val is None:
                    continue
                if dest_info and dest_info.is_virtual():
                    dest_info.setitem(arraydescr, index + dest_start,
                                      get_box_replacement(op.getarg(2)), val)
                else:
                    newop = ResOperation(
                        rop.SETARRAYITEM_GC,
                        [op.getarg(2),
                         ConstInt(index + dest_start), val],
                        descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
            return None
        return self.emit(op)
Ejemplo n.º 3
0
 def possible_aliasing(self, opinfo):
     # If lazy_set is set and contains a setfield on a different
     # structvalue, then we are annoyed, because it may point to either
     # the same or a different structure at runtime.
     # XXX constants?
     return (self._lazy_set is not None and not info.getptrinfo(
         self._lazy_set.getarg(0)).same_info(opinfo))
Ejemplo n.º 4
0
 def force_lazy_sets_for_guard(self):
     pendingfields = []
     items = self.cached_fields.items()
     if not we_are_translated():
         items.sort(key=str, reverse=True)
     for descr, cf in items:
         op = cf._lazy_set
         if op is None:
             continue
         val = op.getarg(1)
         if self.optimizer.is_virtual(val):
             pendingfields.append(op)
             continue
         cf.force_lazy_set(self, descr)
     for descr, submap in self.cached_arrayitems.iteritems():
         for index, cf in submap.iteritems():
             op = cf._lazy_set
             if op is None:
                 continue
             # the only really interesting case that we need to handle in the
             # guards' resume data is that of a virtual object that is stored
             # into a field of a non-virtual object.  Here, 'op' in either
             # SETFIELD_GC or SETARRAYITEM_GC.
             opinfo = info.getptrinfo(op.getarg(0))
             assert not opinfo.is_virtual()  # it must be a non-virtual
             if self.optimizer.is_virtual(op.getarg(2)):
                 pendingfields.append(op)
             else:
                 cf.force_lazy_set(self, descr)
     return pendingfields
Ejemplo n.º 5
0
 def optimize_GUARD_NONNULL_CLASS(self, op):
     info = getptrinfo(op.getarg(0))
     if info and info.is_null():
         r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
         raise InvalidLoop('A GUARD_NONNULL_CLASS (%s) was proven to '
                           'always fail' % r)
     return self.optimize_GUARD_CLASS(op)
Ejemplo n.º 6
0
 def postprocess_GUARD_CLASS(self, op):
     expectedclassbox = op.getarg(1)
     info = getptrinfo(op.getarg(0))
     old_guard_op = info.get_last_guard(self.optimizer)
     update_last_guard = not old_guard_op or isinstance(
         old_guard_op.getdescr(), compile.ResumeAtPositionDescr)
     self.make_constant_class(op.getarg(0), expectedclassbox, update_last_guard)
Ejemplo n.º 7
0
 def optimize_GUARD_NONNULL(self, op):
     opinfo = getptrinfo(op.getarg(0))
     if opinfo is not None:
         if opinfo.is_nonnull():
             return
         elif opinfo.is_null():
             r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
             raise InvalidLoop('A GUARD_NONNULL (%s) was proven to always '
                               'fail' % r)
     return self.emit(op)
Ejemplo n.º 8
0
 def optimize_RECORD_EXACT_CLASS(self, op):
     opinfo = getptrinfo(op.getarg(0))
     expectedclassbox = op.getarg(1)
     assert isinstance(expectedclassbox, Const)
     if opinfo is not None:
         realclassbox = opinfo.get_known_class(self.optimizer.cpu)
         if realclassbox is not None:
             assert realclassbox.same_constant(expectedclassbox)
             return
     self.make_constant_class(op.getarg(0), expectedclassbox,
                              update_last_guard=False)
Ejemplo n.º 9
0
 def optimize_GUARD_GC_TYPE(self, op):
     info = getptrinfo(op.getarg(0))
     if info and info.is_constant():
         c = get_box_replacement(op.getarg(0))
         tid = self.optimizer.cpu.get_actual_typeid(c.getref_base())
         if tid != op.getarg(1).getint():
             raise InvalidLoop("wrong GC type ID found on a constant")
         return
     if info is not None and info.get_descr() is not None:
         if info.get_descr().get_type_id() != op.getarg(1).getint():
             raise InvalidLoop("wrong GC types passed around!")
         return
     return self.emit(op)
Ejemplo n.º 10
0
 def _optimize_oois_ooisnot(self, op, expect_isnot, instance):
     arg0 = get_box_replacement(op.getarg(0))
     arg1 = get_box_replacement(op.getarg(1))
     info0 = getptrinfo(arg0)
     info1 = getptrinfo(arg1)
     if info0 and info0.is_virtual():
         if info1 and info1.is_virtual():
             intres = (info0 is info1) ^ expect_isnot
             self.make_constant_int(op, intres)
         else:
             self.make_constant_int(op, expect_isnot)
     elif info1 and info1.is_virtual():
         self.make_constant_int(op, expect_isnot)
     elif info1 and info1.is_null():
         return self._optimize_nullness(op, op.getarg(0), expect_isnot)
     elif info0 and info0.is_null():
         return self._optimize_nullness(op, op.getarg(1), expect_isnot)
     elif arg0 is arg1:
         self.make_constant_int(op, not expect_isnot)
     else:
         if instance:
             if info0 is None:
                 cls0 = None
             else:
                 cls0 = info0.get_known_class(self.optimizer.cpu)
             if cls0 is not None:
                 if info1 is None:
                     cls1 = None
                 else:
                     cls1 = info1.get_known_class(self.optimizer.cpu)
                 if cls1 is not None and not cls0.same_constant(cls1):
                     # cannot be the same object, as we know that their
                     # class is different
                     self.make_constant_int(op, expect_isnot)
                     return
         return self.emit(op)
Ejemplo n.º 11
0
 def optimize_GUARD_IS_OBJECT(self, op):
     info = getptrinfo(op.getarg(0))
     if info and info.is_constant():
         if info.is_null():
             raise InvalidLoop("A GUARD_IS_OBJECT(NULL) found")
         c = get_box_replacement(op.getarg(0))
         if self.optimizer.cpu.check_is_object(c.getref_base()):
             return
         raise InvalidLoop("A GUARD_IS_OBJECT(not-an-object) found")
     if info is not None:
         if info.is_about_object():
             return
         if info.is_precise():
             raise InvalidLoop()
     return self.emit(op)
Ejemplo n.º 12
0
 def optimize_GUARD_VALUE(self, op):
     arg0 = op.getarg(0)
     if arg0.type == 'r':
         info = getptrinfo(arg0)
         if info:
             if info.is_virtual():
                 raise InvalidLoop("promote of a virtual")
             old_guard_op = info.get_last_guard(self.optimizer)
             if old_guard_op is not None:
                 op = self.replace_old_guard_with_guard_value(
                     op, info, old_guard_op)
     elif arg0.type == 'f':
         arg0 = get_box_replacement(arg0)
         if arg0.is_constant():
             return
     constbox = op.getarg(1)
     assert isinstance(constbox, Const)
     return self.optimize_guard(op, constbox)
Ejemplo n.º 13
0
 def optimize_GUARD_SUBCLASS(self, op):
     info = getptrinfo(op.getarg(0))
     optimizer = self.optimizer
     # must raise 'InvalidLoop' in all cases where 'info' shows the
     # class cannot possibly match (see test_issue2926)
     if info and info.is_constant():
         c = get_box_replacement(op.getarg(0))
         vtable = optimizer.cpu.cls_of_box(c).getint()
         if optimizer._check_subclass(vtable, op.getarg(1).getint()):
             return
         raise InvalidLoop("GUARD_SUBCLASS(const) proven to always fail")
     if info is not None and info.is_about_object():
         known_class = info.get_known_class(optimizer.cpu)
         if known_class:
             # Class of 'info' is exactly 'known_class'.
             # We know statically if the 'guard_subclass' will pass or fail.
             if optimizer._check_subclass(known_class.getint(),
                                          op.getarg(1).getint()):
                 return
             else:
                 raise InvalidLoop(
                     "GUARD_SUBCLASS(known_class) proven to always fail")
         elif info.get_descr() is not None:
             # Class of 'info' is either get_descr() or a subclass of it.
             # We're keeping the 'guard_subclass' at runtime only in the
             # case where get_descr() is some strict parent class of
             # the argument to 'guard_subclass'.
             info_base_descr = info.get_descr().get_vtable()
             if optimizer._check_subclass(info_base_descr,
                                          op.getarg(1).getint()):
                 return  # guard_subclass always passing
             elif optimizer._check_subclass(
                     op.getarg(1).getint(), info_base_descr):
                 pass  # don't know, must keep the 'guard_subclass'
             else:
                 raise InvalidLoop(
                     "GUARD_SUBCLASS(base_class) proven to always fail")
     return self.emit(op)
Ejemplo n.º 14
0
 def postprocess_GUARD_NONNULL(self, op):
     self.make_nonnull(op.getarg(0))
     getptrinfo(op.getarg(0)).mark_last_guard(self.optimizer)