def improve((ins1, ins2)): if ins1.classdef is None: resdef = ins2.classdef elif ins2.classdef is None: resdef = ins1.classdef else: basedef = ins1.classdef.commonbase(ins2.classdef) if basedef is ins1.classdef: resdef = ins2.classdef elif basedef is ins2.classdef: resdef = ins1.classdef else: if ins1.can_be_None and ins2.can_be_None: return s_None else: return s_ImpossibleValue res = SomeInstance( resdef, can_be_None=ins1.can_be_None and ins2.can_be_None) if ins1.contains(res) and ins2.contains(res): return res # fine else: # this case can occur in the presence of 'const' attributes, # which we should try to preserve. Fall-back... thistype = pairtype(SomeInstance, SomeInstance) return super(thistype, pair(ins1, ins2)).improve()
def is_((pbc1, pbc2)): thistype = pairtype(SomePBC, SomePBC) s = super(thistype, pair(pbc1, pbc2)).is_() if not s.is_constant(): if not pbc1.can_be_None or not pbc2.can_be_None: for desc in pbc1.descriptions: if desc in pbc2.descriptions: break else: s.const = False # no common desc in the two sets return s
class __extend__(pairtype(Lisp_Generator, Block)): def emit((gen, block), inputvars): gen.progn.append("(do 'something)")
class __extend__(pairtype(C_Generator, Jump)): def emit((gen, jump), inputvars): gen.lines.append("goto xyz")
class __extend__(pairtype(int, int)): def add((x, y)): return 'integer: %s+%s' % (x, y) def sub((x, y)): return 'integer: %s-%s' % (x, y)
class __extend__(pairtype(MiniPickler, str)): def write((pickler, x)): pickler.emit('S%s' % x)
class __extend__(pairtype(bool, bool)): def add((x, y)): return 'bool: %s+%s' % (x, y)
class __extend__(pairtype(ArrayRepr, ArrayRepr)): def convert_from_to((r_array0, r_array1), v, llops): assert 0
'getitem_idx', 'getitem_key', 'getitem_idx_key', 'inplace_add', 'inplace_sub', 'inplace_mul', 'inplace_truediv', 'inplace_floordiv', 'inplace_div', 'inplace_mod', 'inplace_pow', 'inplace_lshift', 'inplace_rshift', 'inplace_and', 'inplace_or', 'inplace_xor', 'lt', 'le', 'eq', 'ne', 'gt', 'ge', 'is_', 'cmp', 'coerce', ] +[opname+'_ovf' for opname in """add sub mul floordiv div mod pow lshift """.split() ]) for opname in BINARY_OPERATIONS: missing_operation(pairtype(SomeObject, SomeObject), opname) class __extend__(pairtype(SomeObject, SomeObject)): def union((obj1, obj2)): if obj1 == obj2: return obj1 else: result = SomeObject() if obj1.knowntype == obj2.knowntype and obj1.knowntype != object: result.knowntype = obj1.knowntype is_type_of1 = getattr(obj1, 'is_type_of', None) is_type_of2 = getattr(obj2, 'is_type_of', None) if obj1.is_immutable_constant() and obj2.is_immutable_constant() and obj1.const == obj2.const: result.const = obj1.const is_type_of = {}
class __extend__(pairtype(SomeDict, SomeDict)): def union((dic1, dic2)): return SomeDict(dic1.dictdef.union(dic2.dictdef))
class __extend__(pairtype(SomeLongFloat, SomeLongFloat)): def union((flt1, flt2)): return SomeLongFloat()
class __extend__(pairtype(SomeString, SomeObject)): def mod((str, args)): getbookkeeper().count('strformat', str, args) return SomeString()
class __extend__(pairtype(SomeString, SomeUnicodeString), pairtype(SomeUnicodeString, SomeString)): def mod((str, unistring)): raise NotImplementedError( "string formatting mixing strings and unicode not supported")
resulttype = r_ins2.lowleveltype) return v else: return NotImplemented def rtype_is_((r_ins1, r_ins2), hop): if r_ins1.gcflavor != r_ins2.gcflavor: # obscure logic, the is can be true only if both are None v_ins1, v_ins2 = hop.inputargs(r_ins1.common_repr(), r_ins2.common_repr()) return hop.gendirectcall(ll_both_none, v_ins1, v_ins2) if r_ins1.classdef is None or r_ins2.classdef is None: basedef = None else: basedef = r_ins1.classdef.commonbase(r_ins2.classdef) r_ins = getinstancerepr(r_ins1.rtyper, basedef, r_ins1.gcflavor) return pairtype(Repr, Repr).rtype_is_(pair(r_ins, r_ins), hop) rtype_eq = rtype_is_ def rtype_ne(rpair, hop): v = rpair.rtype_eq(hop) return hop.genop("bool_not", [v], resulttype=Bool) # ____________________________________________________________ # # Low-level implementation of operations on classes and instances # doesn't work for non-gc stuff! def ll_cast_to_object(obj): return cast_pointer(OBJECTPTR, obj)
# after converting all other arguments to PyObjRepr as well. This # basically defers the operations to the care of the code generator. def make_operation(opname, cls=PyObjRepr): def rtype_op(_, hop): vlist = hop.inputargs(*([pyobj_repr]*hop.nb_args)) hop.exception_is_here() v = hop.genop(opname, vlist, resulttype=pyobj_repr) if not isinstance(hop.r_result, VoidRepr): return hop.llops.convertvar(v, pyobj_repr, hop.r_result) funcname = 'rtype_' + opname func = func_with_new_name(rtype_op, funcname) assert funcname not in cls.__dict__ # can be in Repr; overridden then. setattr(cls, funcname, func) for opname in annmodel.UNARY_OPERATIONS: make_operation(opname) for opname in annmodel.BINARY_OPERATIONS: make_operation(opname, pairtype(PyObjRepr, Repr)) make_operation(opname, pairtype(Repr, PyObjRepr)) class __extend__(pairtype(PyObjRepr, PyObjRepr)): def rtype_contains((r_seq, r_item), hop): v_seq, v_item = hop.inputargs(r_seq, r_item) return hop.llops.gencapicall('PySequence_Contains_with_exc', [v_seq, v_item], resulttype=Bool)
# ____________________________________________________________ def make_missing_op(rcls, opname): attr = 'rtype_' + opname if not hasattr(rcls, attr): def missing_rtype_operation(self, hop): raise MissingRTypeOperation("unimplemented operation: " "'%s' on %r" % (opname, self)) setattr(rcls, attr, missing_rtype_operation) for opname in annmodel.UNARY_OPERATIONS: make_missing_op(Repr, opname) for opname in annmodel.BINARY_OPERATIONS: make_missing_op(pairtype(Repr, Repr), opname) # not in BINARY_OPERATIONS make_missing_op(pairtype(Repr, Repr), 'contains') class __extend__(pairtype(Repr, Repr)): def convert_from_to((r_from, r_to), v, llops): return NotImplemented # ____________________________________________________________ # Primitive Repr classes, in the same hierarchical order as # the corresponding SomeObjects class FloatRepr(Repr): lowleveltype = Float
class __extend__(pairtype(AddressRepr, AddressRepr)): def rtype_sub((r_addr1, r_addr2), hop): v_addr1, v_addr2 = hop.inputargs(Address, Address) return hop.genop('adr_delta', [v_addr1, v_addr2], resulttype=lltype.Signed)
class __extend__(pairtype(SomeInteger, SomeString), pairtype(SomeInteger, SomeUnicodeString)): def mul((int1, str2)): # xxx do we want to support this getbookkeeper().count("str_mul", str2, int1) return str2.basestringclass()
if isinstance(r_array1.lowleveltype, Primitive): r_array1, v_array1 = convert_scalar_to_array(r_array1, v_array1, hop.llops) elif isinstance(r_array1, AbstractBaseListRepr): r_array1, v_array1 = convert_list_to_array(r_array1, v_array1, hop.llops) elif not isinstance(r_array1, ArrayRepr): raise TyperError("can't operate with %s"%r_array1) if isinstance(r_array2.lowleveltype, Primitive): r_array2, v_array2 = convert_scalar_to_array(r_array2, v_array2, hop.llops) elif isinstance(r_array2, AbstractBaseListRepr): r_array2, v_array2 = convert_list_to_array(r_array2, v_array2, hop.llops) elif not isinstance(r_array2, ArrayRepr): raise TyperError("can't operate with %s"%r_array2) return _rtype_binop(r_array0, r_array1, r_array2, v_array1, v_array2, hop, binop) for tp in (pairtype(ArrayRepr, ArrayRepr), pairtype(ArrayRepr, Repr), pairtype(Repr, ArrayRepr)): for (binop, methname) in ((lambda a,b:a+b, "rtype_add"), (lambda a,b:a-b, "rtype_sub"), (lambda a,b:a*b, "rtype_mul"), (lambda a,b:a/b, "rtype_div")): setattr(tp, methname, lambda self, hop, binop=binop : rtype_binop(self, hop, binop)) #______________________________________________________________________________ def ll_array_inplace_binop(ITEM, it0, it1, binop): ll_assert(it0.size == it1.size, "it0.size == it1.size") while it0.index < it0.size: it0.dataptr[0] = cast_primitive(ITEM, binop(it0.dataptr[0], it1.dataptr[0])) it0.ll_next()
class __extend__(pairtype(SomeInteger, SomeList)): def mul((int1, lst2)): return lst2.listdef.offspring()
class __extend__(pairtype(AbstractRangeRepr, ArrayRepr)): def convert_from_to((r_rng, r_array), v, llops): cARRAY = inputconst(lltype.Void, r_array.lowleveltype.TO) return llops.gendirectcall(ll_build_from_list, cARRAY, v)
class __extend__(pairtype(SomeIterator, SomeIterator)): def union((iter1, iter2)): s_cont = unioncheck(iter1.s_container, iter2.s_container) if iter1.variant != iter2.variant: raise UnionError("merging incompatible iterators variants") return SomeIterator(s_cont, *iter1.variant)
class __extend__(pairtype(MiniPickler, int)): def write((pickler, x)): pickler.emit('I%d' % x)
class __extend__(pairtype(SomePBC, SomeGenericCallable)): def union((pbc, gencall)): return pair(gencall, pbc).union()
class __extend__(pairtype(MiniPickler, list)): def write((pickler, x)): for item in x: pair(pickler, item).write() pickler.emit('L%d' % len(x))
class __extend__(pairtype(SomeImpossibleValue, SomeObject)): def union((imp1, obj2)): return obj2
class __extend__(pairtype(C_Generator, Block)): def emit((gen, block), inputvars): gen.lines.append("C code for block") outputvars = inputvars + ['v4', 'v5'] pair(gen, block.exit).emit(outputvars)
class __extend__(pairtype(SomeObject, SomeImpossibleValue)): def union((obj1, imp2)): return obj1
class __extend__(pairtype(C_Generator, Switch)): def emit((gen, jump), inputvars): gen.lines.append("switch (%s) { ... }" % inputvars[-1])
class __extend__(pairtype(SomeObject, SomeObject)): def union((obj1, obj2)): if obj1 == obj2: return obj1 else: result = SomeObject() if obj1.knowntype == obj2.knowntype and obj1.knowntype != object: result.knowntype = obj1.knowntype is_type_of1 = getattr(obj1, 'is_type_of', None) is_type_of2 = getattr(obj2, 'is_type_of', None) if obj1.is_immutable_constant() and obj2.is_immutable_constant( ) and obj1.const == obj2.const: result.const = obj1.const is_type_of = {} if is_type_of1: for v in is_type_of1: is_type_of[v] = True if is_type_of2: for v in is_type_of2: is_type_of[v] = True if is_type_of: result.is_type_of = is_type_of.keys() else: if is_type_of1 and is_type_of1 == is_type_of2: result.is_type_of = is_type_of1 # try to preserve the origin of SomeObjects if obj1 == result: result = obj1 elif obj2 == result: result = obj2 unioncheck(result) return result # inplace_xxx ---> xxx by default def inplace_add((obj1, obj2)): return pair(obj1, obj2).add() def inplace_sub((obj1, obj2)): return pair(obj1, obj2).sub() def inplace_mul((obj1, obj2)): return pair(obj1, obj2).mul() def inplace_truediv((obj1, obj2)): return pair(obj1, obj2).truediv() def inplace_floordiv((obj1, obj2)): return pair(obj1, obj2).floordiv() def inplace_div((obj1, obj2)): return pair(obj1, obj2).div() def inplace_mod((obj1, obj2)): return pair(obj1, obj2).mod() def inplace_pow((obj1, obj2)): return pair(obj1, obj2).pow(s_None) def inplace_lshift((obj1, obj2)): return pair(obj1, obj2).lshift() def inplace_rshift((obj1, obj2)): return pair(obj1, obj2).rshift() def inplace_and((obj1, obj2)): return pair(obj1, obj2).and_() def inplace_or((obj1, obj2)): return pair(obj1, obj2).or_() def inplace_xor((obj1, obj2)): return pair(obj1, obj2).xor() for name, func in locals().items(): if name.startswith('inplace_'): func.can_only_throw = [] inplace_div.can_only_throw = [ZeroDivisionError] inplace_truediv.can_only_throw = [ZeroDivisionError] inplace_floordiv.can_only_throw = [ZeroDivisionError] inplace_mod.can_only_throw = [ZeroDivisionError] def lt((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const < obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) return s_Bool def le((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const <= obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) return s_Bool def eq((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const == obj2.const) else: getbookkeeper().count("non_int_eq", obj1, obj2) return s_Bool def ne((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const != obj2.const) else: getbookkeeper().count("non_int_eq", obj1, obj2) return s_Bool def gt((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const > obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) return s_Bool def ge((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const >= obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) return s_Bool def cmp((obj1, obj2)): getbookkeeper().count("cmp", obj1, obj2) if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(cmp(obj1.const, obj2.const)) else: return SomeInteger() def is_((obj1, obj2)): r = SomeBool() if obj2.is_constant(): if obj1.is_constant(): r.const = obj1.const is obj2.const if obj2.const is None and not obj1.can_be_none(): r.const = False elif obj1.is_constant(): if obj1.const is None and not obj2.can_be_none(): r.const = False # XXX HACK HACK HACK # XXX HACK HACK HACK # XXX HACK HACK HACK bk = getbookkeeper() if bk is not None: # for testing knowntypedata = r.knowntypedata = {} fn, block, i = bk.position_key annotator = bk.annotator op = block.operations[i] assert op.opname == "is_" assert len(op.args) == 2 def bind(src_obj, tgt_obj, tgt_arg): if hasattr(tgt_obj, 'is_type_of') and src_obj.is_constant(): add_knowntypedata(knowntypedata, True, tgt_obj.is_type_of, bk.valueoftype(src_obj.const)) assert annotator.binding(op.args[tgt_arg]) == tgt_obj add_knowntypedata(knowntypedata, True, [op.args[tgt_arg]], src_obj) nonnone_obj = tgt_obj if src_obj.is_constant( ) and src_obj.const is None and tgt_obj.can_be_none(): nonnone_obj = tgt_obj.nonnoneify() add_knowntypedata(knowntypedata, False, [op.args[tgt_arg]], nonnone_obj) bind(obj2, obj1, 0) bind(obj1, obj2, 1) return r def divmod((obj1, obj2)): getbookkeeper().count("divmod", obj1, obj2) return SomeTuple([pair(obj1, obj2).div(), pair(obj1, obj2).mod()]) def coerce((obj1, obj2)): getbookkeeper().count("coerce", obj1, obj2) return pair(obj1, obj2).union() # reasonable enough # approximation of an annotation intersection, the result should be the annotation obj or # the intersection of obj and improvement def improve((obj, improvement)): if not improvement.contains(obj) and obj.contains(improvement): return improvement else: return obj # checked getitems def _getitem_can_only_throw(s_c1, s_o2): impl = pair(s_c1, s_o2).getitem return read_can_only_throw(impl, s_c1, s_o2) def getitem_idx_key((s_c1, s_o2)): impl = pair(s_c1, s_o2).getitem return impl() getitem_idx_key.can_only_throw = _getitem_can_only_throw getitem_idx = getitem_idx_key getitem_key = getitem_idx_key
class __extend__(pairtype(StatResultRepr, IntegerRepr)): def rtype_getitem((r_sta, r_int), hop): s_int = hop.args_s[1] index = s_int.const return r_sta.redispatch_getfield(hop, index)
class __extend__(pairtype(SomeString, SomePBC)): def add((o, pbc)): if not pbc.isNone(): raise AnnotatorError('add on %r' % pbc) return s_ImpossibleValue
class __extend__(pairtype(BoolRepr, PyObjRepr)): def convert_from_to((r_from, r_to), v, llops): if r_from.lowleveltype == Bool: return llops.gencapicall('PyBool_FromLong', [v], resulttype=pyobj_repr) return NotImplemented
class __extend__(pairtype(SomeExternalObject, SomeExternalObject)): def union((ext1, ext2)): if ext1.knowntype == ext2.knowntype: return SomeExternalObject(ext1.knowntype) return SomeObject()
class __extend__(pairtype(PtrRepr, AddressRepr)): def convert_from_to((r_ptr, r_addr), v, llops): return llops.genop('cast_ptr_to_adr', [v], resulttype=Address)
class __extend__(pairtype(SomePtr, SomePtr)): def union((p1, p2)): assert p1.ll_ptrtype == p2.ll_ptrtype, ( "mixing of incompatible pointer types: %r, %r" % (p1.ll_ptrtype, p2.ll_ptrtype)) return SomePtr(p1.ll_ptrtype)
elif not isinstance(r_array1, ArrayRepr): raise TyperError("can't operate with %s" % r_array1) if isinstance(r_array2.lowleveltype, Primitive): r_array2, v_array2 = convert_scalar_to_array(r_array2, v_array2, hop.llops) elif isinstance(r_array2, AbstractBaseListRepr): r_array2, v_array2 = convert_list_to_array(r_array2, v_array2, hop.llops) elif not isinstance(r_array2, ArrayRepr): raise TyperError("can't operate with %s" % r_array2) return _rtype_binop(r_array0, r_array1, r_array2, v_array1, v_array2, hop, binop) for tp in (pairtype(ArrayRepr, ArrayRepr), pairtype(ArrayRepr, Repr), pairtype(Repr, ArrayRepr)): for (binop, methname) in ((lambda a, b: a + b, "rtype_add"), (lambda a, b: a - b, "rtype_sub"), (lambda a, b: a * b, "rtype_mul"), (lambda a, b: a / b, "rtype_div")): setattr(tp, methname, lambda self, hop, binop=binop: rtype_binop(self, hop, binop)) #______________________________________________________________________________ def ll_array_inplace_binop(ITEM, it0, it1, binop): ll_assert(it0.size == it1.size, "it0.size == it1.size") while it0.index < it0.size:
d = newset(hs_c1.origins, hs_c2.origins, {origin: True}) RESTYPE = bk.current_op_concretetype() hs_res = SomeLLAbstractConstant(RESTYPE, d, eager_concrete = hs_c1.eager_concrete or hs_c2.eager_concrete, myorigin = origin) if hs_c1.is_constant() and hs_c2.is_constant(): try: hs_res.const = llop(RESTYPE, hs_c1.const, hs_c2.const) except Exception: # XXX not too nice pass return hs_res def setup(oplist, ValueCls, var_fn, ConstantCls, const_fn): for name in oplist: llop = getattr(lloperation.llop, name) if not llop.sideeffects or llop.tryfold: if name not in ValueCls.__dict__: setattr(ValueCls, name, var_fn) if llop.canfold or llop.tryfold: if name not in ConstantCls.__dict__: setattr(ConstantCls, name, lambda s, llop=llop: const_fn(llop, s)) setup(UNARY_OPERATIONS, SomeLLAbstractValue, var_unary, SomeLLAbstractConstant, const_unary) setup(BINARY_OPERATIONS, pairtype(SomeLLAbstractValue, SomeLLAbstractValue), var_binary, pairtype(SomeLLAbstractConstant, SomeLLAbstractConstant), const_binary) del setup