def get_livevars_for_roots(self, hop, keep_current_args=False): if self.gcdata.gc.moving_gc and not keep_current_args: # moving GCs don't borrow, so the caller does not need to keep # the arguments alive livevars = [var for var in hop.livevars_after_op() if not var_ispyobj(var)] else: livevars = hop.livevars_after_op() + hop.current_op_keeps_alive() livevars = [var for var in livevars if not var_ispyobj(var)] return livevars
def checkblock(block, is_borrowed, is_start_block): if block.operations == (): # a return/exception block -- don't want to think about them # (even though the test passes for somewhat accidental reasons) return if is_start_block: refs_in = 0 else: refs_in = len([ v for v in block.inputargs if isinstance(v, Variable) and var_needsgc(v) and not is_borrowed(v) ]) push_alives = len( [op for op in block.operations if op.opname == 'gc_push_alive']) pyobj_push_alives = len( [op for op in block.operations if op.opname == 'gc_push_alive_pyobj']) # implicit_pyobj_pushalives included calls to things that return pyobject* implicit_pyobj_pushalives = len([ op for op in block.operations if var_ispyobj(op.result) and op.opname not in ('getfield', 'getarrayitem', 'same_as') ]) nonpyobj_gc_returning_calls = len([ op for op in block.operations if op.opname in ('direct_call', 'indirect_call') and var_needsgc(op.result) and not var_ispyobj(op.result) ]) pop_alives = len( [op for op in block.operations if op.opname == 'gc_pop_alive']) pyobj_pop_alives = len( [op for op in block.operations if op.opname == 'gc_pop_alive_pyobj']) if pop_alives == len(block.operations): # it's a block we inserted return for link in block.exits: assert block.exitswitch is not c_last_exception refs_out = 0 for v2 in link.target.inputargs: if var_needsgc(v2) and not is_borrowed(v2): refs_out += 1 pyobj_pushes = pyobj_push_alives + implicit_pyobj_pushalives nonpyobj_pushes = push_alives + nonpyobj_gc_returning_calls assert refs_in + pyobj_pushes + nonpyobj_pushes == pop_alives + pyobj_pop_alives + refs_out
def checkblock(block, is_borrowed, is_start_block): if block.operations == (): # a return/exception block -- don't want to think about them # (even though the test passes for somewhat accidental reasons) return if is_start_block: refs_in = 0 else: refs_in = len([v for v in block.inputargs if isinstance(v, Variable) and var_needsgc(v) and not is_borrowed(v)]) push_alives = len([op for op in block.operations if op.opname == 'gc_push_alive']) pyobj_push_alives = len([op for op in block.operations if op.opname == 'gc_push_alive_pyobj']) # implicit_pyobj_pushalives included calls to things that return pyobject* implicit_pyobj_pushalives = len([op for op in block.operations if var_ispyobj(op.result) and op.opname not in ('getfield', 'getarrayitem', 'same_as')]) nonpyobj_gc_returning_calls = len([op for op in block.operations if op.opname in ('direct_call', 'indirect_call') and var_needsgc(op.result) and not var_ispyobj(op.result)]) pop_alives = len([op for op in block.operations if op.opname == 'gc_pop_alive']) pyobj_pop_alives = len([op for op in block.operations if op.opname == 'gc_pop_alive_pyobj']) if pop_alives == len(block.operations): # it's a block we inserted return for link in block.exits: assert block.exitswitch is not c_last_exception refs_out = 0 for v2 in link.target.inputargs: if var_needsgc(v2) and not is_borrowed(v2): refs_out += 1 pyobj_pushes = pyobj_push_alives + implicit_pyobj_pushalives nonpyobj_pushes = push_alives + nonpyobj_gc_returning_calls assert refs_in + pyobj_pushes + nonpyobj_pushes == pop_alives + pyobj_pop_alives + refs_out
def test_getfield_pyobj(): class S: pass def f(thing): s = S() s.x = thing return s.x t, transformer = rtype_and_transform(f, [object], _TestGCTransformer) fgraph = graphof(t, f) pyobj_getfields = 0 pyobj_setfields = 0 for b in fgraph.iterblocks(): for op in b.operations: if op.opname == 'getfield' and var_ispyobj(op.result): pyobj_getfields += 1 elif op.opname == 'bare_setfield' and var_ispyobj(op.args[2]): pyobj_setfields += 1 # although there's only one explicit getfield in the code, a # setfield on a pyobj must get the old value out and decref it assert pyobj_getfields >= 2 assert pyobj_setfields >= 1
def test_call_return_pyobj(): def g(factory): return factory() def f(factory): g(factory) t, transformer = rtype_and_transform(f, [object], _TestGCTransformer) fgraph = graphof(t, f) ops = getops(fgraph) calls = ops['direct_call'] for call in calls: if call.result.concretetype is not lltype.Bool: #RPyExceptionOccurred() assert var_ispyobj(call.result)
def dispatch(self): gct = self.gctransformer opname = self.spaceop.opname v_result = self.spaceop.result meth = getattr(gct, 'gct_' + opname, gct.default) meth(self) if var_needsgc(v_result): gct.livevars.append(v_result) if var_ispyobj(v_result): if opname in ('getfield', 'getarrayitem', 'same_as', 'cast_pointer', 'getsubstruct', 'getinteriorfield'): # XXX more operations? gct.push_alive(v_result, self.llops) elif opname not in ('direct_call', 'indirect_call'): gct.push_alive(v_result, self.llops)
def var_needs_set_transform(self, var): return var_ispyobj(var)
def pop_alive(self, var, llops): if var_ispyobj(var): self.pop_alive_pyobj(var, llops) else: self.pop_alive_nopyobj(var, llops)