def create_proxy_graph(self, op): """ creates a graph which calls the original function, checks for raised exceptions, fetches and then raises them again. If this graph is inlined, the correct exception matching blocks are produced.""" # XXX slightly annoying: construct a graph by hand # but better than the alternative result = op.result.copy() opargs = [] inputargs = [] callargs = [] ARGTYPES = [] for var in op.args: if isinstance(var, Variable): v = Variable() v.concretetype = var.concretetype inputargs.append(v) opargs.append(v) callargs.append(var) ARGTYPES.append(var.concretetype) else: opargs.append(var) newop = SpaceOperation(op.opname, opargs, result) startblock = Block(inputargs) startblock.operations.append(newop) newgraph = FunctionGraph("dummy_exc1", startblock) startblock.closeblock(Link([result], newgraph.returnblock)) newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype self.gen_exc_check(startblock, newgraph.returnblock) excblock = Block([]) llops = rtyper.LowLevelOpList(None) var_value = self.gen_getfield('exc_value', llops) var_type = self.gen_getfield('exc_type', llops) # c_check1 = self.c_assertion_error_ll_exc_type c_check2 = self.c_n_i_error_ll_exc_type llops.genop('debug_catch_exception', [var_type, c_check1, c_check2]) # self.gen_setfield('exc_value', self.c_null_evalue, llops) self.gen_setfield('exc_type', self.c_null_etype, llops) excblock.operations[:] = llops newgraph.exceptblock.inputargs[ 0].concretetype = self.lltype_of_exception_type newgraph.exceptblock.inputargs[ 1].concretetype = self.lltype_of_exception_value excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock)) startblock.exits[True].target = excblock startblock.exits[True].args = [] fptr = self.constant_func("dummy_exc1", ARGTYPES, op.result.concretetype, newgraph) return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result)
def gen_exc_check(self, block, returnblock, normalafterblock=None): llops = rtyper.LowLevelOpList(None) spaceop = block.operations[-1] alloc_shortcut = self.check_for_alloc_shortcut(spaceop) if alloc_shortcut: var_no_exc = self.gen_nonnull(spaceop.result, llops) else: v_exc_type = self.gen_getfield('exc_type', llops) var_no_exc = self.gen_isnull(v_exc_type, llops) # # We could add a "var_no_exc is likely true" hint, but it seems # not to help, so it was commented out again. #var_no_exc = llops.genop('likely', [var_no_exc], lltype.Bool) block.operations.extend(llops) block.exitswitch = var_no_exc #exception occurred case b = Block([]) b.operations = [ SpaceOperation('debug_record_traceback', [], varoftype(lltype.Void)) ] l = Link([error_constant(returnblock.inputargs[0].concretetype)], returnblock) b.closeblock(l) l = Link([], b) l.exitcase = l.llexitcase = False #non-exception case l0 = block.exits[0] l0.exitcase = l0.llexitcase = True block.recloseblock(l0, l) insert_zeroing_op = False if spaceop.opname in ['malloc', 'malloc_varsize']: flavor = spaceop.args[1].value['flavor'] if flavor == 'gc': insert_zeroing_op = True true_zero = spaceop.args[1].value.get('zero', False) # NB. when inserting more special-cases here, keep in mind that # you also need to list the opnames in transform_block() # (see "special cases") if insert_zeroing_op: if normalafterblock is None: normalafterblock = insert_empty_block(None, l0) v_result = spaceop.result if v_result in l0.args: result_i = l0.args.index(v_result) v_result_after = normalafterblock.inputargs[result_i] else: v_result_after = v_result.copy() l0.args.append(v_result) normalafterblock.inputargs.append(v_result_after) if true_zero: opname = "zero_everything_inside" else: opname = "zero_gc_pointers_inside" normalafterblock.operations.insert( 0, SpaceOperation(opname, [v_result_after], varoftype(lltype.Void)))