def inputconst(reqtype, value): """Return a Constant with the given value, of the requested type, which can be a Repr instance or a low-level type. """ if isinstance(reqtype, Repr): value = reqtype.convert_const(value) lltype = reqtype.lowleveltype elif isinstance(reqtype, LowLevelType): lltype = reqtype else: raise TypeError(repr(reqtype)) # Void Constants can hold any value; # non-Void Constants must hold a correctly ll-typed value if lltype is not Void: try: realtype = typeOf(value) except (AssertionError, AttributeError): realtype = '???' if not isCompatibleType(realtype, lltype): raise TyperError("inputconst(reqtype = %s, value = %s):\n" "expected a %r,\n" " got a %r" % (reqtype, value, lltype, realtype)) c = Constant(value) c.concretetype = lltype return c
def test_func_simple(): # -------------------- flowgraph building -------------------- # def f(x): # return x+1 x = Variable("x") x.concretetype = Signed result = Variable("result") result.concretetype = Signed one = Constant(1) one.concretetype = Signed op = SpaceOperation("int_add", [x, one], result) block = Block([x]) graph = FunctionGraph("f", block) block.operations.append(op) block.closeblock(Link([result], graph.returnblock)) graph.getreturnvar().concretetype = Signed # -------------------- end -------------------- F = FuncType([Signed], Signed) f = functionptr(F, "f", graph=graph) db = LowLevelDatabase() db.get(f) db.complete() dump_on_stdout(db) S = GcStruct('testing', ('fptr', Ptr(F))) s = malloc(S) s.fptr = f db = LowLevelDatabase() db.get(s) db.complete() dump_on_stdout(db)
def flatten(self, S): start = 0 if S._names and self.equivalent_substruct(S, S._names[0]): SUBTYPE = S._flds[S._names[0]] if isinstance(SUBTYPE, lltype.Struct): self.flatten(SUBTYPE) start = 1 else: ARRAY = lltype.FixedSizeArray(SUBTYPE, 1) self.direct_fieldptr_key[ARRAY, 'item0'] = S, S._names[0] for name in S._names[start:]: key = S, name FIELDTYPE = S._flds[name] if key in self.accessed_substructs: self.needsubmallocs.append(key) self.flatnames.append(key) self.newvarstype[key] = lltype.Ptr(lltype.GcStruct('wrapper', ('data', FIELDTYPE))) elif not isinstance(FIELDTYPE, lltype.ContainerType): example = FIELDTYPE._defl() constant = Constant(example) constant.concretetype = FIELDTYPE self.flatconstants[key] = constant self.flatnames.append(key) self.newvarstype[key] = FIELDTYPE
def make_const_rt_result(self, v_result, value): newrtnode = RuntimeSpecNode(v_result, v_result.concretetype) self.setnode(v_result, newrtnode) if v_result.concretetype is not lltype.Void: assert v_result.concretetype == lltype.typeOf(value) c_value = Constant(value) c_value.concretetype = v_result.concretetype self.renamings[newrtnode] = c_value
def replace_we_are_jitted(graph): from rpython.rlib import jit replacement = Constant(0) replacement.concretetype = lltype.Signed did_replacement = replace_symbolic(graph, jit._we_are_jitted, replacement) if did_replacement: constant_fold_graph(graph) return did_replacement
def inputdesc(reqtype, desc): """Return a Constant for the given desc, of the requested type, which can only be a Repr. """ assert isinstance(reqtype, Repr) value = reqtype.convert_desc(desc) lltype = reqtype.lowleveltype c = Constant(value) c.concretetype = lltype return c
def handle_op_malloc(self, op): if op.result is self.v_expand_malloc: MALLOCTYPE = op.result.concretetype.TO typedesc = self.graphbuilder.mallocv.getmalloctypedesc(MALLOCTYPE) virtualnode = VirtualSpecNode(typedesc, []) self.setnode(op.result, virtualnode) for name, FIELDTYPE in typedesc.names_and_types: fieldnode = RuntimeSpecNode(name, FIELDTYPE) virtualnode.fields.append(fieldnode) c = Constant(FIELDTYPE._defl()) c.concretetype = FIELDTYPE self.renamings[fieldnode] = c self.v_expand_malloc = None # done return [] else: return self.handle_default(op)
def inputconst(reqtype, value): """Return a Constant with the given value, of the requested type, which can be a Repr instance or a low-level type. """ if isinstance(reqtype, Repr): value = reqtype.convert_const(value) lltype = reqtype.lowleveltype elif isinstance(reqtype, LowLevelType): lltype = reqtype else: raise TypeError(repr(reqtype)) if not lltype._contains_value(value): raise TyperError("inputconst(): expected a %r, got %r" % (lltype, value)) c = Constant(value) c.concretetype = lltype return c
def get_exc_reconstruction_block(self, typedesc): exceptblock = self.graph.exceptblock self.mallocv.fixup_except_block(exceptblock) TEXC = exceptblock.inputargs[0].concretetype TVAL = exceptblock.inputargs[1].concretetype # v_ignored_type = varoftype(TEXC) v_incoming_value = varoftype(TVAL) block = Block([v_ignored_type, v_incoming_value]) # c_EXCTYPE = Constant(typedesc.MALLOCTYPE, lltype.Void) v = varoftype(lltype.Ptr(typedesc.MALLOCTYPE)) c_flavor = Constant({'flavor': 'gc'}, lltype.Void) op = SpaceOperation('malloc', [c_EXCTYPE, c_flavor], v) block.operations.append(op) # for name, FIELDTYPE in typedesc.names_and_types: EXACTPTR = lltype.Ptr(typedesc.name2subtype[name]) c_name = Constant(name) c_name.concretetype = lltype.Void # v_in = varoftype(EXACTPTR) op = SpaceOperation('cast_pointer', [v_incoming_value], v_in) block.operations.append(op) # v_field = varoftype(FIELDTYPE) op = SpaceOperation('getfield', [v_in, c_name], v_field) block.operations.append(op) # v_out = varoftype(EXACTPTR) op = SpaceOperation('cast_pointer', [v], v_out) block.operations.append(op) # v0 = varoftype(lltype.Void) op = SpaceOperation('setfield', [v_out, c_name, v_field], v0) block.operations.append(op) # v_exc_value = varoftype(TVAL) op = SpaceOperation('cast_pointer', [v], v_exc_value) block.operations.append(op) # exc_type = self.mallocv.EXCTYPE_to_vtable[typedesc.MALLOCTYPE] c_exc_type = Constant(exc_type, TEXC) block.closeblock(Link([c_exc_type, v_exc_value], exceptblock)) return block
def generic_exception_matching(self, afterblock, copiedexceptblock): #XXXXX don't look: insert blocks that do exception matching #for the cases where direct matching did not work exc_match = Constant( self.translator.rtyper.exceptiondata.fn_exception_match) exc_match.concretetype = typeOf(exc_match.value) blocks = [] for i, link in enumerate(afterblock.exits[1:]): etype = copyvar(None, copiedexceptblock.inputargs[0]) evalue = copyvar(None, copiedexceptblock.inputargs[1]) passon_vars = self.passon_vars(i) block = Block([etype, evalue] + passon_vars) res = Variable() res.concretetype = Bool cexitcase = Constant(link.llexitcase) cexitcase.concretetype = typeOf(cexitcase.value) args = [exc_match, etype, cexitcase] block.operations.append(SpaceOperation("direct_call", args, res)) block.exitswitch = res linkargs = self.find_args_in_exceptional_case(link, link.target, etype, evalue, afterblock, passon_vars) l = Link(linkargs, link.target) l.prevblock = block l.exitcase = True l.llexitcase = True block.closeblock(l) if i > 0: l = Link(blocks[-1].inputargs, block) l.exitcase = False l.llexitcase = False blocks[-1].recloseblock(l, *blocks[-1].exits) blocks.append(block) blocks[-1].recloseblock(*blocks[-1].exits[:1]) blocks[-1].operations = [] blocks[-1].exitswitch = None blocks[-1].exits[0].exitcase = None del blocks[-1].exits[0].llexitcase linkargs = copiedexceptblock.inputargs copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
def make_closure(jd, fullfuncname, is_string): if jd is None: def closure(i): if is_string: i = hlstr(i) for jd in self.jitdrivers_sd: getattr(jd.warmstate, fullfuncname)(i) else: state = jd.warmstate def closure(i): if is_string: i = hlstr(i) getattr(state, fullfuncname)(i) if is_string: TP = PTR_SET_PARAM_STR_FUNCTYPE else: TP = PTR_SET_PARAM_FUNCTYPE funcptr = self.helper_func(TP, closure) return Constant(funcptr, TP)
def transform_ovfcheck(graph): """The special function calls ovfcheck needs to be translated into primitive operations. ovfcheck is called directly after an operation that should be turned into an overflow-checked version. It is considered a syntax error if the resulting <op>_ovf is not defined in objspace/flow/objspace.py. """ covf = Constant(rarithmetic.ovfcheck) for block in graph.iterblocks(): for i in range(len(block.operations) - 1, -1, -1): op = block.operations[i] if op.opname != 'simple_call': continue if op.args[0] == covf: if i == 0: # hard case: ovfcheck() on an operation that occurs # in the previous block, like 'floordiv'. The generic # exception handling around the ovfcheck() is enough # to cover all cases; kill the one around the previous op. entrymap = mkentrymap(graph) links = entrymap[block] assert len(links) == 1 prevblock = links[0].prevblock assert prevblock.exits[0].target is block prevblock.exitswitch = None prevblock.exits = (links[0], ) join_blocks(graph) # merge the two blocks together transform_ovfcheck(graph) # ...and try again return op1 = block.operations[i - 1] if not isinstance(op1, OverflowingOperation): raise Exception("ovfcheck in %s: Operation %s has no " "overflow variant" % (graph.name, op1.opname)) op1_ovf = op1.ovfchecked() block.operations[i - 1] = op1_ovf del block.operations[i] block.renamevariables({op.result: op1_ovf.result})
def gct_fv_gc_malloc(self, hop, flags, TYPE, c_size): # XXX same behavior for zero=True: in theory that's wrong if TYPE._is_atomic(): funcptr = self.malloc_fixedsize_atomic_ptr opname = 'boehm_malloc_atomic' else: funcptr = self.malloc_fixedsize_ptr opname = 'boehm_malloc' tr = self.translator if tr and tr.config.translation.reverse_debugger: # Don't check for NULLs after the operation (it crashes anyway # with an explicit error message in case of out-of-memory). # Avoiding a direct_call lets _RPY_REVDB_PRUID() prints the # right file/line, at least for fixed-size mallocs. v_raw = hop.genop(opname, [c_size], resulttype=llmemory.GCREF) else: v_raw = hop.genop("direct_call", [funcptr, c_size], resulttype=llmemory.GCREF) finalizer_ptr = self.finalizer_funcptr_for_type(TYPE) if finalizer_ptr: c_finalizer_ptr = Constant(finalizer_ptr, self.FINALIZER_PTR) hop.genop("boehm_register_finalizer", [v_raw, c_finalizer_ptr]) return v_raw
def test_regalloc_call(self): v1 = Variable() v1.concretetype = lltype.Signed v2 = Variable() v2.concretetype = lltype.Signed v3 = Variable() v3.concretetype = lltype.Signed v4 = Variable() v4.concretetype = lltype.Signed block = Block([v1]) block.operations = [ SpaceOperation('int_add', [v1, Constant(1, lltype.Signed)], v2), SpaceOperation('rescall', [ListOfKind('int', [v1, v2])], v3), ] graph = FunctionGraph('f', block, v4) block.closeblock(Link([v3], graph.returnblock)) # self.check_assembler( graph, """ int_add %i0, $1 -> %i1 rescall I[%i0, %i1] -> %i0 int_return %i0 """)
def rewrite_access_helper(self, op): # make sure we make a copy of function so it no longer belongs # to extregistry func = op.args[1].value if func.func_name.startswith('stats_'): # get special treatment since we rewrite it to a call that accepts # jit driver assert len(op.args) >= 3, ("%r must have a first argument " "(which is None)" % (func, )) func = func_with_new_name(func, func.func_name + '_compiled') def new_func(ignored, *args): return func(self, *args) ARGS = [lltype.Void] + [arg.concretetype for arg in op.args[3:]] else: ARGS = [arg.concretetype for arg in op.args[2:]] new_func = func_with_new_name(func, func.func_name + '_compiled') RESULT = op.result.concretetype FUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, RESULT)) ptr = self.helper_func(FUNCPTR, new_func) op.opname = 'direct_call' op.args = [Constant(ptr, FUNCPTR)] + op.args[2:]
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) 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) return l_dict
def no_more_blocks_to_annotate(pol, annotator): bk = annotator.bookkeeper # hint to all pending specializers that we are done for callback in bk.pending_specializations: callback() del bk.pending_specializations[:] if annotator.added_blocks is not None: all_blocks = annotator.added_blocks else: all_blocks = annotator.annotated for block in list(all_blocks): for i, instr in enumerate(block.operations): if not isinstance(instr, (op.simple_call, op.call_args)): continue v_func = instr.args[0] s_func = annotator.annotation(v_func) if not hasattr(s_func, 'needs_sandboxing'): continue key = ('sandboxing', s_func.const) if key not in bk.emulated_pbc_calls: params_s = s_func.args_s s_result = s_func.s_result from rpython.translator.sandbox.rsandbox import make_sandbox_trampoline sandbox_trampoline = make_sandbox_trampoline( s_func.name, params_s, s_result) sandbox_trampoline._signature_ = [ SomeTuple(items=params_s) ], s_result bk.emulate_pbc_call(key, bk.immutablevalue(sandbox_trampoline), params_s) else: s_trampoline = bk.emulated_pbc_calls[key][0] sandbox_trampoline = s_trampoline.const new = instr.replace( {instr.args[0]: Constant(sandbox_trampoline)}) block.operations[i] = new
def unformat_arg(s): if s.endswith(','): s = s[:-1].rstrip() if s[0] == '%': try: return registers[s] except KeyError: num = int(s[2:]) if s[1] == 'i': reg = Register('int', num) elif s[1] == 'r': reg = Register('ref', num) elif s[1] == 'f': reg = Register('float', num) else: raise AssertionError("bad register type") registers[s] = reg return reg elif s[0] == '$': intvalue = int(s[1:]) return Constant(intvalue, lltype.Signed) elif s[0] == 'L': return TLabel(s) elif s[0] in 'IRF' and s[1] == '[' and s[-1] == ']': items = split_words(s[2:-1]) items = map(unformat_arg, items) return ListOfKind({'I': 'int', 'R': 'ref', 'F': 'float'}[s[0]], items) elif s.startswith('<SwitchDictDescr '): assert s.endswith('>') switchdict = SwitchDictDescr() switchdict._labels = [] items = split_words(s[len('<SwitchDictDescr '):-1]) for item in items: key, value = item.split(':') value = value.rstrip(',') switchdict._labels.append((int(key), TLabel(value))) return switchdict else: raise AssertionError("unsupported argument: %r" % (s,))
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] cnonmovable = self.classdef.classdesc.read_attribute( '_alloc_nonmovable_', Constant(False)) if cnonmovable.value: opname = 'malloc_nonmovable' else: opname = 'malloc' vptr = llops.genop(opname, 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 collect_var_and_types(self): # # collect all variables and constants used in the body, # and get their types now # # NOTE: cannot use dictionaries with Constants as keys, because # Constants may hash and compare equal but have different lltypes self.all_cached_consts = None # will be filled after implementation_end mix = [self.graph.getreturnvar()] self.more_ll_values = [] for block in self.graph.iterblocks(): mix.extend(block.inputargs) for op in block.operations: mix.extend(op.args) mix.append(op.result) for link in block.exits: mix.extend(link.getextravars()) mix.extend(link.args) if hasattr(link, 'llexitcase'): self.more_ll_values.append(link.llexitcase) elif link.exitcase is not None: mix.append(Constant(link.exitcase)) if self.exception_policy == "CPython": v, exc_cleanup_ops = self.graph.exc_cleanup mix.append(v) for cleanupop in exc_cleanup_ops: mix.extend(cleanupop.args) mix.append(cleanupop.result) uniquemix = [] seen = identity_dict() for v in mix: if v not in seen: uniquemix.append(v) seen[v] = True self.vars = uniquemix
def generic_exception_matching(self, afterblock, copiedexceptblock): #XXXXX don't look: insert blocks that do exception matching #for the cases where direct matching did not work exc_match = Constant( self.translator.rtyper.exceptiondata.fn_exception_match) exc_match.concretetype = typeOf(exc_match.value) blocks = [] for i, link in enumerate(afterblock.exits[1:]): etype = copiedexceptblock.inputargs[0].copy() evalue = copiedexceptblock.inputargs[1].copy() passon_vars = self.passon_vars(i) block = Block([etype, evalue] + passon_vars) res = Variable() res.concretetype = Bool cexitcase = Constant(link.llexitcase) cexitcase.concretetype = typeOf(cexitcase.value) args = [exc_match, etype, cexitcase] block.operations.append(SpaceOperation("direct_call", args, res)) block.exitswitch = res linkargs = self.find_args_in_exceptional_case(link, link.target, etype, evalue, afterblock, passon_vars) l = Link(linkargs, link.target) l.prevblock = block l.exitcase = True l.llexitcase = True block.closeblock(l) if i > 0: l = Link(blocks[-1].inputargs, block) l.exitcase = False l.llexitcase = False blocks[-1].recloseblock(l, *blocks[-1].exits) blocks.append(block) blocks[-1].recloseblock(*blocks[-1].exits[:1]) blocks[-1].operations = [] blocks[-1].exitswitch = None blocks[-1].exits[0].exitcase = None del blocks[-1].exits[0].llexitcase linkargs = copiedexceptblock.inputargs copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
def test_guess_call_kind_and_calls_from_graphs(): class portal_runner_obj: graph = object() class FakeJitDriverSD: portal_runner_ptr = portal_runner_obj g = object() g1 = object() cc = CallControl(jitdrivers_sd=[FakeJitDriverSD()]) cc.candidate_graphs = [g, g1] op = SpaceOperation('direct_call', [Constant(portal_runner_obj)], Variable()) assert cc.guess_call_kind(op) == 'recursive' class fakeresidual: _obj = object() op = SpaceOperation('direct_call', [Constant(fakeresidual)], Variable()) assert cc.guess_call_kind(op) == 'residual' class funcptr: class _obj: class graph: class func: oopspec = "spec" op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) assert cc.guess_call_kind(op) == 'builtin' class funcptr: class _obj: graph = g op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) assert res == [g] assert cc.guess_call_kind(op) == 'regular' class funcptr: class _obj: graph = object() op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cc.graphs_from(op) assert res is None assert cc.guess_call_kind(op) == 'residual' h = object() op = SpaceOperation('indirect_call', [Variable(), Constant([g, g1, h])], Variable()) res = cc.graphs_from(op) assert res == [g, g1] assert cc.guess_call_kind(op) == 'regular' op = SpaceOperation('indirect_call', [Variable(), Constant([h])], Variable()) res = cc.graphs_from(op) assert res is None assert cc.guess_call_kind(op) == 'residual'
def constant_func(self, name, inputtypes, rettype, graph, **kwds): FUNC_TYPE = lltype.FuncType(inputtypes, rettype) fn_ptr = lltype.functionptr(FUNC_TYPE, name, graph=graph, **kwds) return Constant(fn_ptr, lltype.Ptr(FUNC_TYPE))
def constant_value(llvalue): return Constant(llvalue, lltype.typeOf(llvalue))
def sc_we_are_translated(ctx): return Constant(True)
def error_constant(T): return Constant(error_value(T), T)
def specialize_call(self, hop): hop.exception_cannot_occur() retval = Constant(hop.r_result.convert_const(hop.args_v[0].value)) retval.concretetype = hop.r_result.lowleveltype return retval
def normalize_calltable_row_signature(annotator, shape, row): graphs = row.values() assert graphs, "no graph??" sig0 = graphs[0].signature defaults0 = graphs[0].defaults for graph in graphs[1:]: if graph.signature != sig0: break if graph.defaults != defaults0: break else: return False # nothing to do, all signatures already match shape_cnt, shape_keys, shape_star = shape assert not shape_star, "should have been removed at this stage" # for the first 'shape_cnt' arguments we need to generalize to # a common type call_nbargs = shape_cnt + len(shape_keys) did_something = False for graph in graphs: argnames, varargname, kwargname = graph.signature assert not varargname, "XXX not implemented" assert not kwargname, "XXX not implemented" # ? inputargs_s = [annotator.binding(v) for v in graph.getargs()] argorder = range(shape_cnt) for key in shape_keys: i = list(argnames).index(key) assert i not in argorder argorder.append(i) need_reordering = (argorder != range(call_nbargs)) if need_reordering or len(graph.getargs()) != call_nbargs: oldblock = graph.startblock inlist = [] defaults = graph.defaults or () num_nondefaults = len(inputargs_s) - len(defaults) defaults = [description.NODEFAULT ] * num_nondefaults + list(defaults) newdefaults = [] for j in argorder: v = Variable(graph.getargs()[j]) annotator.setbinding(v, inputargs_s[j]) inlist.append(v) newdefaults.append(defaults[j]) newblock = Block(inlist) # prepare the output args of newblock: # 1. collect the positional arguments outlist = inlist[:shape_cnt] # 2. add defaults and keywords for j in range(shape_cnt, len(inputargs_s)): try: i = argorder.index(j) v = inlist[i] except ValueError: default = defaults[j] if default is description.NODEFAULT: raise TyperError( "call pattern has %d positional arguments, " "but %r takes at least %d arguments" % (shape_cnt, graph.name, num_nondefaults)) v = Constant(default) outlist.append(v) newblock.closeblock(Link(outlist, oldblock)) graph.startblock = newblock for i in range(len(newdefaults) - 1, -1, -1): if newdefaults[i] is description.NODEFAULT: newdefaults = newdefaults[i:] break graph.defaults = tuple(newdefaults) graph.signature = Signature([argnames[j] for j in argorder], None, None) # finished checkgraph(graph) annotator.annotated[newblock] = annotator.annotated[oldblock] did_something = True return did_something
def getname_w(self, index): return Constant(self.pycode.names[index])
class __extend__(pairtype(MultipleFrozenPBCRepr, FunctionRepr)): def convert_from_to((r_frozen1, r_fn2), v, llops): if r_fn2.lowleveltype is Void: value = r_fn2.s_pbc.const return Constant(value, Void) return NotImplemented
def adjust_shape(hop2, s_shape): new_shape = (s_shape.const[0] + 1, ) + s_shape.const[1:] c_shape = Constant(new_shape) s_shape = hop2.rtyper.annotator.bookkeeper.immutablevalue(new_shape) hop2.v_s_insertfirstarg(c_shape, s_shape) # reinsert adjusted shape
def inittime_helper(self, ll_helper, ll_args, ll_result, inline=True): ptr = self.annotate_helper(ll_helper, ll_args, ll_result, inline=inline) return Constant(ptr, lltype.typeOf(ptr))
def flowin_op(self, op, vars, newvarsmap): if op.opname in ("getfield", "getarrayitem"): S = op.args[0].concretetype.TO fldname = op.args[1].value key = self.key_for_field_access(S, fldname) if key not in newvarsmap: newop = self.handle_unreachable(op.result) elif key in self.accessed_substructs: c_name = Constant('data', lltype.Void) newop = SpaceOperation("getfield", [newvarsmap[key], c_name], op.result) else: newop = SpaceOperation("same_as", [newvarsmap[key]], op.result) self.newops.append(newop) elif op.opname in ("setfield", "setarrayitem"): S = op.args[0].concretetype.TO fldname = op.args[1].value key = self.key_for_field_access(S, fldname) if key not in newvarsmap: newop = self.handle_unreachable(op.result) self.newops.append(newop) elif key in self.accessed_substructs: c_name = Constant('data', lltype.Void) newop = SpaceOperation("setfield", [newvarsmap[key], c_name, op.args[2]], op.result) self.newops.append(newop) else: newvarsmap[key] = op.args[2] elif op.opname in ("same_as", "cast_pointer"): vars.add(op.result) # Consider the two pointers (input and result) as # equivalent. We can, and indeed must, use the same # flattened list of variables for both, as a "setfield" # via one pointer must be reflected in the other. elif op.opname in ("getsubstruct", "getarraysubstruct", "direct_fieldptr"): S = op.args[0].concretetype.TO fldname = op.args[1].value if op.opname == "getarraysubstruct": fldname = 'item%d' % fldname equiv = self.equivalent_substruct(S, fldname) if equiv: # exactly like a cast_pointer assert op.result not in vars vars.add(op.result) else: # do it with a getsubstruct on the independently # malloc'ed GcStruct if op.opname == "direct_fieldptr": opname = "direct_fieldptr" else: opname = "getsubstruct" try: v = newvarsmap[S, fldname] except KeyError: newop = self.handle_unreachable(op.result) else: cname = Constant('data', lltype.Void) newop = SpaceOperation(opname, [v, cname], op.result) self.newops.append(newop) elif op.opname in ("ptr_iszero", "ptr_nonzero"): # we know the pointer is not NULL if it comes from # a successful malloc c = Constant(op.opname == "ptr_nonzero", lltype.Bool) newop = SpaceOperation('same_as', [c], op.result) self.newops.append(newop) else: raise AssertionError(op.opname)
def recreate_malloc(self, c, v): return SpaceOperation(self.MALLOC_OP, [c, Constant({'flavor': 'gc'}, lltype.Void)], v)
def insert_exits(self, block): if len(block.exits) == 1: # A single link, fall-through link = block.exits[0] assert link.exitcase in (None, False, True) # the cases False or True should not really occur, but can show # up in the manually hacked graphs for generators... self.make_link(link) # elif block.exitswitch is c_last_exception: # An exception block. See test_exc_exitswitch in test_flatten.py # for an example of what kind of code this makes. index = -1 while True: lastopname = block.operations[index].opname if lastopname != '-live-': break index -= 1 assert block.exits[0].exitcase is None # is this always True? # if not self._include_all_exc_links: if index == -1: # cannot raise: the last instruction is not # actually a '-live-' self.make_link(block.exits[0]) return # self.emitline('catch_exception', TLabel(block.exits[0])) self.make_link(block.exits[0]) self.emitline(Label(block.exits[0])) for link in block.exits[1:]: if (link.exitcase is Exception or (link.exitcase is OverflowError and lastopname.startswith('int_') and lastopname.endswith('_ovf'))): # this link captures all exceptions self.make_exception_link(link) break self.emitline( 'goto_if_exception_mismatch', Constant(link.llexitcase, lltype.typeOf(link.llexitcase)), TLabel(link)) self.make_exception_link(link) self.emitline(Label(link)) else: # no link captures all exceptions, so we have to put a reraise # for the other exceptions self.emitline("reraise") self.emitline("---") # elif len(block.exits) == 2 and (isinstance(block.exitswitch, tuple) or block.exitswitch.concretetype == lltype.Bool): # Two exit links with a boolean condition linkfalse, linktrue = block.exits if linkfalse.llexitcase == True: linkfalse, linktrue = linktrue, linkfalse opname = 'goto_if_not' livebefore = False if isinstance(block.exitswitch, tuple): # special case produced by jtransform.optimize_goto_if_not() opname = 'goto_if_not_' + block.exitswitch[0] opargs = block.exitswitch[1:] if opargs[-1] == '-live-before': livebefore = True opargs = opargs[:-1] else: assert block.exitswitch.concretetype == lltype.Bool opargs = [block.exitswitch] # lst = self.flatten_list(opargs) + [TLabel(linkfalse)] if livebefore: self.emitline('-live-') self.emitline(opname, *lst) if not livebefore: self.emitline('-live-', TLabel(linkfalse)) # true path: self.make_link(linktrue) # false path: self.emitline(Label(linkfalse)) self.make_link(linkfalse) # else: # A switch. # switches = [ link for link in block.exits if link.exitcase != 'default' ] switches.sort(key=lambda link: link.llexitcase) kind = getkind(block.exitswitch.concretetype) assert kind == 'int' # XXX # # A switch on an integer, implementable efficiently with the # help of a SwitchDictDescr. We use this even if there are # very few cases: in pyjitpl.py, opimpl_switch() will promote # the int only if it matches one of the cases. from rpython.jit.codewriter.jitcode import SwitchDictDescr switchdict = SwitchDictDescr() switchdict._labels = [] self.emitline('-live-') # for 'guard_value' self.emitline('switch', self.getcolor(block.exitswitch), switchdict) # emit the default path if block.exits[-1].exitcase == 'default': self.make_link(block.exits[-1]) else: self.emitline("unreachable") self.emitline("---") # for switch in switches: key = lltype.cast_primitive(lltype.Signed, switch.llexitcase) switchdict._labels.append((key, TLabel(switch))) # emit code for that path # note: we need a -live- for all the 'guard_false' we produce # if the switched value doesn't match any case. self.emitline(Label(switch)) self.emitline('-live-') self.make_link(switch)
def handle_unreachable(self, v_result): from rpython.rtyper.lltypesystem.rstr import string_repr msg = "unreachable operation (from malloc.py)" ll_msg = string_repr.convert_const(msg) c_msg = Constant(ll_msg, lltype.typeOf(ll_msg)) return SpaceOperation("debug_fatalerror", [c_msg], v_result)
bhcaller._setup_return_value_r(result) elif result_kind == 'float': bhcaller._setup_return_value_f(result) else: assert False jd.handle_jitexc_from_bh = handle_jitexception_from_blackhole # ____________________________________________________________ # Now mutate origportalgraph to end with a call to portal_runner_ptr # origblock, origindex, op = locate_jit_merge_point(origportalgraph) assert op.opname == 'jit_marker' assert op.args[0].value == 'jit_merge_point' greens_v, reds_v = support.decode_hp_hint_args(op) vlist = [Constant(jd.portal_runner_ptr, jd._PTR_PORTAL_FUNCTYPE)] vlist += greens_v vlist += reds_v v_result = Variable() v_result.concretetype = PORTALFUNC.RESULT newop = SpaceOperation('direct_call', vlist, v_result) del origblock.operations[origindex:] origblock.operations.append(newop) origblock.exitswitch = None origblock.recloseblock(Link([v_result], origportalgraph.returnblock)) # the origportal now can raise (even if it did not raise before), # which means that we cannot inline it anywhere any more, but that's # fine since any forced inlining has been done before # checkgraph(origportalgraph)
def tweak_generator_body_graph(Entry, graph): # First, always run simplify_graph in order to reduce the number of # variables passed around simplify_graph(graph) insert_empty_startblock(graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) op0 = op.simple_call(const(StopIteration)) op1 = op.type(op0.result) stopblock.operations = [op0, op1] stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock)) # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: exit.args = [] exit.target = stopblock assert block is not stopblock for index in range(len(block.operations) - 1, -1, -1): hlop = block.operations[index] if hlop.opname == 'yield_': [v_yielded_value] = hlop.args del block.operations[index] newlink = split_block(block, index) newblock = newlink.target # class Resume(AbstractPosition): _immutable_ = True block = newblock Resume.__name__ = 'Resume%d' % len(mappings) mappings.append(Resume) varnames = get_variable_names(newlink.args) # _insert_reads(newblock, varnames) # op_resume = op.simple_call(const(Resume)) block.operations.append(op_resume) v_resume = op_resume.result for i, name in enumerate(varnames): block.operations.append( op.setattr(v_resume, const(name), newlink.args[i])) op_pair = op.newtuple(v_resume, v_yielded_value) block.operations.append(op_pair) newlink.args = [op_pair.result] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: op_check = op.isinstance(block.inputargs[0], const(Resume)) block.operations.append(op_check) block.exitswitch = op_check.result link1 = Link([block.inputargs[0]], Resume.block) link1.exitcase = True nextblock = Block([Variable('entry')]) link2 = Link([block.inputargs[0]], nextblock) link2.exitcase = False block.closeblock(link1, link2) block = nextblock block.closeblock( Link([ Constant(AssertionError), Constant(AssertionError("bad generator class")) ], graph.exceptblock)) graph.startblock = regular_entry_block graph.signature = Signature(['entry']) graph.defaults = () checkgraph(graph) eliminate_empty_blocks(graph)
def immutablevalue(self, x): """The most precise SomeValue instance that contains the immutable value x.""" # convert unbound methods to the underlying function if hasattr(x, 'im_self') and x.im_self is None: x = x.im_func assert not hasattr(x, 'im_self') tp = type(x) if issubclass(tp, Symbolic): # symbolic constants support result = x.annotation() result.const_box = Constant(x) return result if tp is bool: result = SomeBool() elif tp is int: result = SomeInteger(nonneg=x >= 0) elif tp is long: if -sys.maxint - 1 <= x <= sys.maxint: x = int(x) result = SomeInteger(nonneg=x >= 0) else: raise Exception("seeing a prebuilt long (value %s)" % hex(x)) elif issubclass(tp, str): # py.lib uses annotated str subclasses no_nul = not '\x00' in x if len(x) == 1: result = SomeChar(no_nul=no_nul) else: result = SomeString(no_nul=no_nul) elif tp is unicode: if len(x) == 1: result = SomeUnicodeCodePoint() else: result = SomeUnicodeString() elif tp is bytearray: result = SomeByteArray() elif tp is tuple: result = SomeTuple(items=[self.immutablevalue(e) for e in x]) elif tp is float: result = SomeFloat() elif tp is list: key = Constant(x) try: return self.immutable_cache[key] except KeyError: result = SomeList(ListDef(self, s_ImpossibleValue)) self.immutable_cache[key] = result for e in x: result.listdef.generalize(self.immutablevalue(e)) result.const_box = key return result elif (tp is dict or tp is r_dict or tp is SomeOrderedDict.knowntype or tp is r_ordereddict): key = Constant(x) try: return self.immutable_cache[key] except KeyError: if tp is SomeOrderedDict.knowntype or tp is r_ordereddict: cls = SomeOrderedDict else: cls = SomeDict is_r_dict = issubclass(tp, r_dict) result = cls( DictDef(self, s_ImpossibleValue, s_ImpossibleValue, is_r_dict=is_r_dict)) self.immutable_cache[key] = result if is_r_dict: s_eqfn = self.immutablevalue(x.key_eq) s_hashfn = self.immutablevalue(x.key_hash) result.dictdef.dictkey.update_rdict_annotations( s_eqfn, s_hashfn) seen_elements = 0 while seen_elements != len(x): items = x.items() for ek, ev in items: result.dictdef.generalize_key(self.immutablevalue(ek)) result.dictdef.generalize_value( self.immutablevalue(ev)) result.dictdef.seen_prebuilt_key(ek) seen_elements = len(items) # if the dictionary grew during the iteration, # start over again result.const_box = key return result elif tp is weakref.ReferenceType: x1 = x() if x1 is None: result = SomeWeakRef(None) # dead weakref else: s1 = self.immutablevalue(x1) assert isinstance(s1, SomeInstance) result = SomeWeakRef(s1.classdef) elif tp is property: return SomeProperty(x) elif ishashable(x) and x in BUILTIN_ANALYZERS: _module = getattr(x, "__module__", "unknown") result = SomeBuiltin(BUILTIN_ANALYZERS[x], methodname="%s.%s" % (_module, x.__name__)) elif extregistry.is_registered(x): entry = extregistry.lookup(x) result = entry.compute_annotation_bk(self) elif tp is type: result = SomeConstantType(x, self) elif callable(x): if hasattr(x, 'im_self') and hasattr(x, 'im_func'): # on top of PyPy, for cases like 'l.append' where 'l' is a # global constant list, the find_method() returns non-None s_self = self.immutablevalue(x.im_self) result = s_self.find_method(x.im_func.__name__) elif hasattr(x, '__self__') and x.__self__ is not None: # for cases like 'l.append' where 'l' is a global constant list s_self = self.immutablevalue(x.__self__) result = s_self.find_method(x.__name__) assert result is not None else: result = None if result is None: result = SomePBC([self.getdesc(x)]) elif hasattr(x, '_freeze_'): assert x._freeze_() is True # user-defined classes can define a method _freeze_(), which # is called when a prebuilt instance is found. If the method # returns True, the instance is considered immutable and becomes # a SomePBC(). Otherwise it's just SomeInstance(). result = SomePBC([self.getdesc(x)]) elif hasattr(x, '__class__') \ and x.__class__.__module__ != '__builtin__': if hasattr(x, '_cleanup_'): x._cleanup_() self.see_mutable(x) result = SomeInstance(self.getuniqueclassdef(x.__class__)) elif x is None: return s_None else: raise Exception("Don't know how to represent %r" % (x, )) result.const = x return result