def rtyper_makerepr(self, rtyper): from rpython.rtyper.lltypesystem.rpbc import (FunctionsPBCRepr, SmallFunctionSetPBCRepr) kind = self.getKind() if issubclass(kind, description.FunctionDesc): sample = self.any_description() callfamily = sample.querycallfamily() if callfamily and callfamily.total_calltable_size > 0: getRepr = FunctionsPBCRepr if small_cand(rtyper, self): getRepr = SmallFunctionSetPBCRepr else: getRepr = getFrozenPBCRepr elif issubclass(kind, description.ClassDesc): # user classes getRepr = ClassesPBCRepr elif issubclass(kind, description.MethodDesc): getRepr = MethodsPBCRepr elif issubclass(kind, description.FrozenDesc): getRepr = getFrozenPBCRepr elif issubclass(kind, description.MethodOfFrozenDesc): getRepr = MethodOfFrozenPBCRepr else: raise TyperError("unexpected PBC kind %r" % (kind, )) return getRepr(rtyper, self)
def rtype_raw_memcopy(hop): for s_addr in hop.args_s[:2]: if s_addr.is_null_address(): raise TyperError("raw_memcopy() with a constant NULL") v_list = hop.inputargs(llmemory.Address, llmemory.Address, lltype.Signed) hop.exception_cannot_occur() return hop.genop('raw_memcopy', v_list)
def rtype_raw_memclear(hop): s_addr = hop.args_s[0] if s_addr.is_null_address(): raise TyperError("raw_memclear(x, n) where x is the constant NULL") v_list = hop.inputargs(llmemory.Address, lltype.Signed) hop.exception_cannot_occur() return hop.genop('raw_memclear', v_list)
def rtype_builtin_range(hop): vstep = hop.inputconst(Signed, 1) if hop.nb_args == 1: vstart = hop.inputconst(Signed, 0) vstop, = hop.inputargs(Signed) elif hop.nb_args == 2: vstart, vstop = hop.inputargs(Signed, Signed) else: vstart, vstop, vstep = hop.inputargs(Signed, Signed, Signed) if isinstance(vstep, Constant) and vstep.value == 0: # not really needed, annotator catches it. Just in case... raise TyperError("range cannot have a const step of zero") if isinstance(hop.r_result, AbstractRangeRepr): if hop.r_result.step != 0: c_rng = hop.inputconst(Void, hop.r_result.RANGE) hop.exception_is_here() return hop.gendirectcall(hop.r_result.ll_newrange, c_rng, vstart, vstop) else: hop.exception_is_here() return hop.gendirectcall(hop.r_result.ll_newrangest, vstart, vstop, vstep) else: # cannot build a RANGE object, needs a real list r_list = hop.r_result ITEMTYPE = r_list.lowleveltype if isinstance(ITEMTYPE, Ptr): ITEMTYPE = ITEMTYPE.TO cLIST = hop.inputconst(Void, ITEMTYPE) hop.exception_is_here() return hop.gendirectcall(ll_range2list, cLIST, vstart, vstop, vstep)
def exception_cannot_occur(self): self.llops._called_exception_is_here_or_cannot_occur = True if self.llops.llop_raising_exceptions is not None: raise TyperError("cannot catch an exception at more than one llop") if not self.exceptionlinks: return # ignored for high-level ops before the last one in the block self.llops.llop_raising_exceptions = "removed"
def parse_fmt_string(fmt): # we support x, d, s, f, [r] it = iter(fmt) r = [] curstr = '' for c in it: if c == '%': f = it.next() if f == '%': curstr += '%' continue if curstr: r.append(curstr) curstr = '' if f not in 'xdosrf': raise TyperError( "Unsupported formatting specifier: %r in %r" % (f, fmt)) r.append((f, )) else: curstr += c if curstr: r.append(curstr) return r
def rtype_raw_free(hop): s_addr = hop.args_s[0] if s_addr.is_null_address(): raise TyperError("raw_free(x) where x is the constant NULL") v_addr, = hop.inputargs(llmemory.Address) hop.exception_cannot_occur() return hop.genop('raw_free', [v_addr])
def _rtype_template(hop, func): """Write a simple operation implementing the given 'func'. It must be an operation that cannot raise. """ r_result = hop.r_result if r_result.lowleveltype == Bool: repr = signed_repr else: repr = r_result if func.startswith(('lshift', 'rshift')): repr2 = signed_repr else: repr2 = repr vlist = hop.inputargs(repr, repr2) prefix = repr.opprefix if '_ovf' in func or func.startswith(('py_mod', 'py_div')): if prefix + func not in ('int_add_ovf', 'int_add_nonneg_ovf', 'int_sub_ovf', 'int_mul_ovf'): raise TyperError("%r should not be used here any more" % (func, )) hop.has_implicit_exception(OverflowError) hop.exception_is_here() else: hop.exception_cannot_occur() v_res = hop.genop(prefix + func, vlist, resulttype=repr) v_res = hop.llops.convertvar(v_res, repr, r_result) return v_res
def convert_const(self, value): if isinstance(value, objectmodel.Symbolic): return value T = typeOf(value) if isinstance(T, Number) or T is Bool: return cast_primitive(self.lowleveltype, value) raise TyperError("not an integer: %r" % (value, ))
def buildinstancerepr(rtyper, classdef, gcflavor='gc'): from rpython.rtyper.rvirtualizable import VirtualizableInstanceRepr if classdef is None: unboxed = [] virtualizable = False else: unboxed = [ subdef for subdef in classdef.getallsubdefs() if subdef.classdesc.pyobj is not None and issubclass(subdef.classdesc.pyobj, UnboxedValue) ] virtualizable = classdef.classdesc.read_attribute( '_virtualizable_', Constant(False)).value config = rtyper.annotator.translator.config usetagging = len(unboxed) != 0 and config.translation.taggedpointers if virtualizable: assert len(unboxed) == 0 assert gcflavor == 'gc' return VirtualizableInstanceRepr(rtyper, classdef) elif usetagging: # the UnboxedValue class and its parent classes need a # special repr for their instances if len(unboxed) != 1: raise TyperError("%r has several UnboxedValue subclasses" % (classdef, )) assert gcflavor == 'gc' from rpython.rtyper.lltypesystem import rtagged return rtagged.TaggedInstanceRepr(rtyper, classdef, unboxed[0]) else: return InstanceRepr(rtyper, classdef, gcflavor)
def convert_const(self, weakdict): if weakdict is None: return lltype.nullptr(self.WEAKDICT) if not isinstance(weakdict, RWeakValueDictionary): raise TyperError("expected an RWeakValueDictionary: %r" % (weakdict, )) try: key = Constant(weakdict) return self.dict_cache[key] except KeyError: self.setup() l_dict = self.ll_new_weakdict() self.dict_cache[key] = l_dict bk = self.rtyper.annotator.bookkeeper classdef = bk.getuniqueclassdef(weakdict._valueclass) r_value = getinstancerepr(self.rtyper, classdef) any_value = False for dictkey, dictvalue in weakdict._dict.items(): llkey = self.r_key.convert_const(dictkey) llvalue = r_value.convert_const(dictvalue) if llvalue: llvalue = lltype.cast_pointer(rclass.OBJECTPTR, llvalue) self.ll_set_nonnull(l_dict, llkey, llvalue) any_value = True if any_value: l_dict.resize_counter = -1 return l_dict
def getpbcfield(self, vcls, access_set, attr, llops): if (access_set, attr) not in self.pbcfields: raise TyperError("internal error: missing PBC field") mangled_name, r = self.pbcfields[access_set, attr] v_vtable = self.fromtypeptr(vcls, llops) cname = inputconst(Void, mangled_name) return llops.genop('getfield', [v_vtable, cname], resulttype=r)
def _parse_field_list(self, fields, accessor, hints): ranking = {} for name in fields: quasi = False if name.endswith('?[*]'): # a quasi-immutable field pointing to name = name[:-4] # an immutable array rank = IR_QUASIIMMUTABLE_ARRAY quasi = True elif name.endswith('[*]'): # for virtualizables' lists name = name[:-3] rank = IR_IMMUTABLE_ARRAY elif name.endswith('?'): # a quasi-immutable field name = name[:-1] rank = IR_QUASIIMMUTABLE quasi = True else: # a regular immutable/green field rank = IR_IMMUTABLE try: mangled_name, r = self._get_field(name) except KeyError: continue if quasi and hints.get("immutable"): raise TyperError( "can't have _immutable_ = True and a quasi-immutable field " "%s in class %s" % (name, self.classdef)) ranking[mangled_name] = rank accessor.initialize(self.object_type, ranking) return ranking
def commonbase(classdefs): result = classdefs[0] for cdef in classdefs[1:]: result = result.commonbase(cdef) if result is None: raise TyperError("no common base class in %r" % (classdefs, )) return result
def rtyper_makerepr(self, rtyper): kind = self.getKind() if issubclass(kind, FunctionDesc): if len(self.descriptions) == 1 and not self.can_be_None: getRepr = FunctionRepr else: sample = self.any_description() callfamily = sample.querycallfamily() if callfamily and callfamily.total_calltable_size > 0: getRepr = FunctionsPBCRepr if small_cand(rtyper, self): getRepr = SmallFunctionSetPBCRepr else: getRepr = getFrozenPBCRepr elif issubclass(kind, ClassDesc): # user classes getRepr = ClassesPBCRepr elif issubclass(kind, MethodDesc): getRepr = MethodsPBCRepr elif issubclass(kind, FrozenDesc): getRepr = getFrozenPBCRepr elif issubclass(kind, MethodOfFrozenDesc): getRepr = MethodOfFrozenPBCRepr else: raise TyperError("unexpected PBC kind %r" % (kind,)) return getRepr(rtyper, self)
def rtype_r_dict(hop, i_force_non_null=None): from rpython.rlib import jit r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") cDICT = hop.inputconst(ootype.Void, r_dict.DICT) hop.exception_cannot_occur() # the signature of oonewcustomdict is a bit complicated because we # can have three different ways to pass the equal (and hash) # callables: # 1. pass a plain function: eqfn is a StaticMethod, v_eqobj # and eq_method_name are None # 2. pass a bound method: eqfn is None, v_eqobj is the # instance, eq_method_name is the name of the method, # 3. pass a method of a frozen PBC: eqfn is a StaticMethod, v_eqobj is a # non-None Void value (to be ignored by all the backends except the # llinterp), eq_method_name is None s_key = r_dict.dictkey.s_value eqfn, v_eqobj, eq_method_name =\ _get_call_args(hop, r_dict.r_rdict_eqfn, 0, [s_key, s_key]) hashfn, v_hashobj, hash_method_name =\ _get_call_args(hop, r_dict.r_rdict_hashfn, 1, [s_key]) @jit.dont_look_inside def ll_newcustomdict(DICT, v_eqobj, v_hashobj): from rpython.rtyper.lltypesystem.lloperation import llop return llop.oonewcustomdict(DICT, DICT, eqfn, v_eqobj, eq_method_name, hashfn, v_hashobj, hash_method_name) ll_newcustomdict._dont_inline_ = True return hop.gendirectcall(ll_newcustomdict, cDICT, v_eqobj, v_hashobj)
def specialize_call(self, hop): if not isinstance(hop.args_r[1], ControlledInstanceRepr): raise TyperError("unbox() should take a ControlledInstanceRepr,\n" "got %r" % (hop.args_r[1], )) hop.exception_cannot_occur() v = hop.inputarg(hop.args_r[1], arg=1) return hop.llops.convertvar(v, hop.args_r[1].r_real_obj, hop.r_result)
def merge_classpbc_getattr_into_classdef(annotator): # code like 'some_class.attr' will record an attribute access in the # PBC access set of the family of classes of 'some_class'. If the classes # have corresponding ClassDefs, they are not updated by the annotator. # We have to do it now. all_families = annotator.bookkeeper.classpbc_attr_families for attrname, access_sets in all_families.items(): for access_set in access_sets.infos(): descs = access_set.descs if len(descs) <= 1: continue if not isinstance(descs.iterkeys().next(), description.ClassDesc): continue classdefs = [desc.getuniqueclassdef() for desc in descs] commonbase = classdefs[0] for cdef in classdefs[1:]: commonbase = commonbase.commonbase(cdef) if commonbase is None: raise TyperError("reading attribute %r: no common base " "class for %r" % (attrname, descs.keys())) extra_access_sets = commonbase.extra_access_sets if commonbase.repr is not None: assert access_set in extra_access_sets # minimal sanity check continue access_set.commonbase = commonbase if access_set not in extra_access_sets: counter = len(extra_access_sets) extra_access_sets[access_set] = attrname, counter
def rtype_hlinvoke(hop): _, s_repr = hop.r_s_popfirstarg() r_callable = s_repr.const r_func, nimplicitarg = r_callable.get_r_implfunc() s_callable = r_callable.get_s_callable() nbargs = len(hop.args_s) - 1 + nimplicitarg s_sigs = r_func.get_s_signatures((nbargs, (), False)) if len(s_sigs) != 1: raise TyperError("cannot hlinvoke callable %r with not uniform" "annotations: %r" % (r_callable, s_sigs)) args_s, s_ret = s_sigs[0] rinputs = [hop.rtyper.getrepr(s_obj) for s_obj in args_s] rresult = hop.rtyper.getrepr(s_ret) args_s = args_s[nimplicitarg:] rinputs = rinputs[nimplicitarg:] new_args_r = [r_callable] + rinputs for i in range(len(new_args_r)): assert hop.args_r[i].lowleveltype == new_args_r[i].lowleveltype hop.args_r = new_args_r hop.args_s = [s_callable] + args_s hop.s_result = s_ret assert hop.r_result.lowleveltype == rresult.lowleveltype hop.r_result = rresult return hop.dispatch()
def rtype_method_replace(self, hop): rstr = hop.args_r[0].repr if not (hop.args_r[1] == rstr.char_repr and hop.args_r[2] == rstr.char_repr): raise TyperError('replace only works for char args') v_str, v_c1, v_c2 = hop.inputargs(rstr.repr, rstr.char_repr, rstr.char_repr) hop.exception_cannot_occur() return hop.gendirectcall(self.ll.ll_replace_chr_chr, v_str, v_c1, v_c2)
def _setup_repr_final(self): self._setup_immutable_field_list() self._check_for_immutable_conflicts() if self.gcflavor == 'gc': if (self.classdef is not None and self.classdef.classdesc.lookup('__del__') is not None): s_func = self.classdef.classdesc.s_read_attribute('__del__') source_desc = self.classdef.classdesc.lookup('__del__') source_classdef = source_desc.getclassdef(None) source_repr = getinstancerepr(self.rtyper, source_classdef) assert len(s_func.descriptions) == 1 funcdesc, = s_func.descriptions graph = funcdesc.getuniquegraph() self.check_graph_of_del_does_not_call_too_much( self.rtyper, graph) FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void) destrptr = functionptr(FUNCTYPE, graph.name, graph=graph, _callable=graph.func) else: destrptr = None self.rtyper.call_all_setups() # compute ForwardReferences now args_s = [SomePtr(Ptr(OBJECT))] graph = self.rtyper.annotate_helper(ll_runtime_type_info, args_s) s = self.rtyper.annotation(graph.getreturnvar()) if (not isinstance(s, SomePtr) or s.ll_ptrtype != Ptr(RuntimeTypeInfo)): raise TyperError("runtime type info function returns %r, " "expected Ptr(RuntimeTypeInfo)" % (s)) funcptr = self.rtyper.getcallable(graph) attachRuntimeTypeInfo(self.object_type, funcptr, destrptr) vtable = self.rclass.getvtable() self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
def specialize_more_blocks(self): if self.already_seen: newtext = ' more' else: newtext = '' blockcount = 0 self.annmixlevel = None while True: # look for blocks not specialized yet pending = [ block for block in self.annotator.annotated if block not in self.already_seen ] if not pending: break # shuffle blocks a bit if self.seed: import random r = random.Random(self.seed) r.shuffle(pending) if self.order: tracking = self.order(self.annotator, pending) else: tracking = lambda block: None previous_percentage = 0 # specialize all blocks in the 'pending' list for block in pending: tracking(block) blockcount += 1 self.specialize_block(block) self.already_seen[block] = True # progress bar n = len(self.already_seen) if n % 100 == 0: total = len(self.annotator.annotated) percentage = 100 * n // total if percentage >= previous_percentage + 5: previous_percentage = percentage if self.typererror_count: error_report = " but %d errors" % self.typererror_count else: error_report = '' self.log.event( 'specializing: %d / %d blocks (%d%%)%s' % (n, total, percentage, error_report)) # make sure all reprs so far have had their setup() called self.call_all_setups() if self.typererrors: self.dump_typererrors(to_log=True) raise TyperError("there were %d error" % len(self.typererrors)) self.log.event('-=- specialized %d%s blocks -=-' % (blockcount, newtext)) annmixlevel = self.annmixlevel del self.annmixlevel if annmixlevel is not None: annmixlevel.finish()
def rtype_getattr(self, hop): s_attr = hop.args_s[1] attr = s_attr.const try: index = self.statvfs_field_indexes[attr] except KeyError: raise TyperError("os.statvfs().%s: field not available" % (attr, )) return self.redispatch_getfield(hop, index)
class __extend__(pairtype(OOInstanceRepr, IntegerRepr)): def rtype_getitem((r_inst, r_int), hop): if not r_inst.lowleveltype._isArray: raise TyperError("getitem() on a non-array instance") v_array, v_index = hop.inputargs(r_inst, ootype.Signed) hop.exception_is_here() return hop.genop('cli_getelem', [v_array, v_index], hop.r_result.lowleveltype)
def convert_desc(self, desc): if desc not in self.s_pbc.descriptions: raise TyperError("%r not in %r" % (desc, self)) if self.lowleveltype is Void: return None subclassdef = desc.getuniqueclassdef() r_subclass = rclass.getclassrepr(self.rtyper, subclassdef) return r_subclass.getruntime(self.lowleveltype)
def _call(self, hop2, **kwds_i): bltintyper = self.findbltintyper(hop2.rtyper) hop2.llops._called_exception_is_here_or_cannot_occur = False v_result = bltintyper(hop2, **kwds_i) if not hop2.llops._called_exception_is_here_or_cannot_occur: raise TyperError("missing hop.exception_cannot_occur() or " "hop.exception_is_here() in %s" % bltintyper) return v_result
def make_iterator_repr(self, *variant): if not variant: return ListIteratorRepr(self) elif variant == ("reversed", ): return ReversedListIteratorRepr(self) else: raise TyperError("unsupported %r iterator over a list" % (variant, ))
def convert_desc_or_const(self, desc_or_const): if isinstance(desc_or_const, description.Desc): return self.convert_desc(desc_or_const) elif isinstance(desc_or_const, Constant): return self.convert_const(desc_or_const.value) else: raise TyperError("convert_desc_or_const expects a Desc" "or Constant: %r" % desc_or_const)
def translate_hl_to_ll(self, hop, varmapping): #self.log.translating(hop.spaceop.opname, hop.args_s) resultvar = hop.dispatch() if hop.exceptionlinks and hop.llops.llop_raising_exceptions is None: raise TyperError( "the graph catches %s, but the rtyper did not " "take exceptions into account " "(exception_is_here() not called)" % ([link.exitcase.__name__ for link in hop.exceptionlinks], )) if resultvar is None: # no return value self.translate_no_return_value(hop) else: assert isinstance(resultvar, (Variable, Constant)) op = hop.spaceop # for simplicity of the translate_meth, resultvar is usually not # op.result here. We have to replace resultvar with op.result # in all generated operations. if hop.s_result.is_constant(): if isinstance(resultvar, Constant) and \ isinstance(hop.r_result.lowleveltype, Primitive) and \ hop.r_result.lowleveltype is not Void: assert resultvar.value == hop.s_result.const resulttype = resultvar.concretetype op.result.concretetype = hop.r_result.lowleveltype if op.result.concretetype != resulttype: raise TyperError("inconsistent type for the result of '%s':\n" "annotator says %s,\n" "whose repr is %r\n" "but rtype_%s returned %r" % (op.opname, hop.s_result, hop.r_result, op.opname, resulttype)) # figure out if the resultvar is a completely fresh Variable or not if (isinstance(resultvar, Variable) and resultvar.annotation is None and resultvar not in varmapping): # fresh Variable: rename it to the previously existing op.result varmapping[resultvar] = op.result elif resultvar is op.result: # special case: we got the previous op.result Variable again assert varmapping[resultvar] is resultvar else: # renaming unsafe. Insert a 'same_as' operation... hop.llops.append( SpaceOperation('same_as', [resultvar], op.result))
def rtype_method_encode(self, hop): if not hop.args_s[1].is_constant(): raise TyperError("encoding must be constant") encoding = hop.args_s[1].const if encoding == "ascii" and self.lowleveltype == UniChar: expect = UniChar # only for unichar.encode('ascii') else: expect = self.repr # must be a regular unicode string v_self = hop.inputarg(expect, 0) hop.exception_is_here() if encoding == "ascii": return hop.gendirectcall(self.ll_str, v_self) elif encoding == "latin-1": return hop.gendirectcall(self.ll_encode_latin1, v_self) elif encoding == 'utf-8' or encoding == 'utf8': return hop.gendirectcall(self.ll_encode_utf8, v_self) else: raise TyperError("encoding %s not implemented" % (encoding, ))