def test_bridge_from_guard_exception_may_force(self): myjitdriver = JitDriver(greens=[], reds=['n']) c_time = rffi.llexternal("time", [lltype.Signed], lltype.Signed) def check(n): if n % 2: raise ValueError if n == 100000: c_time(0) def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) try: check(n) n -= 1 except ValueError: n -= 3 return n res = self.meta_interp(f, [20], policy=StopAtXPolicy(check)) assert res == f(20) res = self.meta_interp(f, [21], policy=StopAtXPolicy(check)) assert res == f(21)
def test_forced_virtual_assigned_in_bridge(self): myjitdriver = JitDriver(greens=[], reds=['n', 's', 'node', 'node2']) def externfn(node): node.value += 1 def f(n, s): node = self._new() node.value = 1 node2 = self._new() node2.value = 2 while n > 0: myjitdriver.can_enter_jit(n=n, s=s, node=node, node2=node2) myjitdriver.jit_merge_point(n=n, s=s, node=node, node2=node2) next = self._new() next.value = node.value + 1 node = next if (n >> s) & 1: node2.value += node.value node = node2 externfn(node) n -= 1 return node.value res = self.meta_interp(f, [48, 3], policy=StopAtXPolicy(externfn)) assert res == f(48, 3) self.check_trace_count(4) res = self.meta_interp(f, [40, 3], policy=StopAtXPolicy(externfn)) assert res == f(40, 3) self.check_trace_count(3)
def test_indirect_call_unknown_object_2(self): myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'state']) def getvalue2(): return 2 def getvalue25(): return 25 def getvalue1001(): return -1001 class State: count = 0 def externfn(self, n): assert n == 198 - self.count self.count += 1 if n % 5: return getvalue2 elif n % 7: return getvalue25 else: return getvalue1001 def f(y): state = State() x = 0 while y > 0: myjitdriver.can_enter_jit(x=x, y=y, state=state) myjitdriver.jit_merge_point(x=x, y=y, state=state) x += state.externfn(y)() y -= 1 return x res = self.meta_interp(f, [198], policy=StopAtXPolicy(State.externfn.im_func)) assert res == f(198) # we get two TargetTokens, one for the loop and one for the preamble self.check_jitcell_token_count(1) self.check_target_token_count(2)
def test_indirect_call_unknown_object_1(self): myjitdriver = JitDriver(greens = [], reds = ['x', 'y']) def getvalue2(): return 2 def getvalue25(): return 25 def getvalue1001(): return -1001 def externfn(n): if n % 5: return getvalue2 elif n % 7: return getvalue25 else: return getvalue1001 def f(y): x = 0 while y > 0: myjitdriver.can_enter_jit(x=x, y=y) myjitdriver.jit_merge_point(x=x, y=y) x += externfn(y)() y -= 1 return x res = self.meta_interp(f, [198], policy=StopAtXPolicy(externfn)) assert res == f(198) self.check_trace_count(4)
def test_adapt_bridge_to_merge_point(self): myjitdriver = JitDriver(greens=[], reds=['x', 'z']) class Z(object): def __init__(self, elem): self.elem = elem def externfn(z): pass def f(x, y): z = Z(y) while x > 0: myjitdriver.can_enter_jit(x=x, z=z) myjitdriver.jit_merge_point(x=x, z=z) if x % 5 != 0: externfn(z) z = Z(z.elem + 1) x -= 1 return z.elem expected = f(100, 5) res = self.meta_interp(f, [100, 5], policy=StopAtXPolicy(externfn)) assert res == expected if self.enable_opts: self.check_trace_count(2) self.check_jitcell_token_count(1) # 1 loop with bridge from interp else: self.check_trace_count(2) self.check_jitcell_token_count( 1) # 1 loop, callable from the interp
def test_three_receivers(self): myjitdriver = JitDriver(greens = [], reds = ['y']) class Base: pass class W1(Base): def foo(self): return 1 class W2(Base): def foo(self): return 2 class W3(Base): def foo(self): return 3 def externfn(y): lst = [W1, W1, W2, W2, W3, W3, W2, W1, W3] W = lst[y % len(lst)] return W() def f(y): while y > 0: myjitdriver.can_enter_jit(y=y) myjitdriver.jit_merge_point(y=y) w = externfn(y) w.foo() y -= 1 return 42 policy = StopAtXPolicy(externfn) for j in range(69, 75): res = self.meta_interp(f, [j], policy=policy) assert res == 42 self.check_enter_count_at_most(5) self.check_trace_count_at_most(5)
def test_bridge_from_interpreter_exc_2(self): mydriver = JitDriver(reds=['n'], greens=[]) def x(n): if n == 1: raise MyError(n) def f(n): try: while n > 0: mydriver.can_enter_jit(n=n) mydriver.jit_merge_point(n=n) x(n) n -= 1 except MyError: z() def z(): raise ValueError def main(n): try: f(n) return 3 except MyError as e: return e.n except ValueError: return 8 res = self.meta_interp(main, [41], repeat=7, policy=StopAtXPolicy(x), enable_opts='') assert res == 8
def test_loop_with_two_paths(self): from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.lltypesystem.lloperation import llop myjitdriver = JitDriver(greens=[], reds=['x', 'y', 'res']) def l(y, x, t): llop.debug_print(lltype.Void, y, x, t) def g(y, x, r): if y <= 12: res = x - 2 else: res = x l(y, x, r) return res def f(x, y): res = 0 while y > 0: myjitdriver.can_enter_jit(x=x, y=y, res=res) myjitdriver.jit_merge_point(x=x, y=y, res=res) res += g(y, x, res) y -= 1 return res * 2 res = self.meta_interp(f, [6, 33], policy=StopAtXPolicy(l)) assert res == f(6, 33) if self.enable_opts: self.check_trace_count(2) else: self.check_trace_count(2)
def test_three_classes(self): class Base: pass class A(Base): def f(self): return 1 class B(Base): def f(self): return 2 class C(Base): def f(self): return 3 myjitdriver = JitDriver(greens = [], reds = ['n']) def extern(n): if n > 40: return A() elif n > 20: return B() else: return C() def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) n -= extern(n).f() return n res = self.meta_interp(f, [55], policy=StopAtXPolicy(extern)) assert res == f(55) self.check_jitcell_token_count(1)
def test_send_to_single_target_method(self): myjitdriver = JitDriver(greens = [], reds = ['i', 'counter']) class Foo: def meth(self, y): return self.x + y def externfn(i): foo = Foo() foo.x = i * 42 return foo def f(i): counter = 20 res = 0 while counter > 0: myjitdriver.can_enter_jit(counter=counter, i=i) myjitdriver.jit_merge_point(counter=counter, i=i) foo = externfn(i) res = foo.meth(i) counter -= 1 return res res = self.meta_interp(f, [1], policy=StopAtXPolicy(externfn), backendopt=True) assert res == 43 self.check_resops({'int_gt': 2, 'getfield_gc': 2, 'guard_true': 2, 'int_sub': 2, 'jump': 1, 'call': 2, 'guard_no_exception': 2, 'int_add': 2})
def test_assembler_call_red_args(self): driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'], get_printable_location = lambda codeno : str(codeno)) def residual(k): if k > 150: return 0 return 1 def portal(codeno, k): i = 0 while i < 15: driver.can_enter_jit(codeno=codeno, i=i, k=k) driver.jit_merge_point(codeno=codeno, i=i, k=k) if codeno == 2: k += portal(residual(k), k) if codeno == 0: k += 2 elif codeno == 1: k += 1 i += 1 return k res = self.meta_interp(portal, [2, 0], inline=True, policy=StopAtXPolicy(residual)) assert res == portal(2, 0) self.check_resops(call_assembler=4)
def test_two_loops_with_escaping_virtual(self): myjitdriver = JitDriver(greens=[], reds=['n', 'node']) def externfn(node): llop.debug_print(lltype.Void, compute_unique_id(node), node.value, node.extra) return node.value * 2 def f(n): node = self._new() node.value = 0 node.extra = 0 while n > 0: myjitdriver.can_enter_jit(n=n, node=node) myjitdriver.jit_merge_point(n=n, node=node) next = self._new() next.value = node.value + n next.extra = node.extra + 1 if next.extra == 5: next.value = externfn(next) next.extra = 0 node = next n -= 1 return node.value res = self.meta_interp(f, [20], policy=StopAtXPolicy(externfn)) assert res == f(20) self.check_trace_count(2) self.check_resops(**{self._new_op: 1}) self.check_resops(int_mul=0, call_i=1)
def test_escapes(self): myjitdriver = JitDriver(greens=[], reds=['n', 'parent']) class Parent(object): def __init__(self, node): self.node = node def g(x): pass def f(n): node = self._new() node.value = 3 parent = Parent(node) while n > 0: myjitdriver.can_enter_jit(n=n, parent=parent) myjitdriver.jit_merge_point(n=n, parent=parent) node = parent.node g(node) newnode = self._new() newnode.value = 3 parent = Parent(newnode) n -= 1 return parent.node.value res = self.meta_interp(f, [10], policy=StopAtXPolicy(g)) assert res == 3 self.check_resops(**{self._new_op: 1})
def test_raise_through_wrong_exc_2(self): myjitdriver = JitDriver(greens=[], reds=['n']) def check(n): if n < 0: raise ValueError else: raise IndexError def f(n): while True: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) try: check(n) except IndexError: n -= 1 def main(n): try: f(n) except ValueError: return 132 res = self.meta_interp(main, [13], policy=StopAtXPolicy(check)) assert res == 132
def test_invalidate_while_running(self): jitdriver = JitDriver(greens=['foo'], reds=['i', 'total']) class Foo(object): _immutable_fields_ = ['a?'] def __init__(self, a): self.a = a def external(foo, v): if v: foo.a = 2 def f(foo): i = 0 total = 0 while i < 10: jitdriver.jit_merge_point(i=i, foo=foo, total=total) external(foo, i > 7) i += 1 total += foo.a return total def g(): return f(Foo(1)) assert self.meta_interp(g, [], policy=StopAtXPolicy(external)) == g()
def test_residual_oosend_with_void(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: def foo(self, other): return 41 def _freeze_(self): return True def new(n): if n: return A() else: return None pbc = A() def fn(n, i): res = 0 obj = new(n) while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) res = obj.foo(pbc) i-=1 return res policy = StopAtXPolicy(new, A.foo.im_func) res = self.meta_interp(fn, [1, 20], policy=policy) assert res == 41 self.check_resops(call=2)
def test_residual_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: def foo(self): return 41 class B(A): def foo(self): return 42 def new(n): if n: return A() else: return B() def fn(n, i): res = 0 obj = new(n) while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) res = obj.foo() i-=1 return res policy = StopAtXPolicy(new, A.foo.im_func, B.foo.im_func) res = self.meta_interp(fn, [0, 20], policy=policy) assert res == 42 self.check_resops(call=2)
def test_bug1(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'node']) class Base: pass class A(Base): def decr(self, n): return n - 2 class B(Base): def __init__(self, n): self.n = n def decr(self, n): assert n == self.n return self.n - 1 def extern(n): if n <= 21: return B(n) else: return A() def f(n): node = A() while n >= 0: myjitdriver.can_enter_jit(node=node, n=n) myjitdriver.jit_merge_point(node=node, n=n) n = node.decr(n) node = extern(n) return n res = self.meta_interp(f, [60], policy=StopAtXPolicy(extern)) assert res == f(60)
def test_forced_virtual_assigned_different_class_in_bridge(self): myjitdriver = JitDriver(greens=[], reds=['n', 's', 'node', 'node2']) def externfn(node): node.value += 1 class A(object): def __init__(self, value): self.value = value def op(self, val): return self.value + val class B(A): def op(self, val): return self.value - val def f(n, s, node2): node = A(1) while n > 0: myjitdriver.can_enter_jit(n=n, s=s, node=node, node2=node2) myjitdriver.jit_merge_point(n=n, s=s, node=node, node2=node2) if (n >> s) & 1: node2.value += node.value node = node2 else: node.value = node.op(1) node = A(node.value + 7) externfn(node) n -= 1 return node.value def g1(n, s): return f(n, s, A(2)) + f(n, s, B(2)) def g2(n, s): return f(n, s, B(2)) + f(n, s, A(2)) res = self.meta_interp(g1, [40, 3], policy=StopAtXPolicy(externfn)) assert res == g1(40, 3) res = self.meta_interp(g1, [48, 3], policy=StopAtXPolicy(externfn)) assert res == g1(48, 3) res = self.meta_interp(g2, [40, 3], policy=StopAtXPolicy(externfn)) assert res == g2(40, 3) res = self.meta_interp(g2, [48, 3], policy=StopAtXPolicy(externfn)) assert res == g2(48, 3)
def test_directly_call_assembler_virtualizable_force1(self): class Thing(object): def __init__(self, val): self.val = val class Frame(object): _virtualizable_ = ['thing'] driver = JitDriver(greens=['codeno'], reds=['i', 'frame'], virtualizables=['frame'], get_printable_location=lambda codeno: str(codeno)) class SomewhereElse(object): pass somewhere_else = SomewhereElse() def change(newthing): somewhere_else.frame.thing = newthing def main(codeno): frame = Frame() somewhere_else.frame = frame frame.thing = Thing(0) portal(codeno, frame) return frame.thing.val def portal(codeno, frame): print 'ENTER:', codeno, frame.thing.val i = 0 while i < 10: driver.can_enter_jit(frame=frame, codeno=codeno, i=i) driver.jit_merge_point(frame=frame, codeno=codeno, i=i) nextval = frame.thing.val if codeno == 0: subframe = Frame() subframe.thing = Thing(nextval) nextval = portal(1, subframe) elif codeno == 1: if frame.thing.val > 40: change(Thing(13)) nextval = 13 else: fatalerror("bad codeno = " + str(codeno)) frame.thing = Thing(nextval + 1) i += 1 print 'LEAVE:', codeno, frame.thing.val return frame.thing.val res = self.meta_interp(main, [0], inline=True, policy=StopAtXPolicy(change)) assert res == main(0)
def test_single_virtual_forced_in_bridge(self): myjitdriver = JitDriver(greens=[], reds=['n', 's', 'node']) def externfn(node): node.value *= 2 def f(n, s): node = self._new() node.value = 1 while n > 0: myjitdriver.can_enter_jit(n=n, s=s, node=node) myjitdriver.jit_merge_point(n=n, s=s, node=node) next = self._new() next.value = node.value + 1 node = next if (n >> s) & 1: externfn(node) n -= 1 return node.value res = self.meta_interp(f, [48, 3], policy=StopAtXPolicy(externfn)) assert res == f(48, 3) res = self.meta_interp(f, [40, 3], policy=StopAtXPolicy(externfn)) assert res == f(40, 3)
def test_bridge_from_guard_exception(self): myjitdriver = JitDriver(greens=[], reds=['n']) def check(n): if n % 2: raise ValueError def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) try: check(n) n -= 1 except ValueError: n -= 3 return n res = self.meta_interp(f, [20], policy=StopAtXPolicy(check)) assert res == f(20) res = self.meta_interp(f, [21], policy=StopAtXPolicy(check)) assert res == f(21)
def test_generalize_loop(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: def __init__(self, n): self.n = n def extern(obj): pass def fn(i): obj = A(1) while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) obj = A(obj.n + 1) if i < 10: extern(obj) i -= 1 return obj.n res = self.meta_interp(fn, [20], policy=StopAtXPolicy(extern)) assert res == 21
def test_bug_1(self): myjitdriver = JitDriver(greens=[], reds=['n', 'i', 'stack']) def opaque(n, i): if n == 1 and i == 19: for j in range(20): res = f(0) # recurse repeatedly, 20 times assert res == 0 def f(n): stack = [n] i = 0 while i < 20: myjitdriver.can_enter_jit(n=n, i=i, stack=stack) myjitdriver.jit_merge_point(n=n, i=i, stack=stack) opaque(n, i) i += 1 return stack.pop() res = self.meta_interp(f, [1], enable_opts='', repeat=2, policy=StopAtXPolicy(opaque)) assert res == 1
def test_exception_two_cases_2(self): myjitdriver = JitDriver(greens=[], reds=['n']) class Error1(Exception): pass class Error2(Exception): pass class Error3(Exception): pass class Error4(Exception): pass def check(n): if n > 0: raise Error3 else: raise Error2 def g(n): check(n) def f(n): while True: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) try: g(n) except Error1: pass except Error2: break except Error3: n = n - 5 except Error4: pass return n res = self.meta_interp(f, [53], policy=StopAtXPolicy(check)) assert res == -2
def test_exception_later(self): myjitdriver = JitDriver(greens=[], reds=['n']) def check(n): if n < 0: raise MyError(n) return 5 def f(n): try: while True: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) n = n - check(n) except MyError as e: return e.n assert f(53) == -2 res = self.meta_interp(f, [53], policy=StopAtXPolicy(check)) assert res == -2
def test_red_builtin_send(self): myjitdriver = JitDriver(greens = [], reds = ['i', 'counter']) lst = [{1:1, 2:2, 3:3}, {4:4, 5:5}] def externfn(i): return lst[i] def f(i): counter = 20 res = 0 while counter > 0: myjitdriver.can_enter_jit(counter=counter, i=i) myjitdriver.jit_merge_point(counter=counter, i=i) dct = externfn(i) res = len(dct) counter -= 1 return res res = self.meta_interp(f, [1], policy=StopAtXPolicy(externfn)) assert res == 2 # 'len' becomes a getfield('num_items') for now in lltype, # which is itself encoded as a 'getfield_gc' self.check_resops(call=2, getfield_gc=2)
def test_constfold_pure_oosend(self): myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) class A: @elidable def foo(self): return 42 def fn(n, i): res = 0 obj = A() while i > 0: myjitdriver.can_enter_jit(i=i, obj=obj) myjitdriver.jit_merge_point(i=i, obj=obj) promote(obj) res = obj.foo() i-=1 return res policy = StopAtXPolicy(A.foo.im_func) res = self.meta_interp(fn, [1, 20], policy=policy) assert res == 42 self.check_resops(call=0)
def test_exception_four_cases(self): myjitdriver = JitDriver(greens=[], reds=['n', 'm']) class Error1(Exception): pass class Error2(Exception): pass class Error3(Exception): pass class Error4(Exception): pass def check(n): if n % 4 == 0: raise Error1 if n % 4 == 1: raise Error2 if n % 4 == 2: raise Error3 else: raise Error4 def f(n): m = 1 while n > 0: myjitdriver.can_enter_jit(n=n, m=m) myjitdriver.jit_merge_point(n=n, m=m) try: check(n) except Error1: m = intmask(m * 3 + 1) except Error2: m = intmask(m * 5 + 1) except Error3: m = intmask(m * 7 + 1) except Error4: m = intmask(m * 11 + 1) n -= 1 return m res = self.meta_interp(f, [99], policy=StopAtXPolicy(check)) assert res == f(99)
def test_exception_from_outside(self): myjitdriver = JitDriver(greens=[], reds=['n']) def check(n, mode): if mode == 0 and n > -100: raise MyError(n) return n - 5 def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) try: check(n, 0) except MyError as e: n = check(e.n, 1) return n assert f(53) == -2 res = self.meta_interp(f, [53], policy=StopAtXPolicy(check)) assert res == -2