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_loop_with_two_paths(self): from pypy.rpython.lltypesystem import lltype from pypy.rpython.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_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=1)
def test_external_read_sometimes_dont_compile_guard(self): jitdriver = JitDriver(greens = [], reds = ['frame'], virtualizables = ['frame']) class Frame(object): _virtualizable2_ = ['x', 'y'] class SomewhereElse: pass somewhere_else = SomewhereElse() def g(): somewhere_else.counter += 1 if somewhere_else.counter == 70: result = somewhere_else.top_frame.y # external read debug_print(lltype.Void, '-+-+-+-+- external read:', result) assert result == 79 else: result = 1 return result def f(n): frame = Frame() frame.x = n frame.y = 10 somewhere_else.counter = 0 somewhere_else.top_frame = frame while frame.x > 0: jitdriver.can_enter_jit(frame=frame) jitdriver.jit_merge_point(frame=frame) frame.x -= g() frame.y += 1 return frame.x res = self.meta_interp(f, [123], policy=StopAtXPolicy(g), repeat=7) assert res == f(123)
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_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_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_external_write_sometimes(self): jitdriver = JitDriver(greens = [], reds = ['frame'], virtualizables = ['frame']) class Frame(object): _virtualizable2_ = ['x', 'y'] class SomewhereElse: pass somewhere_else = SomewhereElse() def g(): somewhere_else.counter += 1 if somewhere_else.counter == 70: debug_print(lltype.Void, '-+-+-+-+- external write: 7000') somewhere_else.top_frame.y = 7000 result = 2 else: result = 1 return result def f(n): frame = Frame() frame.x = n frame.y = 10 somewhere_else.counter = 0 somewhere_else.top_frame = frame while frame.x > 0: jitdriver.can_enter_jit(frame=frame) jitdriver.jit_merge_point(frame=frame) frame.x -= g() frame.y += 1 return frame.y res = self.meta_interp(f, [123], policy=StopAtXPolicy(g)) assert res == f(123)
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_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_bridge_forces(self): jitdriver = JitDriver(greens = [], reds = ['frame'], virtualizables = ['frame']) class Frame(object): _virtualizable2_ = ['x', 'y'] class SomewhereElse: pass somewhere_else = SomewhereElse() def g(): n = somewhere_else.top_frame.y + 700 debug_print(lltype.Void, '-+-+-+-+- external write:', n) somewhere_else.top_frame.y = n def f(n): frame = Frame() frame.x = n frame.y = 10 somewhere_else.counter = 0 somewhere_else.top_frame = frame while frame.x > 0: jitdriver.can_enter_jit(frame=frame) jitdriver.jit_merge_point(frame=frame) if frame.y > 17: g() frame.x -= 5 frame.y += 1 return frame.y res = self.meta_interp(f, [123], policy=StopAtXPolicy(g)) assert res == f(123)
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_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_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_external_write(self): jitdriver = JitDriver(greens = [], reds = ['frame'], virtualizables = ['frame']) class Frame(object): _virtualizable2_ = ['x', 'y'] class SomewhereElse: pass somewhere_else = SomewhereElse() def g(): result = somewhere_else.top_frame.y + 1 debug_print(lltype.Void, '-+-+-+-+- external write:', result) somewhere_else.top_frame.y = result # external read/write def f(n): frame = Frame() frame.x = n frame.y = 10 somewhere_else.top_frame = frame while frame.x > 0: jitdriver.can_enter_jit(frame=frame) jitdriver.jit_merge_point(frame=frame) g() frame.x -= frame.y return frame.y res = self.meta_interp(f, [240], policy=StopAtXPolicy(g)) assert res == f(240) self.check_aborted_count(3) self.check_jitcell_token_count(0)
def test_external_pass(self): jitdriver = JitDriver(greens = [], reds = ['n', 'z', 'frame'], virtualizables = ['frame']) class BaseFrame(object): _virtualizable2_ = ['x[*]'] def __init__(self, x): self.x = x class Frame(BaseFrame): pass def g(frame): return frame.x[1] == 1 def f(n): BaseFrame([]) # hack to force 'x' to be in BaseFrame frame = Frame([1,2,3]) z = 0 while n > 0: jitdriver.can_enter_jit(frame=frame, n=n, z=z) jitdriver.jit_merge_point(frame=frame, n=n, z=z) z += g(frame) n -= 1 return z res = self.meta_interp(f, [10], policy=StopAtXPolicy(g)) assert res == f(10)
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_directly_call_assembler_virtualizable_force1(self): class Thing(object): def __init__(self, val): self.val = val class Frame(object): _virtualizable2_ = ['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_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_external_read_sometimes_recursive(self): jitdriver = JitDriver(greens = [], reds = ['rec', 'frame'], virtualizables = ['frame']) class Frame(object): _virtualizable2_ = ['x', 'y'] class SomewhereElse: pass somewhere_else = SomewhereElse() def g(rec): somewhere_else.counter += 1 if somewhere_else.counter == 70: frame = somewhere_else.top_frame result1 = frame.y # external read result2 = frame.back.y # external read debug_print(lltype.Void, '-+-+-+-+- external read:', result1, result2) assert result1 == 13 assert result2 == 1023 result = 2 elif rec: res = f(4, False) assert res == 0 or res == -1 result = 1 else: result = 1 return result def f(n, rec): frame = Frame() frame.x = n frame.y = 10 + 1000 * rec frame.back = somewhere_else.top_frame somewhere_else.top_frame = frame while frame.x > 0: jitdriver.can_enter_jit(frame=frame, rec=rec) jitdriver.jit_merge_point(frame=frame, rec=rec) frame.x -= g(rec) frame.y += 1 somewhere_else.top_frame = frame.back return frame.x def main(n): somewhere_else.counter = 0 somewhere_else.top_frame = None return f(n, True) res = self.meta_interp(main, [123], policy=StopAtXPolicy(g)) assert res == main(123)
def test_external_read_sometimes_changing_virtuals(self): jitdriver = JitDriver(greens = [], reds = ['frame'], virtualizables = ['frame']) class Frame(object): _virtualizable2_ = ['x', 'y'] class Y: pass class SomewhereElse: pass somewhere_else = SomewhereElse() def g(): somewhere_else.counter += 1 if somewhere_else.counter == 70: y = somewhere_else.top_frame.y # external read debug_print(lltype.Void, '-+-+-+-+- external virtual write') assert y.num == 123 y.num += 2 else: y = None return y def f(n): frame = Frame() frame.x = n somewhere_else.counter = 0 somewhere_else.top_frame = frame while frame.x > 0: jitdriver.can_enter_jit(frame=frame) jitdriver.jit_merge_point(frame=frame) frame.y = y = Y() y.num = 123 result = g() if frame.y is not y: return -660 if result: if result is not y: return -661 if y.num != 125: return -662 frame.y = None frame.x -= 1 return frame.x res = self.meta_interp(f, [123], policy=StopAtXPolicy(g)) assert res == f(123)
def test_indirect_call_unknown_object_3(self): myjitdriver = JitDriver(greens=[], reds=['x', 'y', 'z', '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 = z = 0 while y > 0: myjitdriver.can_enter_jit(x=x, y=y, z=z, state=state) myjitdriver.jit_merge_point(x=x, y=y, z=z, state=state) x += z z = 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 four TargetTokens: one for each of the 3 getvalue functions, # and one entering from the interpreter (the preamble) self.check_jitcell_token_count(1) self.check_target_token_count(4)
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_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_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_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_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_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_direct_assembler_call_translates(self): """Test CALL_ASSEMBLER and the recursion limit""" from pypy.rlib.rstackovf import StackOverflow class Thing(object): def __init__(self, val): self.val = val class Frame(object): _virtualizable2_ = ['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): 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 frame.thing.val > 40: change(Thing(13)) nextval = 13 frame.thing = Thing(nextval + 1) i += 1 return frame.thing.val driver2 = JitDriver(greens=[], reds=['n']) def main2(bound): try: while portal2(bound) == -bound + 1: bound *= 2 except StackOverflow: pass return bound def portal2(n): while True: driver2.jit_merge_point(n=n) n -= 1 if n <= 0: return n n = portal2(n) assert portal2(10) == -9 def mainall(codeno, bound): return main(codeno) + main2(bound) res = self.meta_interp(mainall, [0, 1], inline=True, policy=StopAtXPolicy(change)) print hex(res) assert res & 255 == main(0) bound = res & ~255 assert 1024 <= bound <= 131072 assert bound & (bound - 1) == 0 # a power of two