def test_compare_single_char_for_ordering(self): jitdriver = JitDriver(reds=['result', 'n'], greens=[]) _str = self._str constant1 = _str("abcdefghij") def cmpstr(x, y): return x > _str(y) def f(n): cmpstr(_str("abc"), "def") # force x and y to be annot as strings result = 0 while n >= 0: jitdriver.jit_merge_point(n=n, result=result) c = constant1[n] result += cmpstr(c, "c") n -= 1 return result res = self.meta_interp(f, [9]) assert res == f(9) self.check_resops(newstr=0, newunicode=0, call=0)
def test_meta_interpretation(self): """ Verify that meta-interpretation works as expected """ def print_location(a): return "a=%d" % a jitdriver = JitDriver(greens=['a'], reds='auto', get_printable_location=print_location) def test(a, b): while a > b: jitdriver.jit_merge_point(a=a) b += 1 return 42 self.assertEqual( interpretation_mechanisms.interpret_in_python(test, [10, 0]), 42) self.assertEqual( interpretation_mechanisms.meta_interpret(test, [10, 0]), 42)
def test_loop_kept_alive(self): myjitdriver = JitDriver(greens=[], reds=['n']) def g(): n = 10 while n > 0: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) n = n - 1 return 21 def f(): for i in range(15): g() return 42 res = self.meta_interp(f, [], loop_longevity=2) assert res == 42 # we should see only the loop and the entry bridge self.check_target_token_count(2)
def test_constant_virtual2(self): myjitdriver = JitDriver(greens=[], reds=['n', 'sa', 'node']) def f(n): node = self._new() node.value = 1 sa = 0 while n > 0: myjitdriver.can_enter_jit(n=n, sa=sa, node=node) myjitdriver.jit_merge_point(n=n, sa=sa, node=node) sa += node.value if n & 15 > 7: next = self._new() next.value = 2 node = next else: next = self._new() next.value = 3 node = next n -= 1 return sa assert self.meta_interp(f, [31]) == f(31)
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_virtualized1(self): myjitdriver = JitDriver(greens=[], reds=['n', 'node']) 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 node = next n -= 1 return node.value * node.extra assert f(10) == 55 * 10 res = self.meta_interp(f, [10]) assert res == 55 * 10 self.check_trace_count(1) self.check_resops(new_with_vtable=0, setfield_gc=0, getfield_gc_i=2, new=0)
def test_virtualized2(self): myjitdriver = JitDriver(greens=[], reds=['n', 'node1', 'node2']) def f(n): node1 = self._new() node1.value = 0 node2 = self._new() node2.value = 0 while n > 0: myjitdriver.can_enter_jit(n=n, node1=node1, node2=node2) myjitdriver.jit_merge_point(n=n, node1=node1, node2=node2) next1 = self._new() next1.value = node1.value + n + node2.value next2 = self._new() next2.value = next1.value node1 = next1 node2 = next2 n -= 1 return node1.value * node2.value assert f(10) == self.meta_interp(f, [10]) self.check_resops(new_with_vtable=0, setfield_gc=0, getfield_gc_i=2, new=0)
def test_virtual_attribute_pure_function(self): mydriver = JitDriver(reds=['i', 'sa', 'n', 'node'], greens=[]) class A(object): def __init__(self, v1, v2): self.v1 = v1 self.v2 = v2 def f(n): i = sa = 0 node = A(1, 2) while i < n: mydriver.jit_merge_point(i=i, sa=sa, n=n, node=node) sa += node.v1 + node.v2 + 2*node.v1 if i < n/2: node = A(n, 2*n) else: node = A(n, 3*n) i += 1 return sa res = self.meta_interp(f, [16]) assert res == f(16)
def test_raw_malloc_no_virtualstate(self): mydriver = JitDriver(greens=[], reds='auto') def f(n): res = 0 buffer = lltype.malloc(rffi.CCHARP.TO, 1, flavor='raw') buffer[0] = chr(0) while ord(buffer[0]) < n: mydriver.jit_merge_point() i = ord(buffer[0]) lltype.free(buffer, flavor='raw') buffer = lltype.malloc(rffi.CCHARP.TO, 1, flavor='raw') buffer[0] = chr(i+1) res += i lltype.free(buffer, flavor='raw') return res assert f(10) == 45 res = self.meta_interp(f, [10]) assert res == 45 # make sure that the raw buffer is *not* virtualized because we do not # support virtualstate self.check_resops(getarrayitem_raw_i=2, raw_store=2)
def test_stringbuilder_append_empty(self): jitdriver = JitDriver(reds=['n'], greens=[]) def f(n): while n > 0: jitdriver.jit_merge_point(n=n) sb = UnicodeBuilder() sb.append(u"") s = sb.build() if len(s) != 0: raise ValueError n -= 1 return n res = self.meta_interp(f, [10], backendopt=True) assert res == 0 self.check_resops({ 'int_sub': 2, 'int_gt': 2, 'guard_true': 2, 'jump': 1 })
def test_del_keep_obj(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'x']) class Foo: def __del__(self): pass def f(n): x = None while n > 0: myjitdriver.can_enter_jit(x=x, n=n) myjitdriver.jit_merge_point(x=x, n=n) x = Foo() Foo() n -= 1 return 42 self.meta_interp(f, [20]) self.check_resops({'call_r': 4, # calls to a helper function 'guard_no_exception': 4, # follows the calls 'int_sub': 2, 'int_gt': 2, 'guard_true': 2, 'jump': 1})
def test_strslice(self): _str = self._str longstring = _str("foobarbazetc") jitdriver = JitDriver(greens=[], reds=['m', 'n']) @dont_look_inside def escape(x): pass def f(n, m): assert n >= 0 while m >= 0: jitdriver.can_enter_jit(m=m, n=n) jitdriver.jit_merge_point(m=m, n=n) s = longstring[m:n] if m <= 5: escape(s) m -= 1 return 42 self.meta_interp(f, [10, 10])
def test_strconcat_guard_fail(self): _str = self._str jitdriver = JitDriver(greens=[], reds=['m', 'n']) @dont_look_inside def escape(x): pass mylist = [_str("abc") + _str(i) for i in range(12)] def f(n, m): while m >= 0: jitdriver.can_enter_jit(m=m, n=n) jitdriver.jit_merge_point(m=m, n=n) s = mylist[n] + mylist[m] if m & 1: escape(s) m -= 1 return 42 self.meta_interp(f, [6, 10])
def test_eq_folded(self): _str = self._str jitdriver = JitDriver(greens=['s'], reds=['n', 'i']) global_s = _str("hello") def f(n, b, s): if b: s += _str("ello") else: s += _str("allo") i = 0 while n > 0: jitdriver.can_enter_jit(s=s, n=n, i=i) jitdriver.jit_merge_point(s=s, n=n, i=i) n -= 1 + (s == global_s) i += 1 return i res = self.meta_interp(f, [10, True, _str('h')], listops=True) assert res == 5 self.check_resops(**{self.CALL: 0, self.CALL_PURE: 0})
def test_int_lshift_ovf(self): myjitdriver = JitDriver(greens=[], reds=['n', 'x', 'y', 'm']) def f(x, y, n): m = 0 while n < 100: myjitdriver.can_enter_jit(n=n, x=x, y=y, m=m) myjitdriver.jit_merge_point(n=n, x=x, y=y, m=m) y += 1 y &= (LONG_BIT - 1) try: ovfcheck(x << y) except OverflowError: m += 1 n += 1 return m res = self.meta_interp(f, [1, 1, 0], enable_opts='') assert res == f(1, 1, 0) res = self.meta_interp(f, [809644098, 16, 0], enable_opts='') assert res == f(809644098, 16, 0)
def test_two_behaviors(self): myjitdriver = JitDriver(greens=[], reds=['y', 'x']) class Int: def __init__(self, value): self.value = value cases = [True] * 100 + [False, True] * 10 + [False] * 20 def f(y): x = Int(0) while y > 0: myjitdriver.can_enter_jit(x=x, y=y) myjitdriver.jit_merge_point(x=x, y=y) y -= 1 if cases[y]: x = Int(x.value + 1) return x.value res = self.meta_interp(f, [len(cases)]) assert res == 110
def test_path_with_operations_not_from_start(self): jitdriver = JitDriver(greens = ['k'], reds = ['n', 'z']) def f(n): k = 0 z = 0 while n > 0: jitdriver.can_enter_jit(n=n, k=k, z=z) jitdriver.jit_merge_point(n=n, k=k, z=z) k += 1 if k == 30: if z == 0 or z == 1: k = 4 z += 1 else: k = 15 z = 0 n -= 1 return 42 res = self.meta_interp(f, [200])
def test_guard_failure_and_then_exception_in_inlined_function(self): def p(pc, code): code = hlstr(code) return "%s %d %s" % (code, pc, code[pc]) myjitdriver = JitDriver(greens=['pc', 'code'], reds=['n', 'flag'], get_printable_location=p) def f(code, n): pc = 0 flag = False while pc < len(code): myjitdriver.jit_merge_point(n=n, code=code, pc=pc, flag=flag) op = code[pc] if op == "-": n -= 1 elif op == "c": try: n = f("---ir---", n) except Exception: return n elif op == "i": if n < 200: flag = True elif op == "r": if flag: raise Exception elif op == "l": if n > 0: myjitdriver.can_enter_jit(n=n, code=code, pc=0, flag=flag) pc = 0 continue else: assert 0 pc += 1 return n def main(n): return f("c-l", n) print main(1000) res = self.meta_interp(main, [1000], enable_opts='', inline=True) assert res == main(1000)
def test_trace_from_start(self): def p(pc, code): code = hlstr(code) return "'%s' at %d: %s" % (code, pc, code[pc]) myjitdriver = JitDriver(greens=['pc', 'code'], reds=['n'], get_printable_location=p) def f(code, n): pc = 0 while pc < len(code): myjitdriver.jit_merge_point(n=n, code=code, pc=pc) op = code[pc] if op == "+": n += 7 elif op == "-": n -= 1 elif op == "c": n = f('---', n) elif op == "l": if n > 0: myjitdriver.can_enter_jit(n=n, code=code, pc=1) pc = 1 continue else: assert 0 pc += 1 return n def g(m): if m > 1000000: f('', 0) result = 0 for i in range(m): result += f('+-cl--', i) res = self.meta_interp(g, [50], backendopt=True) assert res == g(50) py.test.skip("tracing from start is by now only longer enabled " "if a trace gets too big") self.check_tree_loop_count(3) self.check_history(int_add=1)
def test_handle_jitexception_in_portal(self): # a test for _handle_jitexception_in_portal in blackhole.py driver = JitDriver(greens=['codeno'], reds=['i', 'str'], get_printable_location=lambda codeno: str(codeno)) def do_can_enter_jit(codeno, i, str): i = (i + 1) - 1 # some operations driver.can_enter_jit(codeno=codeno, i=i, str=str) def intermediate(codeno, i, str): if i == 9: do_can_enter_jit(codeno, i, str) def portal(codeno, str): i = value.initial while i < 10: intermediate(codeno, i, str) driver.jit_merge_point(codeno=codeno, i=i, str=str) i += 1 if codeno == 64 and i == 10: str = portal(96, str) str += chr(codeno + i) return str class Value: initial = -1 value = Value() def main(): value.initial = 0 return (portal(64, '') + portal(64, '') + portal(64, '') + portal(64, '') + portal(64, '')) assert main() == 'ABCDEFGHIabcdefghijJ' * 5 for tlimit in [95, 90, 102]: print 'tlimit =', tlimit res = self.meta_interp(main, [], inline=True, trace_limit=tlimit) assert ''.join(res.chars) == 'ABCDEFGHIabcdefghijJ' * 5
def test_max_failure_args_exc(self): FAILARGS_LIMIT = 10 jitdriver = JitDriver(greens=[], reds=['i', 'n', 'o']) class A(object): def __init__(self, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9): self.i0 = i0 self.i1 = i1 self.i2 = i2 self.i3 = i3 self.i4 = i4 self.i5 = i5 self.i6 = i6 self.i7 = i7 self.i8 = i8 self.i9 = i9 def loop(n): i = 0 o = A(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) while i < n: jitdriver.can_enter_jit(o=o, i=i, n=n) jitdriver.jit_merge_point(o=o, i=i, n=n) o = A(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9) i += 1 raise ValueError def main(n): try: loop(n) return 1 except ValueError: return 0 res = self.meta_interp(main, [20], failargs_limit=FAILARGS_LIMIT, listops=True) assert not res self.check_aborted_count(4)
def test_list_change_during_running(self): myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) class Foo: _immutable_fields_ = ['lst?[*]'] def __init__(self, lst): self.lst = lst @dont_look_inside def residual_call(foo, x): if x == 10: lst2 = [0, 0] lst2[1] = foo.lst[1] + 1 foo.lst = lst2 def f(a, x): lst1 = [0, 0] lst1[1] = a foo = Foo(lst1) total = 0 while x > 0: myjitdriver.jit_merge_point(foo=foo, x=x, total=total) # read a quasi-immutable field out of a Constant total += foo.lst[1] residual_call(foo, x) total += foo.lst[1] x -= 1 return total # assert f(100, 30) == 6019 res = self.meta_interp(f, [100, 30]) assert res == 6019 self.check_resops(call_may_force=0, getfield_gc=0, getarrayitem_gc_pure=0, guard_not_forced=0, getarrayitem_gc=0, guard_not_invalidated=8)
def test_on_compile(self): called = [] class MyJitIface(JitHookInterface): def after_compile(self, di): called.append(("compile", di.greenkey[1].getint(), di.greenkey[0].getint(), di.type)) def before_compile(self, di): called.append(("optimize", di.greenkey[1].getint(), di.greenkey[0].getint(), di.type)) #def before_optimize(self, jitdriver, logger, looptoken, oeprations, # type, greenkey): # called.append(("trace", greenkey[1].getint(), # greenkey[0].getint(), type)) iface = MyJitIface() driver = JitDriver(greens=['n', 'm'], reds=['i']) def loop(n, m): i = 0 while i < n + m: driver.can_enter_jit(n=n, m=m, i=i) driver.jit_merge_point(n=n, m=m, i=i) i += 1 self.meta_interp(loop, [1, 4], policy=JitPolicy(iface)) assert called == [ #("trace", 4, 1, "loop"), ("optimize", 4, 1, "loop"), ("compile", 4, 1, "loop") ] self.meta_interp(loop, [2, 4], policy=JitPolicy(iface)) assert called == [ #("trace", 4, 1, "loop"), ("optimize", 4, 1, "loop"), ("compile", 4, 1, "loop"), #("trace", 4, 2, "loop"), ("optimize", 4, 2, "loop"), ("compile", 4, 2, "loop") ]
def test_abort_quasi_immut(self): reasons = [] class MyJitIface(JitHookInterface): def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, ops): assert jitdriver is myjitdriver assert len(greenkey) == 1 reasons.append(reason) assert greenkey_repr == 'blah' assert len(ops) > 1 iface = MyJitIface() myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'], get_printable_location=lambda *args: 'blah') class Foo: _immutable_fields_ = ['a?'] def __init__(self, a): self.a = a def f(a, x): foo = Foo(a) total = 0 while x > 0: myjitdriver.jit_merge_point(foo=foo, x=x, total=total) # read a quasi-immutable field out of a Constant total += foo.a foo.a += 1 x -= 1 return total # assert f(100, 7) == 721 res = self.meta_interp(f, [100, 7], policy=JitPolicy(iface)) assert res == 721 assert reasons == [Counters.ABORT_FORCE_QUASIIMMUT] * 2
def test_oosend_guard_failure_2(self): # same as above, but using prebuilt objects 'w1' and 'w2' myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w']) class Base: pass class W1(Base): def __init__(self, x): self.x = x def incr(self): return W2(self.x + 1) def getvalue(self): return self.x class W2(Base): def __init__(self, y): self.y = y def incr(self): return W1(self.y + 100) def getvalue(self): return self.y w1 = W1(10) w2 = W2(20) def f(x, y): set_param(myjitdriver, 'max_unroll_loops', 5) if x & 1: w = w1 else: w = w2 while y > 0: myjitdriver.can_enter_jit(x=x, y=y, w=w) myjitdriver.jit_merge_point(x=x, y=y, w=w) w = w.incr() y -= 1 return w.getvalue() res = self.meta_interp(f, [3, 28]) assert res == f(3, 28) res = self.meta_interp(f, [4, 28]) assert res == f(4, 28) self.check_trace_count(1) self.check_resops(guard_class=1, int_add=4, int_sub=4)
def test_oosend_guard_failure(self): myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w']) class Base: pass class W1(Base): def __init__(self, x): self.x = x def incr(self): return W2(self.x + 1) def getvalue(self): return self.x class W2(Base): def __init__(self, y): self.y = y def incr(self): return W1(self.y + 100) def getvalue(self): return self.y def f(x, y): set_param(myjitdriver, 'max_unroll_loops', 5) if x & 1: w = W1(x) else: w = W2(x) while y > 0: myjitdriver.can_enter_jit(x=x, y=y, w=w) myjitdriver.jit_merge_point(x=x, y=y, w=w) w = w.incr() y -= 1 return w.getvalue() res = self.meta_interp(f, [3, 28]) assert res == f(3, 28) res = self.meta_interp(f, [4, 28]) assert res == f(4, 28) # This checks that the loop was originally aborted due to an # InvalidLoop condition, and was then unrolled, giving two copies # of the body in a single bigger loop with no failing guard except # the final one. self.check_trace_count(1) self.check_resops(guard_class=1, int_add=4, int_sub=4)
def test_str2unicode(self): _str = self._str jitdriver = JitDriver(greens = [], reds = ['m', 'n']) class Foo: pass @dont_look_inside def escape(x): assert x == _str("6y") def f(n, m): while m >= 0: jitdriver.can_enter_jit(m=m, n=n) jitdriver.jit_merge_point(m=m, n=n) foo = Foo() foo.y = chr(m) foo.y = "y" s = _str(str(n)) + _str(foo.y) escape(s) m -= 1 return 42 self.meta_interp(f, [6, 7]) self.check_resops(unicodesetitem=2, newunicode=2, call=4, copyunicodecontent=2, unicodegetitem=0)
def test_stringbuilder_append_len2_1(self): jitdriver = JitDriver(reds=['n', 'str1'], greens=[]) def f(n): str1 = unicode(str(n)) while n > 0: jitdriver.jit_merge_point(n=n, str1=str1) sb = UnicodeBuilder() sb.append(str1) sb.append(u"ab") s = sb.build() if len(s) != 4: raise ValueError if s[0] != u"1": raise ValueError if s[1] != u"0": raise ValueError if s[2] != u"a": raise ValueError if s[3] != u"b": raise ValueError n -= 1 return n res = self.meta_interp(f, [10], backendopt=True) assert res == 0 self.check_resops(call=6, # (ll_append_res0, ll_append_0_2, ll_build) # * 2 unroll cond_call=0)
def test_string_compare_quasiimmutable(self): class Sys(object): _immutable_fields_ = ["defaultencoding?"] def __init__(self, s): self.defaultencoding = s _str = self._str sys = Sys(_str('ascii')) mydriver = JitDriver(reds = ['n', 'sa'], greens = []) def f(n): sa = 0 sys.defaultencoding = _str('ascii') while n: mydriver.jit_merge_point(n=n, sa=sa) if sys.defaultencoding == _str('ascii'): sa += 1 n -= 1 sys.defaultencoding = _str('utf-8') return sa assert self.meta_interp(f, [8]) == f(8) self.check_resops({'jump': 1, 'int_is_true': 2, 'int_add': 2, 'guard_true': 2, 'guard_not_invalidated': 2, 'int_sub': 2})
def test_strconcat_escape_str_char_str(self): _str, _chr = self._str, self._chr jitdriver = JitDriver(greens = [], reds = ['m', 'n']) @dont_look_inside def escape(x): pass mylist = [_str("somestr") + _str(i) for i in range(10)] def f(n, m): while m >= 0: jitdriver.can_enter_jit(m=m, n=n) jitdriver.jit_merge_point(m=m, n=n) s = mylist[n] + _chr(n) + mylist[m] escape(s) m -= 1 return 42 self.meta_interp(f, [6, 7]) if _str is str: self.check_resops(call_pure=0, copystrcontent=4, strsetitem=2, call=2, newstr=2) else: self.check_resops(call_pure=0, unicodesetitem=2, call=2, copyunicodecontent=4, newunicode=2)