class NotVirtualStateInfo(AbstractVirtualStateInfo): def __init__(self, value, is_opaque=False): self.is_opaque = is_opaque self.known_class = value.known_class self.level = value.level if value.intbound is None: self.intbound = IntUnbounded() else: self.intbound = value.intbound.clone() if value.is_constant(): self.constbox = value.box else: self.constbox = None self.position_in_notvirtuals = -1 self.lenbound = value.lenbound def generalization_of(self, other, renum, bad): # XXX This will always retrace instead of forcing anything which # might be what we want sometimes? assert self.position != -1 if self.position in renum: if renum[self.position] == other.position: return True bad[self] = None bad[other] = None return False renum[self.position] = other.position if not isinstance(other, NotVirtualStateInfo): bad[self] = None bad[other] = None return False if other.level < self.level: bad[self] = None bad[other] = None return False if self.level == LEVEL_CONSTANT: if not self.constbox.same_constant(other.constbox): bad[self] = None bad[other] = None return False elif self.level == LEVEL_KNOWNCLASS: if not self.known_class.same_constant(other.known_class): bad[self] = None bad[other] = None return False if not self.intbound.contains_bound(other.intbound): bad[self] = None bad[other] = None return False if self.lenbound and other.lenbound: if self.lenbound.mode != other.lenbound.mode or \ self.lenbound.descr != other.lenbound.descr or \ not self.lenbound.bound.contains_bound(other.lenbound.bound): bad[self] = None bad[other] = None return False elif self.lenbound: bad[self] = None bad[other] = None return False return True def _generate_guards(self, other, box, cpu, extra_guards): if not isinstance(other, NotVirtualStateInfo): raise InvalidLoop('The VirtualStates does not match as a ' + 'virtual appears where a pointer is needed ' + 'and it is too late to force it.') if self.lenbound or other.lenbound: raise InvalidLoop('The array length bounds does not match.') if self.is_opaque: raise InvalidLoop('Generating guards for opaque pointers is not safe') if self.level == LEVEL_KNOWNCLASS and \ box.nonnull() and \ self.known_class.same_constant(cpu.ts.cls_of_box(box)): # Note: This is only a hint on what the class of box was # during the trace. There are actually no guarentees that this # box realy comes from a trace. The hint is used here to choose # between either eimtting a guard_class and jumping to an # excisting compiled loop or retracing the loop. Both # alternatives will always generate correct behaviour, but # performace will differ. op = ResOperation(rop.GUARD_NONNULL, [box], None) extra_guards.append(op) op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None) extra_guards.append(op) return if (self.level == LEVEL_NONNULL and other.level == LEVEL_UNKNOWN and isinstance(box, BoxPtr) and box.nonnull()): op = ResOperation(rop.GUARD_NONNULL, [box], None) extra_guards.append(op) return if (self.level == LEVEL_UNKNOWN and other.level == LEVEL_UNKNOWN and isinstance(box, BoxInt) and self.intbound.contains(box.getint())): if self.intbound.has_lower: bound = self.intbound.lower if not (other.intbound.has_lower and other.intbound.lower >= bound): res = BoxInt() op = ResOperation(rop.INT_GE, [box, ConstInt(bound)], res) extra_guards.append(op) op = ResOperation(rop.GUARD_TRUE, [res], None) extra_guards.append(op) if self.intbound.has_upper: bound = self.intbound.upper if not (other.intbound.has_upper and other.intbound.upper <= bound): res = BoxInt() op = ResOperation(rop.INT_LE, [box, ConstInt(bound)], res) extra_guards.append(op) op = ResOperation(rop.GUARD_TRUE, [res], None) extra_guards.append(op) return # Remaining cases are probably not interesting raise InvalidLoop('Generating guards for making the VirtualStates ' + 'at hand match have not been implemented') def enum_forced_boxes(self, boxes, value, optimizer): if self.level == LEVEL_CONSTANT: return assert 0 <= self.position_in_notvirtuals if optimizer: box = value.force_box(optimizer) else: if value.is_virtual(): raise BadVirtualState box = value.get_key_box() boxes[self.position_in_notvirtuals] = box def _enum(self, virtual_state): if self.level == LEVEL_CONSTANT: return self.position_in_notvirtuals = len(virtual_state.notvirtuals) virtual_state.notvirtuals.append(self) def debug_print(self, indent, seen, bad): mark = '' if self in bad: mark = '*' if we_are_translated(): l = {LEVEL_UNKNOWN: 'Unknown', LEVEL_NONNULL: 'NonNull', LEVEL_KNOWNCLASS: 'KnownClass', LEVEL_CONSTANT: 'Constant', }[self.level] else: l = {LEVEL_UNKNOWN: 'Unknown', LEVEL_NONNULL: 'NonNull', LEVEL_KNOWNCLASS: 'KnownClass(%r)' % self.known_class, LEVEL_CONSTANT: 'Constant(%r)' % self.constbox, }[self.level] lb = '' if self.lenbound: lb = ', ' + self.lenbound.bound.__repr__() debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position + ', ' + l + ', ' + self.intbound.__repr__() + lb + ')')
class NotVirtualStateInfo(AbstractVirtualStateInfo): def __init__(self, value, is_opaque=False): self.is_opaque = is_opaque self.known_class = value.known_class self.level = value.level if value.intbound is None: self.intbound = IntUnbounded() else: self.intbound = value.intbound.clone() if value.is_constant(): self.constbox = value.box else: self.constbox = None self.position_in_notvirtuals = -1 self.lenbound = value.lenbound def _generate_guards(self, other, value, state): if value is None or self.is_opaque: box = None # generating guards for opaque pointers isn't safe else: box = value.box # XXX This will always retrace instead of forcing anything which # might be what we want sometimes? if not isinstance(other, NotVirtualStateInfo): raise VirtualStatesCantMatch( "The VirtualStates does not match as a " + "virtual appears where a pointer is needed " + "and it is too late to force it." ) extra_guards = state.extra_guards cpu = state.cpu if self.lenbound and not self.lenbound.generalization_of(other.lenbound): raise VirtualStatesCantMatch("length bound does not match") if self.level == LEVEL_UNKNOWN: # confusingly enough, this is done also for pointers # which have the full range as the "bound", so it always works return self._generate_guards_intbounds(other, box, extra_guards) # the following conditions often peek into the runtime value that the # box had when tracing. This value is only used as an educated guess. # It is used here to choose between either emitting a guard and jumping # to an existing compiled loop or retracing the loop. Both alternatives # will always generate correct behaviour, but performance will differ. elif self.level == LEVEL_NONNULL: if other.level == LEVEL_UNKNOWN: if box is not None and box.nonnull(): op = ResOperation(rop.GUARD_NONNULL, [box], None) extra_guards.append(op) return else: raise VirtualStatesCantMatch("other not known to be nonnull") elif other.level == LEVEL_NONNULL: return elif other.level == LEVEL_KNOWNCLASS: return # implies nonnull else: assert other.level == LEVEL_CONSTANT assert other.constbox if not other.constbox.nonnull(): raise VirtualStatesCantMatch("constant is null") return elif self.level == LEVEL_KNOWNCLASS: if other.level == LEVEL_UNKNOWN: if box and box.nonnull() and self.known_class.same_constant(cpu.ts.cls_of_box(box)): op = ResOperation(rop.GUARD_NONNULL, [box], None) extra_guards.append(op) op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None) extra_guards.append(op) return else: raise VirtualStatesCantMatch("other's class is unknown") elif other.level == LEVEL_NONNULL: if box and self.known_class.same_constant(cpu.ts.cls_of_box(box)): op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None) extra_guards.append(op) return else: raise VirtualStatesCantMatch("other's class is unknown") elif other.level == LEVEL_KNOWNCLASS: if self.known_class.same_constant(other.known_class): return raise VirtualStatesCantMatch("classes don't match") else: assert other.level == LEVEL_CONSTANT if other.constbox.nonnull() and self.known_class.same_constant(cpu.ts.cls_of_box(other.constbox)): return else: raise VirtualStatesCantMatch("classes don't match") else: assert self.level == LEVEL_CONSTANT if other.level == LEVEL_CONSTANT: if self.constbox.same_constant(other.constbox): return raise VirtualStatesCantMatch("different constants") if box is not None and self.constbox.same_constant(box.constbox()): op = ResOperation(rop.GUARD_VALUE, [box, self.constbox], None) extra_guards.append(op) return else: raise VirtualStatesCantMatch("other not constant") assert 0, "unreachable" def _generate_guards_intbounds(self, other, box, extra_guards): if self.intbound.contains_bound(other.intbound): return if box is not None and isinstance(box, BoxInt) and self.intbound.contains(box.getint()): # this may generate a few more guards than needed, but they are # optimized away when emitting them self.intbound.make_guards(box, extra_guards) return raise VirtualStatesCantMatch("intbounds don't match") def enum_forced_boxes(self, boxes, value, optimizer): if self.level == LEVEL_CONSTANT: return assert 0 <= self.position_in_notvirtuals if optimizer: box = value.force_box(optimizer) else: if value.is_virtual(): raise BadVirtualState box = value.get_key_box() boxes[self.position_in_notvirtuals] = box def _enum(self, virtual_state): if self.level == LEVEL_CONSTANT: return self.position_in_notvirtuals = virtual_state.numnotvirtuals virtual_state.numnotvirtuals += 1 def debug_print(self, indent, seen, bad, metainterp_sd=None): mark = "" if self in bad: mark = "*" if self.level == LEVEL_UNKNOWN: l = "Unknown" elif self.level == LEVEL_NONNULL: l = "NonNull" elif self.level == LEVEL_KNOWNCLASS: addr = self.known_class.getaddr() if metainterp_sd: name = metainterp_sd.get_name_from_address(addr) else: name = "?" l = "KnownClass(%s)" % name else: assert self.level == LEVEL_CONSTANT const = self.constbox if isinstance(const, ConstInt): l = "ConstInt(%s)" % (const.value,) elif isinstance(const, ConstPtr): if const.value: l = "ConstPtr" else: l = "ConstPtr(null)" else: assert isinstance(const, ConstFloat) l = "ConstFloat(%s)" % const.getfloat() lb = "" if self.lenbound: lb = ", " + self.lenbound.bound.__repr__() debug_print( indent + mark + "NotVirtualInfo(%d" % self.position + ", " + l + ", " + self.intbound.__repr__() + lb + ")" )
class NotVirtualStateInfo(AbstractVirtualStateInfo): def __init__(self, value, is_opaque=False): self.is_opaque = is_opaque self.known_class = value.get_known_class() self.level = value.getlevel() if value.getintbound() is None: self.intbound = IntUnbounded() else: self.intbound = value.getintbound().clone() if value.is_constant(): self.constbox = value.box else: self.constbox = None self.position_in_notvirtuals = -1 self.lenbound = value.getlenbound() def _generate_guards(self, other, value, state): if value is None or self.is_opaque: box = None # generating guards for opaque pointers isn't safe else: box = value.box # XXX This will always retrace instead of forcing anything which # might be what we want sometimes? if not isinstance(other, NotVirtualStateInfo): raise VirtualStatesCantMatch( 'The VirtualStates does not match as a ' + 'virtual appears where a pointer is needed ' + 'and it is too late to force it.') extra_guards = state.extra_guards cpu = state.cpu if self.lenbound and not self.lenbound.generalization_of(other.lenbound): raise VirtualStatesCantMatch("length bound does not match") if self.level == LEVEL_UNKNOWN: # confusingly enough, this is done also for pointers # which have the full range as the "bound", so it always works return self._generate_guards_intbounds(other, box, extra_guards) # the following conditions often peek into the runtime value that the # box had when tracing. This value is only used as an educated guess. # It is used here to choose between either emitting a guard and jumping # to an existing compiled loop or retracing the loop. Both alternatives # will always generate correct behaviour, but performance will differ. elif self.level == LEVEL_NONNULL: if other.level == LEVEL_UNKNOWN: if box is not None and box.nonnull(): op = ResOperation(rop.GUARD_NONNULL, [box], None) extra_guards.append(op) return else: raise VirtualStatesCantMatch("other not known to be nonnull") elif other.level == LEVEL_NONNULL: return elif other.level == LEVEL_KNOWNCLASS: return # implies nonnull else: assert other.level == LEVEL_CONSTANT assert other.constbox if not other.constbox.nonnull(): raise VirtualStatesCantMatch("constant is null") return elif self.level == LEVEL_KNOWNCLASS: if other.level == LEVEL_UNKNOWN: if (box and box.nonnull() and self.known_class.same_constant(cpu.ts.cls_of_box(box))): op = ResOperation(rop.GUARD_NONNULL_CLASS, [box, self.known_class], None) extra_guards.append(op) return else: raise VirtualStatesCantMatch("other's class is unknown") elif other.level == LEVEL_NONNULL: if box and self.known_class.same_constant(cpu.ts.cls_of_box(box)): op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None) extra_guards.append(op) return else: raise VirtualStatesCantMatch("other's class is unknown") elif other.level == LEVEL_KNOWNCLASS: if self.known_class.same_constant(other.known_class): return raise VirtualStatesCantMatch("classes don't match") else: assert other.level == LEVEL_CONSTANT if (other.constbox.nonnull() and self.known_class.same_constant(cpu.ts.cls_of_box(other.constbox))): return else: raise VirtualStatesCantMatch("classes don't match") else: assert self.level == LEVEL_CONSTANT if other.level == LEVEL_CONSTANT: if self.constbox.same_constant(other.constbox): return raise VirtualStatesCantMatch("different constants") if box is not None and self.constbox.same_constant(box.constbox()): op = ResOperation(rop.GUARD_VALUE, [box, self.constbox], None) extra_guards.append(op) return else: raise VirtualStatesCantMatch("other not constant") assert 0, "unreachable" def _generate_guards_intbounds(self, other, box, extra_guards): if self.intbound.contains_bound(other.intbound): return if (box is not None and isinstance(box, BoxInt) and self.intbound.contains(box.getint())): # this may generate a few more guards than needed, but they are # optimized away when emitting them self.intbound.make_guards(box, extra_guards) return raise VirtualStatesCantMatch("intbounds don't match") def enum_forced_boxes(self, boxes, value, optimizer): if self.level == LEVEL_CONSTANT: return assert 0 <= self.position_in_notvirtuals if optimizer: box = value.force_box(optimizer) else: if value.is_virtual(): raise BadVirtualState box = value.get_key_box() boxes[self.position_in_notvirtuals] = box def _enum(self, virtual_state): if self.level == LEVEL_CONSTANT: return self.position_in_notvirtuals = virtual_state.numnotvirtuals virtual_state.numnotvirtuals += 1 def debug_print(self, indent, seen, bad, metainterp_sd=None): mark = '' if self in bad: mark = '*' if self.level == LEVEL_UNKNOWN: l = "Unknown" elif self.level == LEVEL_NONNULL: l = "NonNull" elif self.level == LEVEL_KNOWNCLASS: addr = self.known_class.getaddr() if metainterp_sd: name = metainterp_sd.get_name_from_address(addr) else: name = "?" l = "KnownClass(%s)" % name else: assert self.level == LEVEL_CONSTANT const = self.constbox if isinstance(const, ConstInt): l = "ConstInt(%s)" % (const.value, ) elif isinstance(const, ConstPtr): if const.value: l = "ConstPtr" else: l = "ConstPtr(null)" else: assert isinstance(const, ConstFloat) l = "ConstFloat(%s)" % const.getfloat() lb = '' if self.lenbound: lb = ', ' + self.lenbound.bound.__repr__() debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position + ', ' + l + ', ' + self.intbound.__repr__() + lb + ')')