def __init__(self, graph, code): self.graph = graph func = graph.func self.pycode = code self.w_globals = Constant(func.func_globals) self.blockstack = [] self.init_closure(func.func_closure) self.f_lineno = code.co_firstlineno self.last_offset = 0 self.init_locals_stack(code) self.joinpoints = {}
def test_format_assembler_loop(): ssarepr = SSARepr("test") i0, i1 = Register('int', 0), Register('int', 1) ssarepr.insns = [ (Label('L1'), ), ('goto_if_not_int_gt', i0, Constant(0, lltype.Signed), TLabel('L2')), ('int_add', i1, i0, '->', i1), ('int_sub', i0, Constant(1, lltype.Signed), '->', i0), ('goto', TLabel('L1')), (Label('L2'), ), ('int_return', i1), ] asm = format_assembler(ssarepr) expected = """ L1: goto_if_not_int_gt %i0, $0, L2 int_add %i1, %i0 -> %i1 int_sub %i0, $1 -> %i0 goto L1 L2: int_return %i1 """ assert asm == str(py.code.Source(expected)).strip() + '\n'
def test_assemble_list_semibug(): # the semibug is that after forcing 42 into the dict of constants, # it would be reused for all future 42's, even ones that can be # encoded directly. ssarepr = SSARepr("test") ssarepr.insns = [ ('foobar', ListOfKind('int', [Constant(42, lltype.Signed)])), ('foobar', ListOfKind('int', [Constant(42, lltype.Signed)])), ('baz', Constant(42, lltype.Signed)), ('bok', Constant(41, lltype.Signed)), ] assembler = Assembler() jitcode = assembler.assemble(ssarepr) assert jitcode.code == ("\x00\x01\xFF" "\x00\x01\xFF" "\x01\x2A" "\x02\xFE") assert assembler.insns == { 'foobar/I': 0, 'baz/c': 1, # in USE_C_FORM 'bok/i': 2 } # not in USE_C_FORM assert jitcode.constants_i == [42, 41]
def test_liveness(): ssarepr = SSARepr("test") i0, i1, i2 = Register('int', 0), Register('int', 1), Register('int', 2) ssarepr.insns = [ ('int_add', i0, Constant(10, lltype.Signed), '->', i1), ('-live-', i0, i1, i2), ('int_add', i0, Constant(3, lltype.Signed), '->', i2), ('-live-', i2), ] assembler = Assembler() jitcode = assembler.assemble(ssarepr) assert jitcode.code == ( "\x00\x00\x0A\x01" # ends at 4 "\x01\x00\x00" "\x00\x00\x03\x02" # ends at 13 "\x01\x04\x00") assert assembler.insns == {'int_add/ic>i': 0, 'live/': 1} all_liveness = "".join(assembler.all_liveness) op_live = assembler.insns['live/'] with pytest.raises(MissingLiveness): jitcode._live_vars(0, all_liveness, op_live) assert jitcode._live_vars(4, all_liveness, op_live) == '%i0 %i1 %i2' assert jitcode._live_vars(11, all_liveness, op_live) == '%i2'
def cutoff_alwaysraising_block(self, block): "Fix a block whose end can never be reached at run-time." # search the operation that cannot succeed can_succeed = [ op for op in block.operations if op.result.annotation is not None ] cannot_succeed = [ op for op in block.operations if op.result.annotation is None ] n = len(can_succeed) # check consistency assert can_succeed == block.operations[:n] assert cannot_succeed == block.operations[n:] assert 0 <= n < len(block.operations) # chop off the unreachable end of the block del block.operations[n + 1:] self.setbinding(block.operations[n].result, annmodel.s_ImpossibleValue) # insert the equivalent of 'raise AssertionError' graph = self.annotated[block] msg = "Call to %r should have raised an exception" % (getattr( graph, 'func', None), ) c1 = Constant(AssertionError) c2 = Constant(AssertionError(msg)) errlink = Link([c1, c2], graph.exceptblock) block.recloseblock(errlink, *block.exits) # record new link to make the transformation idempotent self.links_followed[errlink] = True # fix the annotation of the exceptblock.inputargs etype, evalue = graph.exceptblock.inputargs s_type = annmodel.SomeType() s_type.is_type_of = [evalue] s_value = annmodel.SomeInstance( self.bookkeeper.getuniqueclassdef(Exception)) self.setbinding(etype, s_type) self.setbinding(evalue, s_value) # make sure the bookkeeper knows about AssertionError self.bookkeeper.getuniqueclassdef(AssertionError)
def test_is_pure(): from rpython.flowspace.model import Variable, Constant assert llop.bool_not.is_pure([Variable()]) assert llop.debug_assert.is_pure([Variable()]) assert not llop.int_add_ovf.is_pure([Variable(), Variable()]) # S1 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed)) v_s1 = Variable() v_s1.concretetype = lltype.Ptr(S1) assert not llop.setfield.is_pure([v_s1, Constant('x'), Variable()]) assert not llop.getfield.is_pure([v_s1, Constant('y')]) # A1 = lltype.GcArray(lltype.Signed) v_a1 = Variable() v_a1.concretetype = lltype.Ptr(A1) assert not llop.setarrayitem.is_pure([v_a1, Variable(), Variable()]) assert not llop.getarrayitem.is_pure([v_a1, Variable()]) assert llop.getarraysize.is_pure([v_a1]) # S2 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed), hints={'immutable': True}) v_s2 = Variable() v_s2.concretetype = lltype.Ptr(S2) assert not llop.setfield.is_pure([v_s2, Constant('x'), Variable()]) assert llop.getfield.is_pure([v_s2, Constant('y')]) # A2 = lltype.GcArray(lltype.Signed, hints={'immutable': True}) v_a2 = Variable() v_a2.concretetype = lltype.Ptr(A2) assert not llop.setarrayitem.is_pure([v_a2, Variable(), Variable()]) assert llop.getarrayitem.is_pure([v_a2, Variable()]) assert llop.getarraysize.is_pure([v_a2]) # for kind in [ rclass.IR_MUTABLE, rclass.IR_IMMUTABLE, rclass.IR_IMMUTABLE_ARRAY, rclass.IR_QUASIIMMUTABLE, rclass.IR_QUASIIMMUTABLE_ARRAY ]: accessor = rclass.FieldListAccessor() S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed), hints={'immutable_fields': accessor}) accessor.initialize(S3, {'x': kind}) v_s3 = Variable() v_s3.concretetype = lltype.Ptr(S3) assert not llop.setfield.is_pure([v_s3, Constant('x'), Variable()]) assert not llop.setfield.is_pure([v_s3, Constant('y'), Variable()]) assert llop.getfield.is_pure([v_s3, Constant('x')]) is kind assert not llop.getfield.is_pure([v_s3, Constant('y')])
def emit_const(self, const, kind, allow_short=False): value = const.value if kind == 'int': TYPE = const.concretetype if isinstance(TYPE, lltype.Ptr): assert TYPE.TO._gckind == 'raw' self.see_raw_object(value) value = llmemory.cast_ptr_to_adr(value) TYPE = llmemory.Address if TYPE == llmemory.Address: value = heaptracker.adr2int(value) if TYPE is lltype.SingleFloat: value = longlong.singlefloat2int(value) if not isinstance(value, (llmemory.AddressAsInt, ComputedIntSymbolic)): value = lltype.cast_primitive(lltype.Signed, value) if allow_short: try: short_num = -128 <= value <= 127 except TypeError: # "Symbolics cannot be compared!" short_num = False if short_num: # emit the constant as a small integer self.code.append(chr(value & 0xFF)) return True constants = self.constants_i elif kind == 'ref': value = lltype.cast_opaque_ptr(llmemory.GCREF, value) constants = self.constants_r elif kind == 'float': if const.concretetype == lltype.Float: value = longlong.getfloatstorage(value) else: assert longlong.is_longlong(const.concretetype) value = rffi.cast(lltype.SignedLongLong, value) constants = self.constants_f else: raise AssemblerError('unimplemented %r in %r' % (const, self.ssareprname)) key = (kind, Constant(value)) if key not in self.constants_dict: constants.append(value) val = 256 - len(constants) assert val >= 0, "too many constants" self.constants_dict[key] = val # emit the constant normally, as one byte that is an index in the # list of constants self.code.append(chr(self.constants_dict[key])) return False
def builtin_func_for_spec(rtyper, oopspec_name, ll_args, ll_res, extra=None, extrakey=None): assert (extra is None) == (extrakey is None) key = (oopspec_name, tuple(ll_args), ll_res, extrakey) try: return rtyper._builtin_func_for_spec_cache[key] except (KeyError, AttributeError): pass args_s = [lltype_to_annotation(v) for v in ll_args] if '.' not in oopspec_name: # 'newxxx' operations LIST_OR_DICT = ll_res else: LIST_OR_DICT = ll_args[0] s_result = lltype_to_annotation(ll_res) impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s), extra) if getattr(impl, 'need_result_type', False): if hasattr(rtyper, 'annotator'): bk = rtyper.annotator.bookkeeper ll_restype = ll_res if impl.need_result_type != 'exact': ll_restype = ll_restype.TO desc = bk.getdesc(ll_restype) else: class TestingDesc(object): knowntype = int pyobj = None desc = TestingDesc() args_s.insert(0, annmodel.SomePBC([desc])) # if hasattr(rtyper, 'annotator'): # regular case mixlevelann = MixLevelHelperAnnotator(rtyper) c_func = mixlevelann.constfunc(impl, args_s, s_result) mixlevelann.finish() else: # for testing only c_func = Constant(oopspec_name, lltype.Ptr(lltype.FuncType(ll_args, ll_res))) # if not hasattr(rtyper, '_builtin_func_for_spec_cache'): rtyper._builtin_func_for_spec_cache = {} rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT) # return c_func, LIST_OR_DICT
def instrument_inline_candidates(graphs, threshold): cache = {None: False} def candidate(graph): try: return cache[graph] except KeyError: res = static_instruction_count(graph) <= threshold cache[graph] = res return res n = 0 for parentgraph in graphs: for block in parentgraph.iterblocks(): ops = block.operations i = len(ops) - 1 while i >= 0: op = ops[i] i -= 1 if op.opname == "direct_call": funcobj = op.args[0].value._obj graph = getattr(funcobj, 'graph', None) if graph is not None: if getattr(getattr(funcobj, '_callable', None), '_dont_inline_', False): continue if candidate(graph): tag = Constant('inline', Void) label = Constant(n, Signed) dummy = Variable() dummy.concretetype = Void count = SpaceOperation('instrument_count', [tag, label], dummy) ops.insert(i + 1, count) n += 1 log.inlining("%d call sites instrumented" % n)
def replace_force_quasiimmut_with_direct_call(self, op): ARG = op.args[0].concretetype mutatefieldname = op.args[1].value key = (ARG, mutatefieldname) if key in self._cache_force_quasiimmed_funcs: cptr = self._cache_force_quasiimmed_funcs[key] else: from rpython.jit.metainterp import quasiimmut func = quasiimmut.make_invalidation_function(ARG, mutatefieldname) FUNC = lltype.Ptr(lltype.FuncType([ARG], lltype.Void)) llptr = self.helper_func(FUNC, func) cptr = Constant(llptr, FUNC) self._cache_force_quasiimmed_funcs[key] = cptr op.opname = 'direct_call' op.args = [cptr, op.args[0]]
def convert_const(self, value): if value is None: return self.null_wref assert isinstance(value, weakref.ReferenceType) instance = value() bk = self.rtyper.annotator.bookkeeper # obscure! if the annotator hasn't seen this object before, # we don't want to look at it now (confusion tends to result). if instance is None or not bk.have_seen(instance): return self.dead_wref else: repr = self.rtyper.bindingrepr(Constant(instance)) llinstance = repr.convert_const(instance) return self._weakref_create(llinstance)
def test_assemble_cast_consts(): ssarepr = SSARepr("test") S = lltype.GcStruct('S') s = lltype.malloc(S) F = lltype.FuncType([], lltype.Signed) f = lltype.functionptr(F, 'f') ssarepr.insns = [ ('int_return', Constant('X', lltype.Char)), ('int_return', Constant(unichr(0x1234), lltype.UniChar)), ('int_return', Constant(f, lltype.Ptr(F))), ('ref_return', Constant(s, lltype.Ptr(S))), ] assembler = Assembler() jitcode = assembler.assemble(ssarepr) assert jitcode.code == ("\x00\x58" "\x01\xFF" "\x01\xFE" "\x02\xFF") assert assembler.insns == { 'int_return/c': 0, 'int_return/i': 1, 'ref_return/r': 2 } f_int = heaptracker.adr2int(llmemory.cast_ptr_to_adr(f)) assert jitcode.constants_i == [0x1234, f_int] s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s) assert jitcode.constants_r == [s_gcref]
def test__flowspace_rewrite_directly_as_(self): def g(x): pass def f(x): pass f._flowspace_rewrite_directly_as_ = g def h(x): f(x) graph = self.codetest(h) assert self.all_operations(graph) == {'simple_call': 1} for block in graph.iterblocks(): if block.operations: op = block.operations[0] assert op.opname == 'simple_call' assert op.args[0] == Constant(g)
def consider_lookup_in_type_where(self, bookkeeper, attr): assert attr not in self.lookups_where from pypy.objspace.std import typeobject cached = "cached_where_%s" % attr clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject) classdesc = clsdef.classdesc classdesc.immutable_fields.add(cached) classdesc.classdict[cached] = Constant((None, None)) clsdef.add_source_for_attribute(cached, classdesc) for t in self.pypytypes: if not (t.is_heaptype() or t.is_cpytype()): setattr(t, cached, t._lookup_where(attr)) source = InstanceSource(bookkeeper, t) clsdef.add_source_for_attribute(cached, source) self.lookups_where[attr] = True
def recursively_flatten(lst): from rpython.flowspace.flowcontext import FlowSignal i = 0 while i < len(lst): unroller = lst[i] if not isinstance(unroller, FlowSignal): i += 1 else: vars = unroller.state_unpack_variables() key = unroller.__class__, len(vars) try: tag = PICKLE_TAGS[key] except KeyError: tag = PICKLE_TAGS[key] = Constant(PickleTag()) UNPICKLE_TAGS[tag] = key lst[i:i + 1] = [tag] + vars
def test_arg_sublist_1(self): v1 = varoftype(lltype.Signed) v2 = varoftype(lltype.Char) v3 = varoftype(rclass.OBJECTPTR) v4 = varoftype(lltype.Ptr(rstr.STR)) v5 = varoftype(lltype.Float) op = SpaceOperation('residual_call_ir_f', [Constant(12345, lltype.Signed), # function ptr ListOfKind('int', [v1, v2]), # int args ListOfKind('ref', [v3, v4])], # ref args v5) # result flattener = GraphFlattener(None, fake_regallocs()) flattener.serialize_op(op) assert_format(flattener.ssarepr, """ residual_call_ir_f $12345, I[%i0, %i1], R[%r0, %r1] -> %f0 """)
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 clone_inlined_jit_merge_points(self, graphs): """ Find all the jit_merge_points in the given graphs, and replace the original JitDriver with a fresh clone. """ if not graphs: return for graph, block, pos in find_jit_merge_points(graphs): op = block.operations[pos] v_driver = op.args[1] driver = v_driver.value if not driver.inline_jit_merge_point: continue new_driver = driver.clone() c_new_driver = Constant(new_driver, v_driver.concretetype) op.args[1] = c_new_driver
def materialize_object(obj_key, state, ops): """ Accepts a VirtualState object and creates the required operations, for its materialization/initialization. XXX: Edits ops in-place """ if obj_key not in state: return False # We're gonna delete the object from the state dict first (since it has # escaped) for correct recursion reasons in case of cyclic dependency. # this needs to be done with all the aliases of the object! vo = state[obj_key] # Thus, we'll make a copy first. assert obj_key in vo.aliases for key in vo.aliases: del state[key] # Starting assembling the operations. Creation and required castings: newvar = Variable() newvar.concretetype = vo.concretetype ops.append(SpaceOperation('malloc', vo.malloc_args, newvar)) # recreate the aliases for var in vo.aliases: if var.concretetype != vo.concretetype: ops.append(SpaceOperation('cast_pointer', [newvar], var)) else: ops.append(SpaceOperation('same_as', [newvar], var)) # Initialization for (key, concretetype), value in vo.vars.items(): if concretetype != vo.concretetype: # we need a cast_pointer v = Variable() v.concretetype = concretetype op = SpaceOperation('cast_pointer', [newvar], v) ops.append(op) target = v else: target = newvar # What if the assigned is a virtual object? Recursion: materialize_object(value, state, ops) m = Variable() m.concretetype = lltype.Void ops.append(SpaceOperation('setfield', [target, Constant(key, lltype.Void), value], m)) return True
def expand_one_push_roots(regalloc, args): if regalloc is None: assert len(args) == 0 else: filled = [False] * regalloc.numcolors for v in args: index = regalloc.getcolor(v) assert not filled[index] filled[index] = True yield _gc_save_root(index, v) bitmask_index, bitmask = make_bitmask(filled, regalloc.graph) if bitmask_index is not None: # xxx we might in some cases avoid this gc_save_root # entirely, if we know we're after another gc_push/gc_pop # that wrote exactly the same mask at the same index bitmask_c = Constant(bitmask, lltype.Signed) yield _gc_save_root(bitmask_index, bitmask_c)
def constant_diffuse(graph): count = 0 # after 'exitswitch vexit', replace 'vexit' with the corresponding constant # if it also appears on the outgoing links for block in graph.iterblocks(): vexit = block.exitswitch if isinstance(vexit, Variable): for link in block.exits: if vexit in link.args and link.exitcase != 'default': remap = { vexit: Constant(link.llexitcase, vexit.concretetype) } link.args = [remap.get(v, v) for v in link.args] count += 1 # if the same constants appear at the same positions in all links # into a block remove them from the links, remove the corresponding # input variables and introduce equivalent same_as at the beginning # of the block then try to fold the block further for block, links in mkentrymap(graph).iteritems(): if block is graph.startblock: continue if block.exits == (): continue firstlink = links[0] rest = links[1:] diffuse = [] for i, c in enumerate(firstlink.args): if not isinstance(c, Constant): continue for lnk in rest: if lnk.args[i] != c: break else: diffuse.append((i, c)) diffuse.reverse() same_as = [] for i, c in diffuse: for lnk in links: del lnk.args[i] v = block.inputargs.pop(i) same_as.append(SpaceOperation('same_as', [c], v)) count += 1 block.operations = same_as + block.operations if same_as: constant_fold_block(block) return count
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 test_frozen_user_class2(self): class C: def __add__(self, other): return 4 def _freeze_(self): return True c = C() d = C() def f(): return c+d graph = self.codetest(f) results = [] for link in graph.iterlinks(): if link.target == graph.returnblock: results.extend(link.args) assert results == [Constant(4)]
def test_join_blocks_cleans_links(): from rpython.rtyper.lltypesystem import lltype from rpython.flowspace.model import Constant from rpython.translator.backendopt.removenoops import remove_same_as def f(x): return bool(x + 2) def g(x): if f(x): return 1 else: return 2 graph, t = translate(g, [int], backend_optimize=False) fgraph = graphof(t, f) fgraph.startblock.exits[0].args = [Constant(True, lltype.Bool)] # does not crash: previously join_blocks would barf on this remove_same_as(graph) backend_optimizations(t)
def insert_ll_stackcheck(translator): from rpython.translator.backendopt.support import find_calls_from from rpython.rlib.rstack import stack_check from rpython.tool.algo.graphlib import Edge, make_edge_dict, break_cycles_v rtyper = translator.rtyper graph = rtyper.annotate_helper(stack_check, []) rtyper.specialize_more_blocks() stack_check_ptr = rtyper.getcallable(graph) stack_check_ptr_const = Constant(stack_check_ptr, lltype.typeOf(stack_check_ptr)) edges = set() insert_in = set() block2graph = {} for caller in translator.graphs: pyobj = getattr(caller, 'func', None) if pyobj is not None: if getattr(pyobj, '_dont_insert_stackcheck_', False): continue for block, callee in find_calls_from(translator, caller): if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False): insert_in.add(callee.startblock) block2graph[callee.startblock] = callee continue if block is not caller.startblock: edges.add((caller.startblock, block)) block2graph[caller.startblock] = caller edges.add((block, callee.startblock)) block2graph[block] = caller edgelist = [Edge(block1, block2) for (block1, block2) in edges] edgedict = make_edge_dict(edgelist) for block in break_cycles_v(edgedict, edgedict): insert_in.add(block) for block in insert_in: v = Variable() v.concretetype = lltype.Void unwind_op = SpaceOperation('direct_call', [stack_check_ptr_const], v) block.operations.insert(0, unwind_op) # prevents cycles of tail calls from occurring -- such cycles would # not consume any stack, so would turn into potentially infinite loops graph = block2graph[block] graph.inhibit_tail_call = True return len(insert_in)
def add_source_attribute(self, name, value, mixin=False): if isinstance(value, types.FunctionType): # for debugging if not hasattr(value, 'class_'): value.class_ = self.pyobj if self.specialize: # make a custom funcdesc that specializes on its first # argument (i.e. 'self'). from rpython.annotator.specialize import specialize_argtype def argtype0(funcdesc, args_s): return specialize_argtype(funcdesc, args_s, 0) funcdesc = FunctionDesc(self.bookkeeper, value, specializer=argtype0) self.classdict[name] = funcdesc return if mixin: # make a new copy of the FunctionDesc for this class, # but don't specialize further for all subclasses funcdesc = FunctionDesc(self.bookkeeper, value) self.classdict[name] = funcdesc return # NB. if value is, say, AssertionError.__init__, then we # should not use getdesc() on it. Never. The problem is # that the py lib has its own AssertionError.__init__ which # is of type FunctionType. But bookkeeper.immutablevalue() # will do the right thing in s_get_value(). if isinstance(value, staticmethod) and mixin: # make a new copy of staticmethod func = value.__get__(42) value = staticmethod(func_with_new_name(func, func.__name__)) if type(value) in MemberDescriptorTypes: # skip __slots__, showing up in the class as 'member' objects return if name == '__init__' and self.is_builtin_exception_class(): # pretend that built-in exceptions have no __init__, # unless explicitly specified in builtin.py from rpython.annotator.builtin import BUILTIN_ANALYZERS value = getattr(value, 'im_func', value) if value not in BUILTIN_ANALYZERS: return self.classdict[name] = Constant(value)
def test_graphs_from_indirect_call(): cc = CallControl() F = lltype.FuncType([], lltype.Signed) v = varoftype(lltype.Signed) graphlst = ['f1graph', 'f2graph'] op = SpaceOperation( 'indirect_call', [varoftype(lltype.Ptr(F)), Constant(graphlst, lltype.Void)], v) # lst = cc.graphs_from(op, {'f1graph': True, 'f2graph': True}.__contains__) assert lst == ['f1graph', 'f2graph'] # normal indirect call # lst = cc.graphs_from(op, {'f1graph': True}.__contains__) assert lst == ['f1graph'] # indirect call, look only inside some graphs # lst = cc.graphs_from(op, {}.__contains__) assert lst is None # indirect call, don't look inside any graph
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 rtype_simple_call(self, hop): # methods: look up the rtype_method_xxx() name = 'rtype_method_' + self.methodname try: bltintyper = getattr(self.self_repr, name) except AttributeError: raise TyperError("missing %s.%s" % (self.self_repr.__class__.__name__, name)) # hack based on the fact that 'lowleveltype == self_repr.lowleveltype' hop2 = hop.copy() assert hop2.args_r[0] is self if isinstance(hop2.args_v[0], Constant): c = hop2.args_v[0].value # get object from bound method c = c.__self__ hop2.args_v[0] = Constant(c) hop2.args_s[0] = self.s_self hop2.args_r[0] = self.self_repr return bltintyper(hop2)
def make_exception_link(self, link, handling_ovf): # Like make_link(), but also introduces the 'last_exception' and # 'last_exc_value' as variables if needed. Also check if the link # is jumping directly to the re-raising exception block. assert link.last_exception is not None assert link.last_exc_value is not None if link.target.operations == () and link.args == [link.last_exception, link.last_exc_value]: if handling_ovf: exc_data = self.cpu.rtyper.exceptiondata ll_ovf = exc_data.get_standard_ll_exc_instance_by_class( OverflowError) c = Constant(ll_ovf, concretetype=lltype.typeOf(ll_ovf)) self.emitline("raise", c) else: self.emitline("reraise") self.emitline("---") return # done self.make_link(link, handling_ovf)