def gct_fv_gc_coalloc(self, hop, coallocator, flags, TYPE, *args): if self.coalloc_clear_ptr is None: return self.gct_fv_gc_malloc( hop, flags, TYPE, *args) op = hop.spaceop flavor = flags['flavor'] assert not flags.get("nocollect", False) PTRTYPE = op.result.concretetype assert PTRTYPE.TO == TYPE type_id = self.get_type_id(TYPE) c_type_id = rmodel.inputconst(lltype.Signed, type_id) info = self.layoutbuilder.type_info_list[type_id] c_size = rmodel.inputconst(lltype.Signed, info.fixedsize) has_finalizer = bool(self.finalizer_funcptr_for_type(TYPE)) assert not has_finalizer v_coallocator = gen_cast(hop.llops, llmemory.Address, coallocator) if not op.opname.endswith('_varsize'): malloc_ptr = self.coalloc_clear_ptr args = [self.c_const_gc, v_coallocator, c_type_id, c_size] else: v_length = op.args[-1] c_ofstolength = rmodel.inputconst(lltype.Signed, info.ofstolength) c_varitemsize = rmodel.inputconst(lltype.Signed, info.varitemsize) malloc_ptr = self.coalloc_varsize_clear_ptr args = [self.c_const_gc, v_coallocator, c_type_id, v_length, c_size, c_varitemsize, c_ofstolength] livevars = self.push_roots(hop) v_result = hop.genop("direct_call", [malloc_ptr] + args, resulttype=llmemory.GCREF) self.pop_roots(hop, livevars) return v_result
def gct_weakref_create(self, hop): op = hop.spaceop type_id = self.get_type_id(WEAKREF) c_type_id = rmodel.inputconst(lltype.Signed, type_id) info = self.layoutbuilder.type_info_list[type_id] c_size = rmodel.inputconst(lltype.Signed, info.fixedsize) malloc_ptr = self.malloc_fixedsize_ptr c_has_finalizer = rmodel.inputconst(lltype.Bool, False) c_has_weakptr = c_can_collect = rmodel.inputconst(lltype.Bool, True) args = [self.c_const_gc, c_type_id, c_size, c_can_collect, c_has_finalizer, c_has_weakptr] # push and pop the current live variables *including* the argument # to the weakref_create operation, which must be kept alive and # moved if the GC needs to collect livevars = self.push_roots(hop, keep_current_args=True) v_result = hop.genop("direct_call", [malloc_ptr] + args, resulttype=llmemory.GCREF) v_result = hop.genop("cast_opaque_ptr", [v_result], resulttype=WEAKREFPTR) self.pop_roots(hop, livevars) # cast_ptr_to_adr must be done after malloc, as the GC pointer # might have moved just now. v_instance, = op.args v_addr = hop.genop("cast_ptr_to_adr", [v_instance], resulttype=llmemory.Address) hop.genop("bare_setfield", [v_result, rmodel.inputconst(lltype.Void, "weakptr"), v_addr]) v_weakref = hop.genop("cast_ptr_to_weakrefptr", [v_result], resulttype=llmemory.WeakRefPtr) hop.cast_result(v_weakref)
def dispatcher(self, shape, index, argtypes, resulttype): key = shape, index, tuple(argtypes), resulttype if key in self._dispatch_cache: return self._dispatch_cache[key] from pypy.translator.unsimplify import varoftype from pypy.objspace.flow.model import FunctionGraph, Link, Block, SpaceOperation inputargs = [varoftype(t) for t in [Char] + argtypes] startblock = Block(inputargs) startblock.exitswitch = inputargs[0] graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype)) row_of_graphs = self.callfamily.calltables[shape][index] links = [] descs = list(self.s_pbc.descriptions) if self.s_pbc.can_be_None: descs.insert(0, None) for desc in descs: if desc is None: continue args_v = [varoftype(t) for t in argtypes] b = Block(args_v) llfn = self.rtyper.getcallable(row_of_graphs[desc]) v_fn = inputconst(typeOf(llfn), llfn) v_result = varoftype(resulttype) b.operations.append( SpaceOperation("direct_call", [v_fn] + args_v, v_result)) b.closeblock(Link([v_result], graph.returnblock)) i = self.descriptions.index(desc) links.append(Link(inputargs[1:], b, chr(i))) links[-1].llexitcase = chr(i) startblock.closeblock(*links) self.rtyper.annotator.translator.graphs.append(graph) ll_ret = self.rtyper.type_system.getcallable(graph) #FTYPE = FuncType c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret) return c_ret
def gettype_from_unboxed(self, llops, vinst): unboxedclass_repr = getclassrepr(self.rtyper, self.unboxedclassdef) cunboxedcls = inputconst(CLASSTYPE, unboxedclass_repr.getvtable()) if self.is_parent: # If the lltype of vinst shows that it cannot be a tagged value, # we can directly read the typeptr. Otherwise, call a helper that # checks if the tag bit is set in the pointer. unboxedinstance_repr = getinstancerepr(self.rtyper, self.unboxedclassdef) try: lltype.castable(unboxedinstance_repr.lowleveltype, vinst.concretetype) except lltype.InvalidCast: can_be_tagged = False else: can_be_tagged = True vinst = llops.genop('cast_pointer', [vinst], resulttype=self.common_repr()) if can_be_tagged: return llops.gendirectcall(ll_unboxed_getclass, vinst, cunboxedcls) else: ctypeptr = inputconst(lltype.Void, 'typeptr') return llops.genop('getfield', [vinst, ctypeptr], resulttype=CLASSTYPE) else: return cunboxedcls
def get_resume_point_link(self, block): try: return self.resumepoints[block] except KeyError: resumeblock = Block([]) redcount = 0 greencount = 0 newvars = [] for v in block.inputargs: if v.concretetype is lltype.Void: v1 = self.c_dummy elif self.hannotator.binding(v).is_green(): c = inputconst(lltype.Signed, greencount) v1 = self.genop(resumeblock, 'restore_green', [c], result_like = v) greencount += 1 else: c = inputconst(lltype.Signed, redcount) v1 = self.genop(resumeblock, 'restore_local', [c], result_like = v) redcount += 1 newvars.append(v1) resumeblock.closeblock(Link(newvars, block)) reenter_link = Link([], resumeblock) N = len(self.resumepoints) reenter_link.exitcase = N self.resumepoints[block] = reenter_link return reenter_link
def gettype_from_unboxed(self, llops, vinst, can_be_none=False): unboxedclass_repr = getclassrepr(self.rtyper, self.unboxedclassdef) cunboxedcls = inputconst(CLASSTYPE, unboxedclass_repr.getvtable()) if self.is_parent: # If the lltype of vinst shows that it cannot be a tagged value, # we can directly read the typeptr. Otherwise, call a helper that # checks if the tag bit is set in the pointer. unboxedinstance_repr = getinstancerepr(self.rtyper, self.unboxedclassdef) try: lltype.castable(unboxedinstance_repr.lowleveltype, vinst.concretetype) except lltype.InvalidCast: can_be_tagged = False else: can_be_tagged = True vinst = llops.genop('cast_pointer', [vinst], resulttype=self.common_repr()) if can_be_tagged: if can_be_none: func = ll_unboxed_getclass_canbenone else: func = ll_unboxed_getclass return llops.gendirectcall(func, vinst, cunboxedcls) elif can_be_none: return llops.gendirectcall(ll_inst_type, vinst) else: ctypeptr = inputconst(lltype.Void, 'typeptr') return llops.genop('getfield', [vinst, ctypeptr], resulttype = CLASSTYPE) else: return cunboxedcls
def _generate_newlist(self, llops, items_v, v_sizehint): c_list = inputconst(ootype.Void, self.lowleveltype) v_result = llops.genop("new", [c_list], resulttype=self.lowleveltype) c_resize = inputconst(ootype.Void, "_ll_resize") c_length = inputconst(ootype.Signed, len(items_v)) llops.genop("oosend", [c_resize, v_result, c_length], resulttype=ootype.Void) return v_result
def new_instance(self, llops, classcallhop=None): """Build a new instance, without calling __init__.""" flavor = self.gcflavor flags = {'flavor': flavor} ctype = inputconst(Void, self.object_type) cflags = inputconst(Void, flags) vlist = [ctype, cflags] vptr = llops.genop('malloc', vlist, resulttype=Ptr(self.object_type)) ctypeptr = inputconst(CLASSTYPE, self.rclass.getvtable()) self.setfield(vptr, '__class__', ctypeptr, llops) # initialize instance attributes from their defaults from the class if self.classdef is not None: flds = self.allinstancefields.keys() flds.sort() for fldname in flds: if fldname == '__class__': continue mangled_name, r = self.allinstancefields[fldname] if r.lowleveltype is Void: continue value = self.classdef.classdesc.read_attribute(fldname, None) if value is not None: cvalue = inputconst(r.lowleveltype, r.convert_desc_or_const(value)) self.setfield(vptr, fldname, cvalue, llops, flags={'access_directly': True}) return vptr
def rtype_bltn_list(self, hop): from pypy.rpython.ootypesystem import rlist v_tup = hop.inputarg(self, 0) RESULT = hop.r_result.lowleveltype c_resulttype = inputconst(ootype.Void, RESULT) c_length = inputconst(ootype.Signed, len(self.items_r)) hop.exception_is_here() if isinstance(RESULT, ootype.Array): v_list = hop.genop('oonewarray', [c_resulttype, c_length], resulttype=RESULT) else: assert isinstance(RESULT, ootype.List) v_list = hop.genop('new', [c_resulttype], resulttype=RESULT) c_resize = inputconst(ootype.Void, '_ll_resize') hop.genop('oosend', [c_resize, v_list, c_length], resulttype=ootype.Void) c_setitem = inputconst(ootype.Void, 'll_setitem_fast') for index in range(len(self.items_r)): name = self.fieldnames[index] r_item = self.items_r[index] c_name = hop.inputconst(ootype.Void, name) v_item = hop.genop("oogetfield", [v_tup, c_name], resulttype=r_item) v_item = hop.llops.convertvar(v_item, r_item, hop.r_result.item_repr) c_index = inputconst(ootype.Signed, index) hop.genop('oosend', [c_setitem, v_list, c_index, v_item], resulttype=ootype.Void) return v_list
def _generate_newlist(self, llops, items_v): c_list = inputconst(ootype.Void, self.lowleveltype) v_result = llops.genop("new", [c_list], resulttype=self.lowleveltype) c_resize = inputconst(ootype.Void, "_ll_resize") c_length = inputconst(ootype.Signed, len(items_v)) llops.genop("oosend", [c_resize, v_result, c_length], resulttype=ootype.Void) return v_result
def _gct_resize_buffer_no_realloc(self, hop, v_lgt): op = hop.spaceop meth = self.gct_fv_gc_malloc_varsize flags = {'flavor':'gc', 'varsize': True, 'keep_current_args': True} self.varsize_malloc_helper(hop, flags, meth, []) # fish resvar v_newbuf = hop.llops[-1].result v_src = op.args[0] TYPE = v_src.concretetype.TO c_fldname = rmodel.inputconst(lltype.Void, TYPE._arrayfld) v_adrsrc = hop.genop('cast_ptr_to_adr', [v_src], resulttype=llmemory.Address) v_adrnewbuf = hop.genop('cast_ptr_to_adr', [v_newbuf], resulttype=llmemory.Address) ofs = (llmemory.offsetof(TYPE, TYPE._arrayfld) + llmemory.itemoffsetof(getattr(TYPE, TYPE._arrayfld), 0)) v_ofs = rmodel.inputconst(lltype.Signed, ofs) v_adrsrc = hop.genop('adr_add', [v_adrsrc, v_ofs], resulttype=llmemory.Address) v_adrnewbuf = hop.genop('adr_add', [v_adrnewbuf, v_ofs], resulttype=llmemory.Address) size = llmemory.sizeof(getattr(TYPE, TYPE._arrayfld).OF) c_size = rmodel.inputconst(lltype.Signed, size) v_lgtsym = hop.genop('int_mul', [c_size, v_lgt], resulttype=lltype.Signed) vlist = [v_adrsrc, v_adrnewbuf, v_lgtsym] hop.genop('raw_memcopy', vlist)
def rtype_is_true(self, hop): if not self.s_pbc.can_be_None: return inputconst(Bool, True) else: v1, = hop.inputargs(self) return hop.genop('char_ne', [v1, inputconst(Char, '\000')], resulttype=Bool)
def _gct_resize_buffer_no_realloc(self, hop, v_lgt): op = hop.spaceop meth = self.gct_fv_gc_malloc_varsize flags = {'flavor': 'gc', 'varsize': True, 'keep_current_args': True} self.varsize_malloc_helper(hop, flags, meth, []) # fish resvar v_newbuf = hop.llops[-1].result v_src = op.args[0] TYPE = v_src.concretetype.TO c_fldname = rmodel.inputconst(lltype.Void, TYPE._arrayfld) v_adrsrc = hop.genop('cast_ptr_to_adr', [v_src], resulttype=llmemory.Address) v_adrnewbuf = hop.genop('cast_ptr_to_adr', [v_newbuf], resulttype=llmemory.Address) ofs = (llmemory.offsetof(TYPE, TYPE._arrayfld) + llmemory.itemoffsetof(getattr(TYPE, TYPE._arrayfld), 0)) v_ofs = rmodel.inputconst(lltype.Signed, ofs) v_adrsrc = hop.genop('adr_add', [v_adrsrc, v_ofs], resulttype=llmemory.Address) v_adrnewbuf = hop.genop('adr_add', [v_adrnewbuf, v_ofs], resulttype=llmemory.Address) size = llmemory.sizeof(getattr(TYPE, TYPE._arrayfld).OF) c_size = rmodel.inputconst(lltype.Signed, size) v_lgtsym = hop.genop('int_mul', [c_size, v_lgt], resulttype=lltype.Signed) vlist = [v_adrsrc, v_adrnewbuf, v_lgtsym] hop.genop('raw_memcopy', vlist)
def gendirectcall(self, ll_function, *args_v): rtyper = self.rtyper args_s = [] newargs_v = [] for v in args_v: if v.concretetype is Void: s_value = rtyper.binding(v, default=annmodel.s_None) if not s_value.is_constant(): raise TyperError("non-constant variable of type Void") if not isinstance(s_value, annmodel.SomePBC): raise TyperError("non-PBC Void argument: %r", (s_value,)) args_s.append(s_value) else: args_s.append(annmodel.lltype_to_annotation(v.concretetype)) newargs_v.append(v) self.rtyper.call_all_setups() # compute ForwardReferences now # hack for bound methods if hasattr(ll_function, 'im_func'): bk = rtyper.annotator.bookkeeper args_s.insert(0, bk.immutablevalue(ll_function.im_self)) newargs_v.insert(0, inputconst(Void, ll_function.im_self)) ll_function = ll_function.im_func graph = annotate_lowlevel_helper(rtyper.annotator, ll_function, args_s, rtyper.lowlevel_ann_policy) self.record_extra_call(graph) # build the 'direct_call' operation f = self.rtyper.getcallable(graph) c = inputconst(typeOf(f), f) fobj = self.rtyper.type_system_deref(f) return self.genop('direct_call', [c]+newargs_v, resulttype = typeOf(fobj).RESULT)
def new_instance(self, llops, classcallhop=None): """Build a new instance, without calling __init__.""" flavor = self.gcflavor flags = {'flavor': flavor } ctype = inputconst(Void, self.object_type) cflags = inputconst(Void, flags) vlist = [ctype, cflags] vptr = llops.genop('malloc', vlist, resulttype = Ptr(self.object_type)) ctypeptr = inputconst(CLASSTYPE, self.rclass.getvtable()) self.setfield(vptr, '__class__', ctypeptr, llops) # initialize instance attributes from their defaults from the class if self.classdef is not None: flds = self.allinstancefields.keys() flds.sort() for fldname in flds: if fldname == '__class__': continue mangled_name, r = self.allinstancefields[fldname] if r.lowleveltype is Void: continue if fldname == '_hash_cache_': value = Constant(0, Signed) else: value = self.classdef.classdesc.read_attribute(fldname, None) if value is not None: cvalue = inputconst(r.lowleveltype, r.convert_desc_or_const(value)) self.setfield(vptr, fldname, cvalue, llops, {'access_directly': True}) return vptr
def gendirectcall(self, ll_function, *args_v): rtyper = self.rtyper args_s = [] newargs_v = [] for v in args_v: if v.concretetype is Void: s_value = rtyper.binding(v, default=annmodel.s_None) if not s_value.is_constant(): raise TyperError("non-constant variable of type Void") if not isinstance(s_value, annmodel.SomePBC): raise TyperError("non-PBC Void argument: %r", (s_value, )) args_s.append(s_value) else: args_s.append(annmodel.lltype_to_annotation(v.concretetype)) newargs_v.append(v) self.rtyper.call_all_setups() # compute ForwardReferences now # hack for bound methods if hasattr(ll_function, 'im_func'): bk = rtyper.annotator.bookkeeper args_s.insert(0, bk.immutablevalue(ll_function.im_self)) newargs_v.insert(0, inputconst(Void, ll_function.im_self)) ll_function = ll_function.im_func graph = annotate_lowlevel_helper(rtyper.annotator, ll_function, args_s, rtyper.lowlevel_ann_policy) self.record_extra_call(graph) # build the 'direct_call' operation f = self.rtyper.getcallable(graph) c = inputconst(typeOf(f), f) fobj = self.rtyper.type_system_deref(f) return self.genop('direct_call', [c] + newargs_v, resulttype=typeOf(fobj).RESULT)
def newlist(llops, r_list, items_v): v_result = r_list._generate_newlist(llops, items_v) c_setitem = inputconst(ootype.Void, "ll_setitem_fast") for i, v_item in enumerate(items_v): ci = inputconst(Signed, i) llops.genop("oosend", [c_setitem, v_result, ci, v_item], resulttype=ootype.Void) return v_result
def newlist(llops, r_list, items_v, v_sizehint=None): v_result = r_list._generate_newlist(llops, items_v, v_sizehint) c_setitem = inputconst(ootype.Void, "ll_setitem_fast") for i, v_item in enumerate(items_v): ci = inputconst(Signed, i) llops.genop("oosend", [c_setitem, v_result, ci, v_item], resulttype=ootype.Void) return v_result
def set_vable(self, llops, vinst, force_cast=False): if self.top_of_virtualizable_hierarchy: if force_cast: vinst = llops.genop('cast_pointer', [vinst], resulttype=self) cname = inputconst(lltype.Void, 'vable_token') cvalue = inputconst(lltype.Signed, 0) llops.genop('setfield', [vinst, cname, cvalue]) else: self.rbase.set_vable(llops, vinst, force_cast=True)
def set_vable(self, llops, vinst, force_cast=False): if self.top_of_virtualizable_hierarchy: if force_cast: vinst = llops.genop('cast_pointer', [vinst], resulttype=self) cname = inputconst(lltype.Void, 'vable_rti') vvalue = inputconst(VABLERTIPTR, lltype.nullptr(VABLERTIPTR.TO)) llops.genop('setfield', [vinst, cname, vvalue]) else: self.rbase.set_vable(llops, vinst, force_cast=True)
def get_c_data(self, llops, v_box): if self.ownsmemory: inputargs = [v_box, inputconst(lltype.Void, "c_data")] return llops.genop('getsubstruct', inputargs, lltype.Ptr(self.c_data_type) ) else: inputargs = [v_box, inputconst(lltype.Void, "c_data")] return llops.genop('getfield', inputargs, lltype.Ptr(self.c_data_type) )
def new_instance(self, llops, classcallhop=None): """Build a new instance, without calling __init__.""" classrepr = getclassrepr(self.rtyper, self.classdef) v_instance = llops.genop("new", [inputconst(ootype.Void, self.lowleveltype)], self.lowleveltype) cmeta = inputconst(ootype.Void, "meta") cmeta_instance = inputconst(CLASSTYPE, classrepr.get_meta_instance()) llops.genop("oosetfield", [v_instance, cmeta, cmeta_instance], resulttype=ootype.Void) return v_instance
def newtuple(cls, llops, r_tuple, items_v): # items_v should have the lowleveltype of the internal reprs if len(r_tuple.items_r) == 0: return inputconst(r_tuple, ()) # always the same empty tuple c1 = inputconst(ootype.Void, r_tuple.lowleveltype) v_result = llops.genop("new", [c1], resulttype=r_tuple.lowleveltype) for i in range(len(r_tuple.items_r)): cname = inputconst(ootype.Void, r_tuple.fieldnames[i]) llops.genop("oosetfield", [v_result, cname, items_v[i]]) return v_result
class __extend__(pairtype(AbstractClassesPBCRepr, AbstractClassesPBCRepr)): def convert_from_to((r_clspbc1, r_clspbc2), v, llops): # this check makes sense because both source and dest repr are ClassesPBCRepr if r_clspbc1.lowleveltype == r_clspbc2.lowleveltype: return v if r_clspbc1.lowleveltype is Void: return inputconst(r_clspbc2, r_clspbc1.s_pbc.const) if r_clspbc2.lowleveltype is Void: return inputconst(Void, r_clspbc2.s_pbc.const) return NotImplemented
def convert_scalar_to_array(r_item, v_item, llops): # x -> array([x]) s_item = lltype_to_annotation(r_item.lowleveltype) s_array = aarray.build_annotation_from_scalar(s_item) r_array = llops.rtyper.getrepr(s_array) from pypy.rpython.rmodel import inputconst cARRAY = inputconst(Void, r_array.ARRAY.TO) cITEM = inputconst(Void, r_array.ITEM) v_casted = llops.genop("cast_primitive", [v_item], r_array.ITEM) v_array = llops.gendirectcall(ll_build_from_scalar, cARRAY, v_casted) return r_array, v_array
def push_roots(self, hop): if self.push_root_ptr is None: return livevars = [var for var in self.livevars if not var_ispyobj(var)] c_len = rmodel.inputconst(lltype.Signed, len(livevars) ) base_addr = hop.genop("direct_call", [self.incr_stack_ptr, c_len ], resulttype=llmemory.Address) for k,var in enumerate(livevars): c_k = rmodel.inputconst(lltype.Signed, k) v_adr = gen_cast(hop.llops, llmemory.Address, var) hop.genop("direct_call", [self.save_addr_ptr, base_addr, c_k, v_adr])
class __extend__(pairtype(PyObjRepr, AbstractStringRepr)): def convert_from_to((r_from, r_to), v, llops): v_len = llops.gencapicall('PyString_Size', [v], resulttype=Signed) cstr = inputconst(Void, STR) cflags = inputconst(Void, {'flavor': 'gc'}) v_result = llops.genop('malloc_varsize', [cstr, cflags, v_len], resulttype=Ptr(STR)) llops.gencapicall('PyString_ToRPyString', [v, v_result]) string_repr = llops.rtyper.type_system.rstr.string_repr v_result = llops.convertvar(v_result, string_repr, r_to) return v_result
def newlist(llops, r_list, items_v): c_list = inputconst(ootype.Void, r_list.lowleveltype) v_result = llops.genop("new", [c_list], resulttype=r_list.lowleveltype) c_resize = inputconst(ootype.Void, "_ll_resize") c_length = inputconst(ootype.Signed, len(items_v)) llops.genop("oosend", [c_resize, v_result, c_length], resulttype=ootype.Void) c_setitem = inputconst(ootype.Void, "ll_setitem_fast") for i, v_item in enumerate(items_v): ci = inputconst(Signed, i) llops.genop("oosend", [c_setitem, v_result, ci, v_item], resulttype=ootype.Void) return v_result
def set_vable(self, llops, vinst, force_cast=False): if self.top_of_virtualizable_hierarchy: if force_cast: vinst = llops.genop('cast_pointer', [vinst], resulttype=self) for name, llvalue in (('access', lltype.nullptr(self.ACCESS)), ('base', llmemory.NULL), ('rti', lltype.nullptr(VABLERTIPTR.TO))): cname = inputconst(lltype.Void, 'vable_'+name) vvalue = inputconst(lltype.typeOf(llvalue), llvalue) llops.genop('setfield', [vinst, cname, vvalue]) else: self.rbase.set_vable(llops, vinst, force_cast=True)
def set_vable(self, llops, vinst, force_cast=False): if self.top_of_virtualizable_hierarchy: if force_cast: vinst = llops.genop('cast_pointer', [vinst], resulttype=self) for name, llvalue in (('access', lltype.nullptr(self.ACCESS)), ('base', llmemory.NULL), ('rti', lltype.nullptr(VABLERTIPTR.TO))): cname = inputconst(lltype.Void, 'vable_' + name) vvalue = inputconst(lltype.typeOf(llvalue), llvalue) llops.genop('setfield', [vinst, cname, vvalue]) else: self.rbase.set_vable(llops, vinst, force_cast=True)
def handle_after_residual_call_details(self, block, pos, newops, blockset, withexc, oop = False): dopts = {'withexc': withexc, 'oop': oop } copts = Constant(dopts, lltype.Void) v_flags = self.genop(newops, 'after_residual_call', [copts], resulttype=lltype.Signed, red=True) residual_fetch_index = len(newops) self.genop(newops, 'residual_fetch', [v_flags, copts]) residual_fetch_pos = pos+residual_fetch_index block.operations[pos:pos+1] = newops link_t = split_block(self.hannotator, block, residual_fetch_pos) nextblock = link_t.target blockset[nextblock] = False i_flags = link_t.args.index(v_flags) reds, greens = self.sort_by_color(link_t.args) self.genop(block, 'save_locals', reds) SPLIT_FOR_ZERO = False if SPLIT_FOR_ZERO: promoteblock = Block([copyvar(self.hannotator, v) for v in link_t.args]) link_f = Link(link_t.args, promoteblock) promoteblock.recloseblock(Link(promoteblock.inputargs, nextblock)) blockset[promoteblock] = False v_flags2 = promoteblock.inputargs[i_flags] else: promoteblock = block v_flags2 = v_flags # if there is no global merge point, this 'promote' will actually # always see a constant red box v_finished_flag = self.genop(promoteblock, 'promote', [v_flags2], resulttype = lltype.Bool) self.go_to_dispatcher_if(promoteblock, v_finished_flag) if SPLIT_FOR_ZERO: c_zero = inputconst(lltype.Signed, 0) link_t.args = link_t.args[:] link_t.args[i_flags] = c_zero resumepoint = self.get_resume_point(promoteblock) c_resumepoint = inputconst(lltype.Signed, resumepoint) v_is_zero = self.genop(block, 'int_eq', [v_flags, c_zero], resulttype=lltype.Bool, red=True) v_is_zero = self.genop(block, 'split', [v_is_zero, c_resumepoint] + greens, resulttype = lltype.Bool) block.exitswitch = v_is_zero link_t.exitcase = True link_f.exitcase = False block.recloseblock(link_f, link_t)
def newtuple(cls, llops, r_tuple, items_v): # items_v should have the lowleveltype of the internal reprs if len(r_tuple.items_r) == 0: return inputconst(Void, ()) # a Void empty tuple c1 = inputconst(Void, r_tuple.lowleveltype.TO) cflags = inputconst(Void, {'flavor': 'gc'}) v_result = llops.genop('malloc', [c1, cflags], resulttype = r_tuple.lowleveltype) for i in range(len(r_tuple.items_r)): cname = inputconst(Void, r_tuple.fieldnames[i]) llops.genop('setfield', [v_result, cname, items_v[i]]) return v_result
def newtuple(cls, llops, r_tuple, items_v): # items_v should have the lowleveltype of the internal reprs if len(r_tuple.items_r) == 0: return inputconst(Void, ()) # a Void empty tuple c1 = inputconst(Void, r_tuple.lowleveltype.TO) cflags = inputconst(Void, {'flavor': 'gc'}) v_result = llops.genop('malloc', [c1, cflags], resulttype=r_tuple.lowleveltype) for i in range(len(r_tuple.items_r)): cname = inputconst(Void, r_tuple.fieldnames[i]) llops.genop('setfield', [v_result, cname, items_v[i]]) return v_result
def newlist(llops, r_list, items_v): LIST = r_list.LIST if len(items_v) == 0: v_result = llops.gendirectcall(LIST.ll_newemptylist) else: cno = inputconst(Signed, len(items_v)) v_result = llops.gendirectcall(LIST.ll_newlist, cno) v_func = inputconst(Void, dum_nocheck) for i, v_item in enumerate(items_v): ci = inputconst(Signed, i) llops.gendirectcall(ll_setitem_nonneg, v_func, v_result, ci, v_item) return v_result
def gen_zero_gc_pointers(TYPE, v, llops): assert isinstance(TYPE, lltype.Struct) for name in TYPE._names: FIELD = getattr(TYPE, name) if isinstance(FIELD, lltype.Ptr) and FIELD._needsgc(): c_name = rmodel.inputconst(lltype.Void, name) c_null = rmodel.inputconst(FIELD, lltype.nullptr(FIELD.TO)) llops.genop('bare_setfield', [v, c_name, c_null]) elif isinstance(FIELD, lltype.Struct): c_name = rmodel.inputconst(lltype.Void, name) v1 = llops.genop('getsubstruct', [v, c_name], resulttype = lltype.Ptr(FIELD)) gen_zero_gc_pointers(FIELD, v1, llops)
def newlist(llops, r_list, items_v, v_sizehint=None): # XXX do something about v_sizehint c_list = inputconst(ootype.Void, r_list.lowleveltype) v_result = llops.genop("new", [c_list], resulttype=r_list.lowleveltype) c_resize = inputconst(ootype.Void, "_ll_resize") c_length = inputconst(ootype.Signed, len(items_v)) llops.genop("oosend", [c_resize, v_result, c_length], resulttype=ootype.Void) c_setitem = inputconst(ootype.Void, "ll_setitem_fast") for i, v_item in enumerate(items_v): ci = inputconst(Signed, i) llops.genop("oosend", [c_setitem, v_result, ci, v_item], resulttype=ootype.Void) return v_result
def insert_merge(self, block, kind): allvars = block.inputargs[:] block.inputargs[:] = [copyvar(self.hannotator, v) for v in allvars] reds1, greens1 = self.sort_by_color(block.inputargs) reds3, greens3 = self.sort_by_color(allvars) nextblock = self.naive_split_block(block, 0) self.genop(block, 'save_locals', reds1) mp = self.mergepointfamily.add(kind) c_mp = inputconst(lltype.Void, mp) if kind == 'global': prefix = 'global_' greens2 = [copyvar(self.hannotator, v) for v in greens1] mergeblock = self.naive_split_block(block, len(block.operations)) mergeblock.inputargs[:] = greens2 self.genop(block, 'save_greens', greens1) block.recloseblock(Link([self.c_dummy], self.graph.returnblock)) N = self.get_resume_point(mergeblock) c_resumeindex = inputconst(lltype.Signed, N) self.genop(block, 'guard_global_merge', [c_resumeindex]) # Note: the jitstate.greens list will contain the correct # green gv's for the following global_merge_point, because # the green values have just been restored by the resume # point logic here else: mergeblock = block greens2 = greens1 prefix = '' mergeblock.exits[0].args[:] = greens2 nextblock.inputargs[:] = greens3 v_finished_flag = self.genop(mergeblock, '%smerge_point' % (prefix,), [self.c_mpfamily, c_mp] + greens2, resulttype = lltype.Bool) self.go_to_dispatcher_if(mergeblock, v_finished_flag) restoreops = [] for i, v in enumerate(reds3): c = inputconst(lltype.Signed, i) restoreops.append(SpaceOperation('restore_local', [c], v)) nextblock.operations[:0] = restoreops if kind == 'global': N = self.get_resume_point(nextblock) self.mergepointfamily.resumepoint_after_mergepoint[mp] = N
def build_from_shape(self, hop, r_arg, v_arg, zero=False): cARRAY = inputconst(lltype.Void, self.lowleveltype.TO) ndim = self.s_array.ndim if isinstance(r_arg, TupleRepr): r_tuple, v_tuple = r_arg, v_arg ll_build_from_shape = gen_build_from_shape(ndim, zero) c_ndim = inputconst(lltype.Signed, ndim) assert ndim == len(r_tuple.items_r) return hop.llops.gendirectcall(ll_build_from_shape, cARRAY, v_tuple) else: assert ndim == 1 v_size = hop.inputarg(Signed, 0) _malloc = lambda tp, size: malloc(tp, size, zero=zero) cmalloc = inputconst(Void, _malloc) return hop.llops.gendirectcall(ll_build_from_size, cARRAY, v_size, cmalloc)
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_meta = self.fromclasstype(vcls, llops) cname = inputconst(ootype.Void, mangled_name) return llops.genop('oogetfield', [v_meta, cname], resulttype=r)
def setfield(self, vinst, attr, vvalue, llops): # this method emulates behaviour from the corresponding # lltypesystem one. It is referenced in some obscure corners # like rtyping of OSError. mangled_name = mangle(attr, self.rtyper.getconfig()) cname = inputconst(ootype.Void, mangled_name) llops.genop('oosetfield', [vinst, cname, vvalue])
def rtype_getattr(self, hop): v_inst, _ = hop.inputargs(self, ootype.Void) s_inst = hop.args_s[0] attr = hop.args_s[1].const mangled = mangle(attr, self.rtyper.getconfig()) v_attr = hop.inputconst(ootype.Void, mangled) if mangled in self.allfields: # regular instance attributes self.lowleveltype._check_field(mangled) return hop.genop("oogetfield", [v_inst, v_attr], resulttype = hop.r_result.lowleveltype) elif mangled in self.allmethods: # special case for methods: represented as their 'self' only # (see MethodsPBCRepr) return hop.r_result.get_method_from_instance(self, v_inst, hop.llops) elif mangled in self.allclassattributes: # class attributes if hop.s_result.is_constant(): return hop.inputconst(hop.r_result, hop.s_result.const) else: cname = hop.inputconst(ootype.Void, mangled) return hop.genop("oosend", [cname, v_inst], resulttype = hop.r_result.lowleveltype) elif attr == '__class__': if hop.r_result.lowleveltype is ootype.Void: # special case for when the result of '.__class__' is constant [desc] = hop.s_result.descriptions return hop.inputconst(ootype.Void, desc.pyobj) else: cmeta = inputconst(ootype.Void, "meta") return hop.genop('oogetfield', [v_inst, cmeta], resulttype=CLASSTYPE) else: raise TyperError("no attribute %r on %r" % (attr, self))
def getfield(self, v_inst, attr, llops, flags={}): mangled = mangle(attr, self.rtyper.getconfig()) v_attr = inputconst(ootype.Void, mangled) r_value = self.allfields[mangled] self.lowleveltype._check_field(mangled) self.hook_access_field(v_inst, v_attr, llops, flags) return llops.genop('oogetfield', [v_inst, v_attr], resulttype=r_value)
def new_instance(self, llops, classcallhop=None): """Build a new instance, without calling __init__.""" classrepr = getclassrepr(self.rtyper, self.classdef) v_instance = llops.genop("new", [inputconst(ootype.Void, self.lowleveltype)], self.lowleveltype) return v_instance
def decompose_slice_args(self): # Select which kind of slicing is needed. We support: # * [start:] # * [start:stop] # * [:-1] s_start = self.args_s[1] s_stop = self.args_s[2] if (s_start.is_constant() and s_start.const in (None, 0) and s_stop.is_constant() and s_stop.const == -1): return "minusone", [] if isinstance(s_start, annmodel.SomeInteger): if not s_start.nonneg: raise TyperError("slice start must be proved non-negative") if isinstance(s_stop, annmodel.SomeInteger): if not s_stop.nonneg: raise TyperError("slice stop must be proved non-negative") if s_start.is_constant() and s_start.const is None: v_start = inputconst(Signed, 0) else: v_start = self.inputarg(Signed, arg=1) if s_stop.is_constant() and s_stop.const is None: return "startonly", [v_start] else: v_stop = self.inputarg(Signed, arg=2) return "startstop", [v_start, v_stop]
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 gct_gc_deallocate(self, hop): TYPE = hop.spaceop.args[0].value v_addr = hop.spaceop.args[1] dealloc_fptr = self.dynamic_deallocation_funcptr_for_type(TYPE) cdealloc_fptr = rmodel.inputconst( lltype.typeOf(dealloc_fptr), dealloc_fptr) hop.genop("direct_call", [cdealloc_fptr, v_addr])
class __extend__(pairtype(TupleRepr, PyObjRepr)): def convert_from_to((r_from, r_to), v, llops): ci = inputconst(Signed, len(r_from.items_r)) v_result = llops.gencapicall('PyTuple_New', [ci], resulttype=pyobj_repr) for i in range(len(r_from.items_r)): cname = inputconst(Void, r_from.fieldnames[i]) v_item = llops.genop( 'getfield', [v, cname], resulttype=r_from.external_items_r[i].lowleveltype) v_converted = llops.convertvar(v_item, r_from.external_items_r[i], pyobj_repr) ci = inputconst(Signed, i) llops.gencapicall('PyTuple_SetItem_WithIncref', [v_result, ci, v_converted]) return v_result