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
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)
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))
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
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)
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)
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)
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)
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)
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)
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)
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)
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)
def postprocess_GUARD_NONNULL(self, op): self.make_nonnull(op.getarg(0)) getptrinfo(op.getarg(0)).mark_last_guard(self.optimizer)