def newgraph(gv_FUNCTYPE, name): FUNCTYPE = _from_opaque(gv_FUNCTYPE).value # 'name' is just a way to track things name = from_opaque_string(name) inputargs = [] erasedinputargs = [] for ARG in FUNCTYPE.ARGS: v = flowmodel.Variable() v.concretetype = ARG inputargs.append(v) v = flowmodel.Variable() v.concretetype = lltype.erasedType(ARG) erasedinputargs.append(v) startblock = flowmodel.Block(inputargs) # insert an exploding operation here which is removed by # builder.end() to ensure that builder.end() is actually called. startblock.operations.append( flowmodel.SpaceOperation("debug_assert", [ flowmodel.Constant(False, lltype.Bool), flowmodel.Constant("you didn't call builder.end()?", lltype.Void) ], varoftype(lltype.Void))) return_var = flowmodel.Variable() return_var.concretetype = FUNCTYPE.RESULT graph = flowmodel.FunctionGraph(name, startblock, return_var) v1 = flowmodel.Variable() v1.concretetype = lltype.erasedType(FUNCTYPE.RESULT) graph.prereturnblock = flowmodel.Block([v1]) casting_link(graph.prereturnblock, [v1], graph.returnblock) substartblock = flowmodel.Block(erasedinputargs) casting_link(graph.startblock, inputargs, substartblock) fptr = lltype.functionptr(FUNCTYPE, name, graph=graph) return genconst(fptr)
def closelinktofreshblock(link, inputargs=None, otherlink=None): link = _from_opaque(link) prevblockvars = link.prevblock.getvariables() # the next block's inputargs come from 'inputargs' if specified if inputargs is None: inputvars = prevblockvars else: inputvars = _inputvars(inputargs) inputvars = dict.fromkeys(inputvars).keys() # the link's arguments are the same as the inputvars, except # if otherlink is specified, in which case they are copied from otherlink if otherlink is None: linkvars = list(inputvars) else: otherlink = _from_opaque(otherlink) linkvars = list(otherlink.args) # check linkvars for consistency existing_vars = dict.fromkeys(prevblockvars) for v in inputvars: assert isinstance(v, flowmodel.Variable) for v in linkvars: assert v in existing_vars nextblock = flowmodel.Block(inputvars) link.args = linkvars link.target = nextblock return _to_opaque(nextblock)
def meet(hs1, hs2): bk = HintBookkeeper(None) block = flowmodel.Block([]) block.operations.append(flowmodel.SpaceOperation('x', [], flowmodel.Variable())) bk.enter(("graph", block, 0)) bk.current_op_concretetype = lambda: lltype.Signed # hack return pair(hs1, hs2).int_add()
def test_nclc_nongc_not_passed_on(): # +--- inputargs: pointer_to_gc # | v0 <- op_getsubstruct pointer_to_gc 'b' # +--- exitargs: pointer_to_gc (i.e. the pointer to non-gc doesn't leave the block) llops = LowLevelOpList() ptr_a = varoftype(lltype.Ptr(GcA)) v_res = llops.genop("getsubstruct", [ptr_a, model.Constant('b', lltype.Void)], resulttype=lltype.Ptr(NonGcB)) block = model.Block([ptr_a]) block.operations.extend(llops) block.closeblock(model.Link([ptr_a], None)) assert not needs_conservative_livevar_calculation(block)
def test_nclc_should_be_true(): # this is testing a block like: # +--- inputargs: pointer_to_gc # | v0 <- op_getsubstruct pointer_to_gc 'b' # +--- exitargs: v0 (i.e. pointer to non-gc) llops = LowLevelOpList() ptr_a = varoftype(lltype.Ptr(GcA)) v_res = llops.genop("getsubstruct", [ptr_a, model.Constant('b', lltype.Void)], resulttype=lltype.Ptr(NonGcB)) block = model.Block([ptr_a]) block.operations.extend(llops) block.closeblock(model.Link([v_res], None)) assert needs_conservative_livevar_calculation(block)
def test_sbwk_should_insert_keepalives(): # this is testing something like: # v0 <- op_producing_non_gc # v1 <- op_using_v0 <- split here llops = LowLevelOpList() ptr_a = varoftype(lltype.Ptr(GcA)) v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)], resulttype=lltype.Ptr(NonGcB)) llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res], resulttype=lltype.Void) block = model.Block([ptr_a]) block.operations.extend(llops) block.closeblock(model.Link([], None)) link = split_block_with_keepalive(block, 1) assert 'keepalive' in [op.opname for op in link.target.operations]
def test_nclc_ignore_functype(): # +--- inputargs: pointer_to_gc # | v0 <- op_getfield pointer_to_gc 'c' # +--- exitargs: v0 (i.e. a pointer to function) # pointers to functions are 'not gc' but functions are also # immortal so you don't need to muck around inserting keepalives # so *they* don't die! llops = LowLevelOpList() ptr_a = varoftype(lltype.Ptr(GcA)) v_res = llops.genop("getfield", [ptr_a, model.Constant('c', lltype.Void)], resulttype=GcA.c) block = model.Block([ptr_a]) block.operations.extend(llops) block.closeblock(model.Link([v_res], None)) assert not needs_conservative_livevar_calculation(block)
def newblock(): block = flowmodel.Block([]) return _to_opaque(block)