PageRenderTime 125ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/jit/metainterp/test/test_virtualizable.py

https://bitbucket.org/pypy/pypy/
Python | 1793 lines | 1736 code | 42 blank | 15 comment | 25 complexity | 0fe3cb22733fb4d4a9f4abf191addd72 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. from rpython.jit.codewriter import heaptracker
  3. from rpython.jit.codewriter.policy import StopAtXPolicy
  4. from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
  5. from rpython.jit.metainterp.test.support import LLJitMixin
  6. from rpython.jit.metainterp.warmspot import get_translator, get_stats
  7. from rpython.jit.metainterp.resoperation import rop
  8. from rpython.rlib.jit import JitDriver, hint, dont_look_inside, promote, virtual_ref
  9. from rpython.rlib.rarithmetic import intmask
  10. from rpython.rtyper.annlowlevel import hlstr
  11. from rpython.rtyper.llannotation import lltype_to_annotation
  12. from rpython.rtyper.extregistry import ExtRegistryEntry
  13. from rpython.rtyper.lltypesystem import lltype, lloperation, llmemory
  14. from rpython.rtyper import rclass
  15. from rpython.rtyper.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY, FieldListAccessor
  16. def promote_virtualizable(*args):
  17. pass
  18. class Entry(ExtRegistryEntry):
  19. "Annotation and rtyping of LLOp instances, which are callable."
  20. _about_ = promote_virtualizable
  21. def compute_result_annotation(self, *args):
  22. return lltype_to_annotation(lltype.Void)
  23. def specialize_call(self, hop):
  24. args_v = [hop.inputarg(hop.args_r[0], 0),
  25. hop.inputconst(lltype.Void, hop.args_v[1].value),
  26. hop.inputconst(lltype.Void, {})]
  27. hop.exception_cannot_occur()
  28. return hop.genop('jit_force_virtualizable',
  29. args_v, resulttype=lltype.Void)
  30. debug_print = lloperation.llop.debug_print
  31. # ____________________________________________________________
  32. class ExplicitVirtualizableTests:
  33. XY = lltype.GcStruct(
  34. 'XY',
  35. ('parent', rclass.OBJECT),
  36. ('vable_token', llmemory.GCREF),
  37. ('inst_x', lltype.Signed),
  38. ('inst_node', lltype.Ptr(LLtypeMixin.NODE)),
  39. hints = {'virtualizable_accessor': FieldListAccessor()})
  40. XY._hints['virtualizable_accessor'].initialize(
  41. XY, {'inst_x': IR_IMMUTABLE, 'inst_node': IR_IMMUTABLE})
  42. xy_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  43. heaptracker.set_testing_vtable_for_gcstruct(XY, xy_vtable, 'XY')
  44. def _freeze_(self):
  45. return True
  46. def setup(self):
  47. xy = lltype.malloc(self.XY)
  48. xy.vable_token = lltype.nullptr(llmemory.GCREF.TO)
  49. xy.parent.typeptr = self.xy_vtable
  50. return xy
  51. def test_preexisting_access(self):
  52. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
  53. virtualizables = ['xy'])
  54. def f(n):
  55. xy = self.setup()
  56. xy.inst_x = 10
  57. while n > 0:
  58. myjitdriver.can_enter_jit(xy=xy, n=n)
  59. myjitdriver.jit_merge_point(xy=xy, n=n)
  60. promote_virtualizable(xy, 'inst_x')
  61. x = xy.inst_x
  62. xy.inst_x = x + 1
  63. n -= 1
  64. promote_virtualizable(xy, 'inst_x')
  65. return xy.inst_x
  66. res = self.meta_interp(f, [20])
  67. assert res == 30
  68. self.check_simple_loop(setfield_gc=0, getfield_gc_i=0)
  69. def test_preexisting_access_2(self):
  70. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
  71. virtualizables = ['xy'])
  72. def f(n):
  73. xy = self.setup()
  74. xy.inst_x = 100
  75. while n > -8:
  76. myjitdriver.can_enter_jit(xy=xy, n=n)
  77. myjitdriver.jit_merge_point(xy=xy, n=n)
  78. if n > 0:
  79. promote_virtualizable(xy, 'inst_x')
  80. x = xy.inst_x
  81. xy.inst_x = x + 1
  82. else:
  83. promote_virtualizable(xy, 'inst_x')
  84. x = xy.inst_x
  85. xy.inst_x = x + 10
  86. n -= 1
  87. promote_virtualizable(xy, 'inst_x')
  88. return xy.inst_x
  89. assert f(5) == 185
  90. res = self.meta_interp(f, [5])
  91. assert res == 185
  92. self.check_resops(setfield_gc=0, getfield_gc_r=1,
  93. getfield_gc_i=1) # <= at the header of the loop
  94. def test_two_paths_access(self):
  95. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
  96. virtualizables = ['xy'])
  97. def f(n):
  98. xy = self.setup()
  99. xy.inst_x = 100
  100. while n > 0:
  101. myjitdriver.can_enter_jit(xy=xy, n=n)
  102. myjitdriver.jit_merge_point(xy=xy, n=n)
  103. promote_virtualizable(xy, 'inst_x')
  104. x = xy.inst_x
  105. if n <= 10:
  106. x += 1000
  107. promote_virtualizable(xy, 'inst_x')
  108. xy.inst_x = x + 1
  109. n -= 1
  110. promote_virtualizable(xy, 'inst_x')
  111. return xy.inst_x
  112. res = self.meta_interp(f, [18])
  113. assert res == 10118
  114. self.check_resops(setfield_gc=0, getfield_gc_i=1, getfield_gc_r=1)
  115. def test_synchronize_in_return(self):
  116. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
  117. virtualizables = ['xy'])
  118. def g(xy, n):
  119. while n > 0:
  120. myjitdriver.can_enter_jit(xy=xy, n=n)
  121. myjitdriver.jit_merge_point(xy=xy, n=n)
  122. promote_virtualizable(xy, 'inst_x')
  123. xy.inst_x += 1
  124. n -= 1
  125. def f(n):
  126. xy = self.setup()
  127. promote_virtualizable(xy, 'inst_x')
  128. xy.inst_x = 10000
  129. m = 10
  130. while m > 0:
  131. g(xy, n)
  132. m -= 1
  133. promote_virtualizable(xy, 'inst_x')
  134. return xy.inst_x
  135. res = self.meta_interp(f, [18])
  136. assert res == 10180
  137. self.check_resops(setfield_gc=0, getfield_gc_i=1, getfield_gc_r=1)
  138. def test_synchronize_in_return_2(self):
  139. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
  140. virtualizables = ['xy'])
  141. class Foo(object):
  142. pass
  143. def g(xy, n):
  144. myjitdriver.jit_merge_point(xy=xy, n=n)
  145. promote_virtualizable(xy, 'inst_x')
  146. xy.inst_x += 1
  147. return Foo()
  148. def f(n):
  149. xy = self.setup()
  150. promote_virtualizable(xy, 'inst_x')
  151. xy.inst_x = 10000
  152. m = 10
  153. foo = None
  154. while m > 0:
  155. foo = g(xy, n)
  156. m -= 1
  157. assert foo is not None
  158. promote_virtualizable(xy, 'inst_x')
  159. return xy.inst_x
  160. res = self.meta_interp(f, [18])
  161. assert res == 10010
  162. self.check_resops(omit_finish=False,
  163. guard_not_forced_2=1, finish=1)
  164. def test_virtualizable_and_greens(self):
  165. myjitdriver = JitDriver(greens = ['m'], reds = ['n', 'xy'],
  166. virtualizables = ['xy'])
  167. def g(n):
  168. xy = self.setup()
  169. xy.inst_x = 10
  170. m = 0
  171. while n > 0:
  172. myjitdriver.can_enter_jit(xy=xy, n=n, m=m)
  173. myjitdriver.jit_merge_point(xy=xy, n=n, m=m)
  174. promote_virtualizable(xy, 'inst_x')
  175. x = xy.inst_x
  176. xy.inst_x = x + 1
  177. m = (m+1) & 3 # the loop gets unrolled 4 times
  178. n -= 1
  179. promote_virtualizable(xy, 'inst_x')
  180. return xy.inst_x
  181. def f(n):
  182. res = 0
  183. k = 4
  184. while k > 0:
  185. res += g(n)
  186. k -= 1
  187. return res
  188. res = self.meta_interp(f, [40])
  189. assert res == 50 * 4
  190. self.check_resops(setfield_gc=0, getfield_gc_i=2, getfield_gc_r=2)
  191. def test_double_frame(self):
  192. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy', 'other'],
  193. virtualizables = ['xy'])
  194. def f(n):
  195. xy = self.setup()
  196. xy.inst_x = 10
  197. other = self.setup()
  198. other.inst_x = 15
  199. while n > 0:
  200. myjitdriver.can_enter_jit(xy=xy, n=n, other=other)
  201. myjitdriver.jit_merge_point(xy=xy, n=n, other=other)
  202. promote_virtualizable(other, 'inst_x')
  203. value = other.inst_x # getfield_gc
  204. other.inst_x = value + 1 # setfield_gc
  205. promote_virtualizable(xy, 'inst_x')
  206. xy.inst_x = value + 100 # virtualized away
  207. n -= 1
  208. promote_virtualizable(xy, 'inst_x')
  209. return xy.inst_x
  210. res = self.meta_interp(f, [20])
  211. assert res == 134
  212. self.check_simple_loop(setfield_gc=1, getfield_gc_i=0, cond_call=1,
  213. getfield_gc_r=0)
  214. self.check_resops(setfield_gc=2, getfield_gc_i=2, getfield_gc_r=2)
  215. # ------------------------------
  216. XY2 = lltype.GcStruct(
  217. 'XY2',
  218. ('parent', rclass.OBJECT),
  219. ('vable_token', llmemory.GCREF),
  220. ('inst_x', lltype.Signed),
  221. ('inst_l1', lltype.Ptr(lltype.GcArray(lltype.Signed))),
  222. ('inst_l2', lltype.Ptr(lltype.GcArray(lltype.Signed))),
  223. hints = {'virtualizable_accessor': FieldListAccessor()})
  224. XY2._hints['virtualizable_accessor'].initialize(
  225. XY2, {'inst_x': IR_IMMUTABLE,
  226. 'inst_l1': IR_IMMUTABLE_ARRAY, 'inst_l2': IR_IMMUTABLE_ARRAY})
  227. xy2_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  228. heaptracker.set_testing_vtable_for_gcstruct(XY2, xy2_vtable, 'XY2')
  229. def setup2(self):
  230. xy2 = lltype.malloc(self.XY2)
  231. xy2.vable_token = lltype.nullptr(llmemory.GCREF.TO)
  232. xy2.parent.typeptr = self.xy2_vtable
  233. return xy2
  234. def test_access_list_fields(self):
  235. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
  236. virtualizables = ['xy2'])
  237. ARRAY = lltype.GcArray(lltype.Signed)
  238. def f(n):
  239. xy2 = self.setup2()
  240. xy2.inst_x = 100
  241. xy2.inst_l1 = lltype.malloc(ARRAY, 3)
  242. xy2.inst_l1[0] = -9999999
  243. xy2.inst_l1[1] = -9999999
  244. xy2.inst_l1[2] = 3001
  245. xy2.inst_l2 = lltype.malloc(ARRAY, 2)
  246. xy2.inst_l2[0] = 80
  247. xy2.inst_l2[1] = -9999999
  248. while n > 0:
  249. myjitdriver.can_enter_jit(xy2=xy2, n=n)
  250. myjitdriver.jit_merge_point(xy2=xy2, n=n)
  251. promote_virtualizable(xy2, 'inst_l1')
  252. promote_virtualizable(xy2, 'inst_l2')
  253. xy2.inst_l1[2] += xy2.inst_l2[0]
  254. n -= 1
  255. promote_virtualizable(xy2, 'inst_l1')
  256. return xy2.inst_l1[2]
  257. res = self.meta_interp(f, [16])
  258. assert res == 3001 + 16 * 80
  259. self.check_simple_loop(setarrayitem_gc=0, setfield_gc=0,
  260. getarrayitem_gc_i=0, getarrayitem_gc_r=0, getfield_gc_i=0,
  261. getfield_gc_r=0)
  262. def test_synchronize_arrays_in_return(self):
  263. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
  264. virtualizables = ['xy2'])
  265. ARRAY = lltype.GcArray(lltype.Signed)
  266. def g(xy2, n):
  267. while n > 0:
  268. myjitdriver.can_enter_jit(xy2=xy2, n=n)
  269. myjitdriver.jit_merge_point(xy2=xy2, n=n)
  270. promote_virtualizable(xy2, 'inst_x')
  271. promote_virtualizable(xy2, 'inst_l2')
  272. xy2.inst_l2[0] += xy2.inst_x
  273. n -= 1
  274. def f(n):
  275. xy2 = self.setup2()
  276. xy2.inst_x = 2
  277. xy2.inst_l1 = lltype.malloc(ARRAY, 2)
  278. xy2.inst_l1[0] = 1941309
  279. xy2.inst_l1[1] = 2941309
  280. xy2.inst_l2 = lltype.malloc(ARRAY, 1)
  281. xy2.inst_l2[0] = 10000
  282. m = 10
  283. while m > 0:
  284. g(xy2, n)
  285. m -= 1
  286. promote_virtualizable(xy2, 'inst_l2')
  287. return xy2.inst_l2[0]
  288. assert f(18) == 10360
  289. res = self.meta_interp(f, [18])
  290. assert res == 10360
  291. self.check_simple_loop(setfield_gc=0, getarrayitem_gc_i=0,
  292. getfield_gc_i=0, getfield_gc_r=0,
  293. setarrayitem_gc=0, getarrayitem_gc_r=0)
  294. def test_array_length(self):
  295. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
  296. virtualizables = ['xy2'])
  297. ARRAY = lltype.GcArray(lltype.Signed)
  298. def g(xy2, n):
  299. while n > 0:
  300. myjitdriver.can_enter_jit(xy2=xy2, n=n)
  301. myjitdriver.jit_merge_point(xy2=xy2, n=n)
  302. promote_virtualizable(xy2, 'inst_l1')
  303. promote_virtualizable(xy2, 'inst_l2')
  304. xy2.inst_l1[1] += len(xy2.inst_l2)
  305. n -= 1
  306. def f(n):
  307. xy2 = self.setup2()
  308. xy2.inst_x = 2
  309. xy2.inst_l1 = lltype.malloc(ARRAY, 2)
  310. xy2.inst_l1[0] = 1941309
  311. xy2.inst_l1[1] = 2941309
  312. xy2.inst_l2 = lltype.malloc(ARRAY, 1)
  313. xy2.inst_l2[0] = 10000
  314. g(xy2, n)
  315. return xy2.inst_l1[1]
  316. res = self.meta_interp(f, [18])
  317. assert res == 2941309 + 18
  318. self.check_simple_loop(setfield_gc=0, getarrayitem_gc_i=0,
  319. getarrayitem_gc_r=0, getfield_gc_i=0,
  320. arraylen_gc=0, getfield_gc_r=0)
  321. def test_residual_function(self):
  322. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
  323. virtualizables = ['xy2'])
  324. ARRAY = lltype.GcArray(lltype.Signed)
  325. #
  326. @dont_look_inside
  327. def h(xy2):
  328. # this function is marked for residual calls because
  329. # it does something with a virtualizable's array that is not
  330. # just accessing an item
  331. return xy2.inst_l2
  332. #
  333. def g(xy2, n):
  334. while n > 0:
  335. myjitdriver.can_enter_jit(xy2=xy2, n=n)
  336. myjitdriver.jit_merge_point(xy2=xy2, n=n)
  337. promote_virtualizable(xy2, 'inst_l1')
  338. xy2.inst_l1[1] = xy2.inst_l1[1] + len(h(xy2))
  339. n -= 1
  340. def f(n):
  341. xy2 = self.setup2()
  342. xy2.inst_x = 2
  343. xy2.inst_l1 = lltype.malloc(ARRAY, 2)
  344. xy2.inst_l1[0] = 1941309
  345. xy2.inst_l1[1] = 2941309
  346. xy2.inst_l2 = lltype.malloc(ARRAY, 1)
  347. xy2.inst_l2[0] = 10000
  348. g(xy2, n)
  349. return xy2.inst_l1[1]
  350. res = self.meta_interp(f, [18])
  351. assert res == 2941309 + 18
  352. self.check_simple_loop(call_r=1, setfield_gc=0, getarrayitem_gc_i=0,
  353. getarrayitem_gc_r=0, arraylen_gc=1, getfield_gc_i=0,
  354. getfield_gc_r=0)
  355. def test_double_frame_array(self):
  356. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2', 'other'],
  357. virtualizables = ['xy2'])
  358. ARRAY = lltype.GcArray(lltype.Signed)
  359. def f(n):
  360. xy2 = self.setup2()
  361. xy2.inst_x = 10
  362. xy2.inst_l1 = lltype.malloc(ARRAY, 1)
  363. xy2.inst_l1[0] = 1982731
  364. xy2.inst_l2 = lltype.malloc(ARRAY, 1)
  365. xy2.inst_l2[0] = 10000
  366. other = self.setup2()
  367. other.inst_x = 15
  368. other.inst_l1 = lltype.malloc(ARRAY, 2)
  369. other.inst_l1[0] = 189182
  370. other.inst_l1[1] = 58421
  371. other.inst_l2 = lltype.malloc(ARRAY, 2)
  372. other.inst_l2[0] = 181
  373. other.inst_l2[1] = 189
  374. while n > 0:
  375. myjitdriver.can_enter_jit(xy2=xy2, n=n, other=other)
  376. myjitdriver.jit_merge_point(xy2=xy2, n=n, other=other)
  377. promote_virtualizable(other, 'inst_l2')
  378. length = len(other.inst_l2) # getfield_gc/arraylen_gc
  379. value = other.inst_l2[0] # getfield_gc/getarrayitem_gc
  380. other.inst_l2[0] = value + length # getfield_gc/setarrayitem_gc
  381. promote_virtualizable(xy2, 'inst_l2')
  382. xy2.inst_l2[0] = value + 100 # virtualized away
  383. n -= 1
  384. promote_virtualizable(xy2, 'inst_l2')
  385. return xy2.inst_l2[0]
  386. expected = f(20)
  387. res = self.meta_interp(f, [20], enable_opts='')
  388. assert res == expected
  389. self.check_simple_loop(setarrayitem_gc=1, setfield_gc=0,
  390. getarrayitem_gc_i=1, arraylen_gc=1,
  391. getfield_gc_r=2)
  392. # ------------------------------
  393. XY2SUB = lltype.GcStruct(
  394. 'XY2SUB',
  395. ('parent', XY2))
  396. xy2sub_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  397. heaptracker.set_testing_vtable_for_gcstruct(XY2SUB, xy2sub_vtable,
  398. 'XY2SUB')
  399. def setup2sub(self):
  400. xy2 = lltype.malloc(self.XY2SUB)
  401. xy2.parent.vable_token = lltype.nullptr(llmemory.GCREF.TO)
  402. xy2.parent.parent.typeptr = self.xy2_vtable
  403. return xy2
  404. def test_subclass(self):
  405. myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
  406. virtualizables = ['xy2'])
  407. ARRAY = lltype.GcArray(lltype.Signed)
  408. def g(xy2, n):
  409. while n > 0:
  410. myjitdriver.can_enter_jit(xy2=xy2, n=n)
  411. myjitdriver.jit_merge_point(xy2=xy2, n=n)
  412. parent = xy2.parent
  413. promote_virtualizable(parent, 'inst_x')
  414. promote_virtualizable(parent, 'inst_l2')
  415. parent.inst_l2[0] += parent.inst_x
  416. n -= 1
  417. def f(n):
  418. xy2 = self.setup2sub()
  419. xy2.parent.inst_x = 2
  420. xy2.parent.inst_l1 = lltype.malloc(ARRAY, 2)
  421. xy2.parent.inst_l1[0] = 1941309
  422. xy2.parent.inst_l1[1] = 2941309
  423. xy2.parent.inst_l2 = lltype.malloc(ARRAY, 1)
  424. xy2.parent.inst_l2[0] = 10000
  425. m = 10
  426. while m > 0:
  427. g(xy2, n)
  428. m -= 1
  429. parent = xy2.parent
  430. promote_virtualizable(parent, 'inst_l2')
  431. return parent.inst_l2[0]
  432. assert f(18) == 10360
  433. res = self.meta_interp(f, [18])
  434. assert res == 10360
  435. self.check_simple_loop(getfield_gc_i=0, getfield_gc_r=0,
  436. getarrayitem_gc_i=0, getarrayitem_gc_r=0,
  437. setfield_gc=0, setarrayitem_gc=0)
  438. # ------------------------------
  439. class ImplicitVirtualizableTests(object):
  440. def test_simple_implicit(self):
  441. myjitdriver = JitDriver(greens = [], reds = ['frame'],
  442. virtualizables = ['frame'])
  443. class Frame(object):
  444. _virtualizable_ = ['x', 'y']
  445. def __init__(self, x, y):
  446. self.x = x
  447. self.y = y
  448. class SomewhereElse:
  449. pass
  450. somewhere_else = SomewhereElse()
  451. def f(n):
  452. frame = Frame(n, 0)
  453. somewhere_else.top_frame = frame # escapes
  454. while frame.x > 0:
  455. myjitdriver.can_enter_jit(frame=frame)
  456. myjitdriver.jit_merge_point(frame=frame)
  457. frame.y += frame.x
  458. frame.x -= 1
  459. return somewhere_else.top_frame.y
  460. res = self.meta_interp(f, [10])
  461. assert res == 55
  462. self.check_simple_loop(setfield_gc=0, getfield_gc_i=0,
  463. getfield_gc_r=0)
  464. def test_virtualizable_with_array(self):
  465. myjitdriver = JitDriver(greens = [], reds = ['n', 'x', 'frame'],
  466. virtualizables = ['frame'])
  467. class Frame(object):
  468. _virtualizable_ = ['l[*]', 's']
  469. def __init__(self, l, s):
  470. self.l = l
  471. self.s = s
  472. def f(n, a):
  473. frame = Frame([a, a+1, a+2, a+3], 0)
  474. x = 0
  475. while n > 0:
  476. myjitdriver.can_enter_jit(frame=frame, n=n, x=x)
  477. myjitdriver.jit_merge_point(frame=frame, n=n, x=x)
  478. frame.s = promote(frame.s)
  479. n -= 1
  480. s = frame.s
  481. assert s >= 0
  482. x += frame.l[s]
  483. frame.s += 1
  484. s = frame.s
  485. assert s >= 0
  486. x += frame.l[s]
  487. x += len(frame.l)
  488. frame.s -= 1
  489. return x
  490. res = self.meta_interp(f, [10, 1], listops=True)
  491. assert res == f(10, 1)
  492. self.check_simple_loop(getfield_gc_i=0, getarrayitem_gc_i=0,
  493. getarrayitem_gc_r=0, getfield_gc_r=0)
  494. self.check_resops(getfield_gc_r=1, getarrayitem_gc_i=4,
  495. getfield_gc_i=1)
  496. def test_subclass_of_virtualizable(self):
  497. myjitdriver = JitDriver(greens = [], reds = ['frame'],
  498. virtualizables = ['frame'])
  499. class Frame(object):
  500. _virtualizable_ = ['x', 'y']
  501. def __init__(self, x, y):
  502. self.x = x
  503. self.y = y
  504. class SubFrame(Frame):
  505. pass
  506. def f(n):
  507. Frame(0, 0) # hack: make sure x and y are attached to Frame
  508. frame = SubFrame(n, 0)
  509. while frame.x > 0:
  510. myjitdriver.can_enter_jit(frame=frame)
  511. myjitdriver.jit_merge_point(frame=frame)
  512. frame.y += frame.x
  513. frame.x -= 1
  514. return frame.y
  515. res = self.meta_interp(f, [10])
  516. assert res == 55
  517. self.check_simple_loop(setfield_gc=0, getfield_gc_i=0,
  518. getfield_gc_r=0)
  519. def test_external_pass(self):
  520. jitdriver = JitDriver(greens = [], reds = ['n', 'z', 'frame'],
  521. virtualizables = ['frame'])
  522. class BaseFrame(object):
  523. _virtualizable_ = ['x[*]']
  524. def __init__(self, x):
  525. self.x = x
  526. class Frame(BaseFrame):
  527. pass
  528. def g(frame):
  529. return frame.x[1] == 1
  530. def f(n):
  531. BaseFrame([]) # hack to force 'x' to be in BaseFrame
  532. frame = Frame([1, 2, 3])
  533. z = 0
  534. while n > 0:
  535. jitdriver.can_enter_jit(frame=frame, n=n, z=z)
  536. jitdriver.jit_merge_point(frame=frame, n=n, z=z)
  537. z += g(frame)
  538. n -= 1
  539. return z
  540. res = self.meta_interp(f, [10], policy=StopAtXPolicy(g))
  541. assert res == f(10)
  542. def test_external_read(self):
  543. jitdriver = JitDriver(greens = [], reds = ['frame'],
  544. virtualizables = ['frame'])
  545. class Frame(object):
  546. _virtualizable_ = ['x', 'y']
  547. class SomewhereElse:
  548. pass
  549. somewhere_else = SomewhereElse()
  550. def g():
  551. result = somewhere_else.top_frame.y # external read
  552. debug_print(lltype.Void, '-+-+-+-+- external read:', result)
  553. return result
  554. def f(n):
  555. frame = Frame()
  556. frame.x = n
  557. frame.y = 10
  558. somewhere_else.top_frame = frame
  559. while frame.x > 0:
  560. jitdriver.can_enter_jit(frame=frame)
  561. jitdriver.jit_merge_point(frame=frame)
  562. frame.x -= g()
  563. frame.y += 1
  564. return frame.x
  565. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
  566. assert res == f(123)
  567. self.check_aborted_count(2)
  568. self.check_jitcell_token_count(0)
  569. def test_external_read_with_exception(self):
  570. jitdriver = JitDriver(greens = [], reds = ['frame'],
  571. virtualizables = ['frame'])
  572. class Frame(object):
  573. _virtualizable_ = ['x', 'y']
  574. class SomewhereElse:
  575. pass
  576. somewhere_else = SomewhereElse()
  577. class FooError(Exception):
  578. def __init__(self, value):
  579. self.value = value
  580. def g():
  581. result = somewhere_else.top_frame.y # external read
  582. debug_print(lltype.Void, '-+-+-+-+- external read:', result)
  583. raise FooError(result)
  584. def f(n):
  585. frame = Frame()
  586. frame.x = n
  587. frame.y = 10
  588. somewhere_else.top_frame = frame
  589. while frame.x > 0:
  590. jitdriver.can_enter_jit(frame=frame)
  591. jitdriver.jit_merge_point(frame=frame)
  592. try:
  593. g()
  594. except FooError as e:
  595. frame.x -= e.value
  596. frame.y += 1
  597. return frame.x
  598. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
  599. assert res == f(123)
  600. self.check_aborted_count(2)
  601. self.check_jitcell_token_count(0)
  602. def test_external_write(self):
  603. jitdriver = JitDriver(greens = [], reds = ['frame'],
  604. virtualizables = ['frame'])
  605. class Frame(object):
  606. _virtualizable_ = ['x', 'y']
  607. class SomewhereElse:
  608. pass
  609. somewhere_else = SomewhereElse()
  610. def g():
  611. result = somewhere_else.top_frame.y + 1
  612. debug_print(lltype.Void, '-+-+-+-+- external write:', result)
  613. somewhere_else.top_frame.y = result # external read/write
  614. def f(n):
  615. frame = Frame()
  616. frame.x = n
  617. frame.y = 10
  618. somewhere_else.top_frame = frame
  619. while frame.x > 0:
  620. jitdriver.can_enter_jit(frame=frame)
  621. jitdriver.jit_merge_point(frame=frame)
  622. g()
  623. frame.x -= frame.y
  624. return frame.y
  625. res = self.meta_interp(f, [240], policy=StopAtXPolicy(g))
  626. assert res == f(240)
  627. self.check_aborted_count(3)
  628. self.check_jitcell_token_count(0)
  629. def test_external_read_sometimes(self):
  630. jitdriver = JitDriver(greens = [], reds = ['frame'],
  631. virtualizables = ['frame'])
  632. class Frame(object):
  633. _virtualizable_ = ['x', 'y']
  634. class SomewhereElse:
  635. pass
  636. somewhere_else = SomewhereElse()
  637. def g():
  638. somewhere_else.counter += 1
  639. if somewhere_else.counter == 70:
  640. result = somewhere_else.top_frame.y # external read
  641. debug_print(lltype.Void, '-+-+-+-+- external read:', result)
  642. assert result == 79
  643. else:
  644. result = 1
  645. return result
  646. def f(n):
  647. frame = Frame()
  648. frame.x = n
  649. frame.y = 10
  650. somewhere_else.counter = 0
  651. somewhere_else.top_frame = frame
  652. while frame.x > 0:
  653. jitdriver.can_enter_jit(frame=frame)
  654. jitdriver.jit_merge_point(frame=frame)
  655. frame.x -= g()
  656. frame.y += 1
  657. return frame.x
  658. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
  659. assert res == f(123)
  660. def test_external_read_sometimes_with_virtuals(self):
  661. jitdriver = JitDriver(greens = [], reds = ['frame'],
  662. virtualizables = ['frame'])
  663. class Frame(object):
  664. _virtualizable_ = ['x', 'y']
  665. class Y:
  666. pass
  667. class SomewhereElse:
  668. pass
  669. somewhere_else = SomewhereElse()
  670. def g():
  671. somewhere_else.counter += 1
  672. if somewhere_else.counter == 70:
  673. y = somewhere_else.top_frame.y # external read
  674. debug_print(lltype.Void, '-+-+-+-+- external read')
  675. else:
  676. y = None
  677. return y
  678. def f(n):
  679. frame = Frame()
  680. frame.x = n
  681. somewhere_else.counter = 0
  682. somewhere_else.top_frame = frame
  683. while frame.x > 0:
  684. jitdriver.can_enter_jit(frame=frame)
  685. jitdriver.jit_merge_point(frame=frame)
  686. frame.y = y = Y()
  687. result = g()
  688. if frame.y is not y:
  689. return -660
  690. if result:
  691. if result is not y:
  692. return -661
  693. frame.y = None
  694. frame.x -= 1
  695. return frame.x
  696. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
  697. assert res == f(123)
  698. def test_external_read_sometimes_changing_virtuals(self):
  699. jitdriver = JitDriver(greens = [], reds = ['frame'],
  700. virtualizables = ['frame'])
  701. class Frame(object):
  702. _virtualizable_ = ['x', 'y']
  703. class Y:
  704. pass
  705. class SomewhereElse:
  706. pass
  707. somewhere_else = SomewhereElse()
  708. def g():
  709. somewhere_else.counter += 1
  710. if somewhere_else.counter == 70:
  711. y = somewhere_else.top_frame.y # external read
  712. debug_print(lltype.Void, '-+-+-+-+- external virtual write')
  713. assert y.num == 123
  714. y.num += 2
  715. else:
  716. y = None
  717. return y
  718. def f(n):
  719. frame = Frame()
  720. frame.x = n
  721. somewhere_else.counter = 0
  722. somewhere_else.top_frame = frame
  723. while frame.x > 0:
  724. jitdriver.can_enter_jit(frame=frame)
  725. jitdriver.jit_merge_point(frame=frame)
  726. frame.y = y = Y()
  727. y.num = 123
  728. result = g()
  729. if frame.y is not y:
  730. return -660
  731. if result:
  732. if result is not y:
  733. return -661
  734. if y.num != 125:
  735. return -662
  736. frame.y = None
  737. frame.x -= 1
  738. return frame.x
  739. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
  740. assert res == f(123)
  741. def test_external_read_sometimes_with_exception(self):
  742. jitdriver = JitDriver(greens = [], reds = ['frame'],
  743. virtualizables = ['frame'])
  744. class Frame(object):
  745. _virtualizable_ = ['x', 'y']
  746. class FooBarError(Exception):
  747. pass
  748. class SomewhereElse:
  749. pass
  750. somewhere_else = SomewhereElse()
  751. def g():
  752. somewhere_else.counter += 1
  753. if somewhere_else.counter == 70:
  754. result = somewhere_else.top_frame.y # external read
  755. debug_print(lltype.Void, '-+-+-+-+- external read:', result)
  756. assert result == 79
  757. raise FooBarError
  758. else:
  759. result = 1
  760. return result
  761. def f(n):
  762. frame = Frame()
  763. frame.x = n
  764. frame.y = 10
  765. somewhere_else.counter = 0
  766. somewhere_else.top_frame = frame
  767. try:
  768. while frame.x > 0:
  769. jitdriver.can_enter_jit(frame=frame)
  770. jitdriver.jit_merge_point(frame=frame)
  771. frame.x -= g()
  772. frame.y += 1
  773. except FooBarError:
  774. pass
  775. return frame.x
  776. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
  777. assert res == f(123)
  778. def test_external_read_sometimes_dont_compile_guard(self):
  779. jitdriver = JitDriver(greens = [], reds = ['frame'],
  780. virtualizables = ['frame'])
  781. class Frame(object):
  782. _virtualizable_ = ['x', 'y']
  783. class SomewhereElse:
  784. pass
  785. somewhere_else = SomewhereElse()
  786. def g():
  787. somewhere_else.counter += 1
  788. if somewhere_else.counter == 70:
  789. result = somewhere_else.top_frame.y # external read
  790. debug_print(lltype.Void, '-+-+-+-+- external read:', result)
  791. assert result == 79
  792. else:
  793. result = 1
  794. return result
  795. def f(n):
  796. frame = Frame()
  797. frame.x = n
  798. frame.y = 10
  799. somewhere_else.counter = 0
  800. somewhere_else.top_frame = frame
  801. while frame.x > 0:
  802. jitdriver.can_enter_jit(frame=frame)
  803. jitdriver.jit_merge_point(frame=frame)
  804. frame.x -= g()
  805. frame.y += 1
  806. return frame.x
  807. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g), repeat=7)
  808. assert res == f(123)
  809. def test_external_read_sometimes_recursive(self):
  810. jitdriver = JitDriver(greens = [], reds = ['rec', 'frame'],
  811. virtualizables = ['frame'])
  812. class Frame(object):
  813. _virtualizable_ = ['x', 'y']
  814. class SomewhereElse:
  815. pass
  816. somewhere_else = SomewhereElse()
  817. def g(rec):
  818. somewhere_else.counter += 1
  819. if somewhere_else.counter == 70:
  820. frame = somewhere_else.top_frame
  821. result1 = frame.y # external read
  822. result2 = frame.back.y # external read
  823. debug_print(lltype.Void, '-+-+-+-+- external read:',
  824. result1, result2)
  825. assert result1 == 13
  826. assert result2 == 1023
  827. result = 2
  828. elif rec:
  829. res = f(4, False)
  830. assert res == 0 or res == -1
  831. result = 1
  832. else:
  833. result = 1
  834. return result
  835. def f(n, rec):
  836. frame = Frame()
  837. frame.x = n
  838. frame.y = 10 + 1000 * rec
  839. frame.back = somewhere_else.top_frame
  840. somewhere_else.top_frame = frame
  841. while frame.x > 0:
  842. jitdriver.can_enter_jit(frame=frame, rec=rec)
  843. jitdriver.jit_merge_point(frame=frame, rec=rec)
  844. frame.x -= g(rec)
  845. frame.y += 1
  846. somewhere_else.top_frame = frame.back
  847. return frame.x
  848. def main(n):
  849. somewhere_else.counter = 0
  850. somewhere_else.top_frame = None
  851. return f(n, True)
  852. res = self.meta_interp(main, [123], policy=StopAtXPolicy(g))
  853. assert res == main(123)
  854. def test_external_write_sometimes(self):
  855. jitdriver = JitDriver(greens = [], reds = ['frame'],
  856. virtualizables = ['frame'])
  857. class Frame(object):
  858. _virtualizable_ = ['x', 'y']
  859. class SomewhereElse:
  860. pass
  861. somewhere_else = SomewhereElse()
  862. def g():
  863. somewhere_else.counter += 1
  864. if somewhere_else.counter == 70:
  865. debug_print(lltype.Void, '-+-+-+-+- external write: 7000')
  866. somewhere_else.top_frame.y = 7000
  867. result = 2
  868. else:
  869. result = 1
  870. return result
  871. def f(n):
  872. frame = Frame()
  873. frame.x = n
  874. frame.y = 10
  875. somewhere_else.counter = 0
  876. somewhere_else.top_frame = frame
  877. while frame.x > 0:
  878. jitdriver.can_enter_jit(frame=frame)
  879. jitdriver.jit_merge_point(frame=frame)
  880. frame.x -= g()
  881. frame.y += 1
  882. return frame.y
  883. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
  884. assert res == f(123)
  885. def test_bridge_forces(self):
  886. jitdriver = JitDriver(greens = [], reds = ['frame'],
  887. virtualizables = ['frame'])
  888. class Frame(object):
  889. _virtualizable_ = ['x', 'y']
  890. class SomewhereElse:
  891. pass
  892. somewhere_else = SomewhereElse()
  893. def g():
  894. n = somewhere_else.top_frame.y + 700
  895. debug_print(lltype.Void, '-+-+-+-+- external write:', n)
  896. somewhere_else.top_frame.y = n
  897. def f(n):
  898. frame = Frame()
  899. frame.x = n
  900. frame.y = 10
  901. somewhere_else.counter = 0
  902. somewhere_else.top_frame = frame
  903. while frame.x > 0:
  904. jitdriver.can_enter_jit(frame=frame)
  905. jitdriver.jit_merge_point(frame=frame)
  906. if frame.y > 17:
  907. g()
  908. frame.x -= 5
  909. frame.y += 1
  910. return frame.y
  911. res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
  912. assert res == f(123)
  913. def test_promote_index_in_virtualizable_list(self):
  914. jitdriver = JitDriver(greens = [], reds = ['n', 'frame'],
  915. virtualizables = ['frame'])
  916. class Frame(object):
  917. _virtualizable_ = ['stackpos', 'stack[*]']
  918. def f(n):
  919. frame = Frame()
  920. frame.stack = [42, 0, 0]
  921. frame.stackpos = 1
  922. while n > 0:
  923. jitdriver.can_enter_jit(frame=frame, n=n)
  924. jitdriver.jit_merge_point(frame=frame, n=n)
  925. popped = frame.stack[frame.stackpos]
  926. sp = frame.stackpos - 1
  927. assert sp >= 0
  928. frame.stackpos = sp
  929. to_push = intmask(popped * 3)
  930. frame.stack[frame.stackpos] = to_push
  931. frame.stackpos += 1
  932. n -= 1
  933. return frame.stack[0]
  934. res = self.meta_interp(f, [70], listops=True)
  935. assert res == intmask(42 ** 70)
  936. self.check_resops(int_add=0,
  937. int_sub=2) # for 'n -= 1' only
  938. def test_simple_access_directly(self):
  939. myjitdriver = JitDriver(greens = [], reds = ['frame'],
  940. virtualizables = ['frame'])
  941. class Frame(object):
  942. _virtualizable_ = ['x', 'y']
  943. def __init__(self, x, y):
  944. self = hint(self, access_directly=True)
  945. self.x = x
  946. self.y = y
  947. class SomewhereElse:
  948. pass
  949. somewhere_else = SomewhereElse()
  950. def f(n):
  951. frame = Frame(n, 0)
  952. somewhere_else.top_frame = frame # escapes
  953. frame = hint(frame, access_directly=True)
  954. while frame.x > 0:
  955. myjitdriver.can_enter_jit(frame=frame)
  956. myjitdriver.jit_merge_point(frame=frame)
  957. frame.y += frame.x
  958. frame.x -= 1
  959. return somewhere_else.top_frame.y
  960. res = self.meta_interp(f, [10])
  961. assert res == 55
  962. self.check_simple_loop(setfield_gc=0, getfield_gc_i=0,
  963. getfield_gc_r=0)
  964. from rpython.jit.backend.test.support import BaseCompiledMixin
  965. if isinstance(self, BaseCompiledMixin):
  966. return
  967. t = get_translator()
  968. f_graph, portal_graph = [graph for graph in t.graphs
  969. if getattr(graph, 'func', None) is f]
  970. init_graph = t._graphof(Frame.__init__.im_func)
  971. def direct_calls(graph):
  972. return [op.args[0].value._obj._callable.func_name
  973. for block, op in graph.iterblockops()
  974. if op.opname == 'direct_call']
  975. assert direct_calls(f_graph) == ['__init__',
  976. 'force_virtualizable_if_necessary',
  977. 'll_portal_runner']
  978. assert direct_calls(portal_graph) == ['force_virtualizable_if_necessary',
  979. 'maybe_enter_jit']
  980. assert direct_calls(init_graph) == []
  981. def test_virtual_child_frame(self):
  982. myjitdriver = JitDriver(greens = [], reds = ['frame'],
  983. virtualizables = ['frame'])
  984. class Frame(object):
  985. _virtualizable_ = ['x', 'y']
  986. def __init__(self, x, y):
  987. self = hint(self, access_directly=True)
  988. self.x = x
  989. self.y = y
  990. class SomewhereElse:
  991. pass
  992. somewhere_else = SomewhereElse()
  993. def f(n):
  994. frame = Frame(n, 0)
  995. somewhere_else.top_frame = frame # escapes
  996. frame = hint(frame, access_directly=True)
  997. while frame.x > 0:
  998. myjitdriver.can_enter_jit(frame=frame)
  999. myjitdriver.jit_merge_point(frame=frame)
  1000. child_frame = Frame(frame.x, 1)
  1001. frame.y += child_frame.x
  1002. frame.x -= 1
  1003. return somewhere_else.top_frame.y
  1004. res = self.meta_interp(f, [10])
  1005. assert res == 55
  1006. self.check_resops(new_with_vtable=0)
  1007. def test_check_for_nonstandardness_only_once(self):
  1008. myjitdriver = JitDriver(greens = [], reds = ['frame'],
  1009. virtualizables = ['frame'])
  1010. class Frame(object):
  1011. _virtualizable_ = ['x', 'y', 'z']
  1012. def __init__(self, x, y, z=1):
  1013. self = hint(self, access_directly=True)
  1014. self.x = x
  1015. self.y = y
  1016. self.z = z
  1017. class SomewhereElse:
  1018. pass
  1019. somewhere_else = SomewhereElse()
  1020. def f(n):
  1021. frame = Frame(n, 0)
  1022. somewhere_else.top_frame = frame # escapes
  1023. frame = hint(frame, access_directly=True)
  1024. while frame.x > 0:
  1025. myjitdriver.can_enter_jit(frame=frame)
  1026. myjitdriver.jit_merge_point(frame=frame)
  1027. top_frame = somewhere_else.top_frame
  1028. child_frame = Frame(frame.x, top_frame.z, 17)
  1029. frame.y += child_frame.x
  1030. frame.x -= top_frame.z
  1031. return somewhere_else.top_frame.y
  1032. res = self.meta_interp(f, [10])
  1033. assert res == 55
  1034. self.check_resops(new_with_vtable=0, ptr_eq=1)
  1035. self.check_history(ptr_eq=2)
  1036. def test_virtual_child_frame_with_arrays(self):
  1037. myjitdriver = JitDriver(greens = [], reds = ['frame'],
  1038. virtualizables = ['frame'])
  1039. class Frame(object):
  1040. _virtualizable_ = ['x[*]']
  1041. def __init__(self, x, y):
  1042. self = hint(self, access_directly=True,
  1043. fresh_virtualizable=True)
  1044. self.x = [x, y]
  1045. class SomewhereElse:
  1046. pass
  1047. somewhere_else = SomewhereElse()
  1048. def f(n):
  1049. frame = Frame(n, 0)
  1050. somewhere_else.top_frame = frame # escapes
  1051. frame = hint(frame, access_directly=True)
  1052. while frame.x[0] > 0:
  1053. myjitdriver.can_enter_jit(frame=frame)
  1054. myjitdriver.jit_merge_point(frame=frame)
  1055. child_frame = Frame(frame.x[0], 1)
  1056. frame.x[1] += child_frame.x[0]
  1057. frame.x[0] -= 1
  1058. return somewhere_else.top_frame.x[1]
  1059. res = self.meta_interp(f, [10], listops=True)
  1060. assert res == 55
  1061. self.check_resops(new_with_vtable=0)
  1062. def test_blackhole_should_not_pay_attention(self):
  1063. myjitdriver = JitDriver(greens = [], reds = ['frame'],
  1064. virtualizables = ['frame'])
  1065. class Frame(object):
  1066. _virtualizable_ = ['x', 'y']
  1067. def __init__(self, x, y):
  1068. self = hint(self, access_directly=True)
  1069. self.x = x
  1070. self.y = y
  1071. class SomewhereElse:
  1072. pass
  1073. somewhere_else = SomewhereElse()
  1074. def g(frame):
  1075. assert frame.x == 2
  1076. assert frame.y == 52
  1077. frame.y += 100
  1078. def f(n):
  1079. frame = Frame(n, 0)
  1080. somewhere_else.top_frame = frame # escapes
  1081. frame = hint(frame, access_directly=True)
  1082. while frame.x > 0:
  1083. myjitdriver.can_enter_jit(frame=frame)
  1084. myjitdriver.jit_merge_point(frame=frame)
  1085. if frame.x == 2:
  1086. g(frame)
  1087. frame.y += frame.x
  1088. frame.x -= 1
  1089. return somewhere_else.top_frame.y
  1090. res = self.meta_interp(f, [10])
  1091. assert res == 155
  1092. self.check_simple_loop(setfield_gc=0, getfield_gc_i=0,
  1093. getfield_gc_r=0)
  1094. self.check_resops(setfield_gc=0, getfield_gc_i=2,
  1095. getfield_gc_r=0)
  1096. def test_blackhole_should_synchronize(self):
  1097. myjitdriver = JitDriver(greens = [], reds = ['frame'],
  1098. virtualizables = ['frame'])
  1099. class Frame(object):
  1100. _virtualizable_ = ['x', 'y']
  1101. def __init__(self, x, y):
  1102. self.x = x
  1103. self.y = y
  1104. class SomewhereElse:
  1105. pass
  1106. somewhere_else = SomewhereElse()
  1107. def g(frame):
  1108. assert frame.x == 2
  1109. assert frame.y == 52
  1110. frame.y += 100
  1111. def f(n):
  1112. frame = Frame(n, 0)
  1113. somewhere_else.top_frame = frame # escapes
  1114. while frame.x > 0:
  1115. myjitdriver.can_enter_jit(frame=frame)
  1116. myjitdriver.jit_merge_point(frame=frame)
  1117. if frame.x == 2:
  1118. g(frame)
  1119. frame.y += frame.x
  1120. frame.x -= 1
  1121. return somewhere_else.top_frame.y
  1122. res = self.meta_interp(f, [10])
  1123. assert res == 155
  1124. self.check_simple_loop(setfield_gc=0, getfield_gc_i=0,
  1125. getfield_gc_r=0)
  1126. self.check_resops(setfield_gc=0, getfield_gc_i=2, getfield_gc_r=0)
  1127. def test_blackhole_should_not_reenter(self):
  1128. if not self.basic:
  1129. py.test.skip("purely frontend test")
  1130. myjitdriver = JitDriver(greens = [], reds = ['fail', 'frame'],
  1131. virtualizables = ['frame'])
  1132. class Frame(object):
  1133. _virtualizable_ = ['x', 'y']
  1134. def __init__(self, x, y):
  1135. self = hint(self, access_directly=True)
  1136. self.x = x
  1137. self.y = y
  1138. class SomewhereElse:
  1139. pass
  1140. somewhere_else = SomewhereElse()
  1141. def jump_back(frame, fail):
  1142. myjitdriver.can_enter_jit(frame=frame, fail=fail)
  1143. def f(n, fail):
  1144. frame = Frame(n, 0)
  1145. somewhere_else.top_frame = frame # escapes
  1146. frame = hint(frame, access_directly=True)
  1147. while True:
  1148. myjitdriver.jit_merge_point(frame=frame, fail=fail)
  1149. if frame.x <= 0:
  1150. break
  1151. frame.x -= 1
  1152. if fail or frame.x > 2:
  1153. frame.y += frame.x
  1154. jump_back(frame, fail)
  1155. return somewhere_else.top_frame.y
  1156. def main():
  1157. a = f(10, True)
  1158. b = f(10, True)
  1159. c = f(10, True)
  1160. d = f(10, True)
  1161. e = f(10, False)
  1162. return a + 17*b + 17*17*c + 17*17*17*d + 17*17*17*17*e
  1163. # the situation is: blackholing starts at the "if" above, then
  1164. # really calls jump_back(), which ends up calling
  1165. # can_enter_jit() for the same frame as the one we are currently
  1166. # blackholing. It should just work fine, though.
  1167. res = self.meta_interp(main, [])
  1168. assert res == main()
  1169. def test_inlining(self):
  1170. class Frame(object):
  1171. _virtualizable_ = ['x', 'next']
  1172. def __init__(self, x):
  1173. self = hint(self, access_directly=True)
  1174. self.x = x
  1175. self.next = None
  1176. driver = JitDriver(greens=[], reds=['result', 'frame'],
  1177. virtualizables=['frame'])
  1178. def interp(caller):
  1179. f = Frame(caller.x)
  1180. caller.next = f
  1181. f = hint(f, access_directly=True)
  1182. result = 0
  1183. while f.x > 0:
  1184. driver.can_enter_jit(frame=f, result=result)
  1185. driver.jit_merge_point(frame=f, result=result)
  1186. f.x -= 1
  1187. result += indirection(f)
  1188. return result
  1189. def indirection(arg):
  1190. return interp(arg) + 1
  1191. def run_interp(n):
  1192. f = hint(Frame(n), access_directly=True)
  1193. return interp(f)
  1194. res = self.meta_interp(run_interp, [4])
  1195. assert res == run_interp(4)
  1196. def test_guard_failure_in_inlined_function(self):
  1197. class Frame(object):
  1198. _virtualizable_ = ['n', 'next']
  1199. def __init__(self, n):
  1200. self = hint(self, access_directly=True)
  1201. self.n = n
  1202. self.next = None
  1203. driver = JitDriver(greens=[], reds=['result', 'frame'],
  1204. virtualizables=['frame'])
  1205. def p(pc, code):
  1206. code = hlstr(code)
  1207. return "%s %d %s" % (code, pc, code[pc])
  1208. myjitdriver = JitDriver(greens=['pc', 'code'], reds=['frame'],
  1209. virtualizables=["frame"],
  1210. get_printable_location=p)
  1211. def f(code, frame):
  1212. pc = 0
  1213. while pc < len(code):
  1214. myjitdriver.jit_merge_point(frame=frame, code=code, pc=pc)
  1215. op = code[pc]
  1216. if op == "-":
  1217. frame.n -= 1
  1218. elif op == "c":
  1219. subframe = Frame(frame.n)
  1220. frame.next = subframe
  1221. frame.n = f("---i---", subframe)
  1222. frame.next = None
  1223. elif op == "i":
  1224. if frame.n % 5 == 1:
  1225. return frame.n
  1226. elif op == "l":
  1227. if frame.n > 0:
  1228. myjitdriver.can_enter_jit(frame=frame, code=code, pc=0)
  1229. pc = 0
  1230. continue
  1231. else:
  1232. assert 0
  1233. pc += 1
  1234. return frame.n
  1235. def main(n):
  1236. frame = Frame(n)
  1237. return f("c-l", frame)
  1238. res = self.meta_interp(main, [100], inline=True, enable_opts='')
  1239. assert res == main(100)
  1240. def test_stuff_from_backend_test(self):
  1241. class Thing(object):
  1242. def __init__(self, val):
  1243. self.val = val
  1244. class Frame(object):
  1245. _virtualizable_ = ['thing']
  1246. driver = JitDriver(greens = ['codeno'], reds = ['i', 'frame'],
  1247. virtualizables = ['frame'],
  1248. get_printable_location = lambda codeno: str(codeno))
  1249. class SomewhereElse(object):
  1250. pass
  1251. somewhere_else = SomewhereElse()
  1252. @dont_look_inside
  1253. def change(newthing):
  1254. somewhere_else.frame.thing = newthing
  1255. def main(codeno):
  1256. frame = Frame()
  1257. somewhere_else.frame = frame
  1258. frame.thing = Thing(0)
  1259. portal(codeno, frame)
  1260. return frame.thing.val
  1261. def portal(codeno, frame):
  1262. i = 0
  1263. while i < 10:
  1264. driver.can_enter_jit(frame=frame, codeno=codeno, i=i)
  1265. driver.jit_merge_point(frame=frame, codeno=codeno, i=i)
  1266. nextval = frame.thing.val
  1267. if codeno == 0:
  1268. subframe = Frame()
  1269. subframe.thing = Thing(nextval)
  1270. nextval = portal(1, subframe)
  1271. elif frame.thing.val > 40:
  1272. change(Thing(13))
  1273. nextval = 13
  1274. frame.thing = Thing(nextval + 1)
  1275. i += 1
  1276. return frame.thing.val
  1277. res = self.meta_interp(main, [0], inline=True)
  1278. print hex(res)
  1279. assert res == main(0)
  1280. def test_force_virtualref_to_virtualizable(self):
  1281. jitdriver = JitDriver(
  1282. greens=[],
  1283. reds=['i', 'n', 'f', 'f_ref'],
  1284. virtualizables=['f']
  1285. )
  1286. class Frame(object):
  1287. _virtualizable_ = ['x']
  1288. def main(n):
  1289. f = Frame()
  1290. f.x = 1
  1291. f_ref = virtual_ref(f)
  1292. i = 0
  1293. while i < n:
  1294. jitdriver.jit_merge_point(f=f, i=i, f_ref=f_ref, n=n)
  1295. i += f_ref().x
  1296. return i
  1297. res = self.meta_interp(main, [10])
  1298. assert res == main(10)
  1299. self.check_resops({
  1300. "getfield_gc_i": 1, "int_lt": 2, "ptr_eq": 1, "guard_true": 3,
  1301. "int_add": 2, "jump": 1
  1302. })
  1303. def test_frame_nonstandard_no_virtualizable(self):
  1304. driver1 = JitDriver(greens=[], reds=['i', 's', 'frame'])
  1305. driver2 = JitDriver(greens=[], reds=['frame'],
  1306. virtualizables=['frame'])
  1307. class Frame(object):
  1308. _virtualizable_ = ['x']
  1309. def g(frame):
  1310. driver2.jit_merge_point(frame=frame)
  1311. frame.x += 1
  1312. return frame
  1313. def f():
  1314. i = 0
  1315. s = 0
  1316. frame = Frame()
  1317. frame.x = 0
  1318. g(frame)
  1319. while i < 10:
  1320. driver1.jit_merge_point(frame=frame, s=s, i=i)
  1321. frame = g(frame)
  1322. s += frame.x
  1323. i += 1
  1324. return s
  1325. def main():
  1326. res = 0
  1327. for i in range(10):
  1328. res += f()
  1329. return res
  1330. res = self.meta_interp(main, [])
  1331. assert res == main()
  1332. def test_two_virtualizables_mixed(self):
  1333. driver1 = JitDriver(greens=[], reds=['i', 's', 'frame',
  1334. 'subframe'])
  1335. driver2 = JitDriver(greens=[], reds=['subframe'],
  1336. virtualizables=['subframe'])
  1337. class Frame(object):
  1338. _virtualizable_ = ['x']
  1339. class SubFrame(object):
  1340. _virtualizable_ = ['x']
  1341. def g(subframe):
  1342. driver2.jit_merge_point(subframe=subframe)
  1343. subframe.x += 1
  1344. def f():
  1345. i = 0
  1346. frame = Frame()
  1347. frame.x = 0
  1348. subframe = SubFrame()
  1349. subframe.x = 0
  1350. s = 0
  1351. while i < 10:
  1352. driver1.jit_merge_point(frame=frame, subframe=subframe, i=i,
  1353. s=s)
  1354. g(subframe)
  1355. s += subframe.x
  1356. i += 1
  1357. return s
  1358. res = self.meta_interp(f, [])
  1359. assert res == f()
  1360. def test_force_virtualizable_by_hint(self):
  1361. class Frame(object):
  1362. _virtualizable_ = ['x']
  1363. driver = JitDriver(greens = [], reds = ['i', 'frame'],
  1364. virtualizables = ['frame'])
  1365. def f(frame, i):
  1366. while i > 0:
  1367. driver.jit_merge_point(i=i, frame=frame)
  1368. i -= 1
  1369. frame.x += 1
  1370. hint(frame, force_virtualizable=True)
  1371. def main():
  1372. frame = Frame()
  1373. frame.x = 0
  1374. s = 0
  1375. for i in range(20):
  1376. f(frame, 4)
  1377. s += frame.x
  1378. return s
  1379. r = self.meta_interp(main, [])
  1380. assert r == main()
  1381. # fish the bridge
  1382. loop = get_stats().get_all_loops()[0]
  1383. d = loop.operations[-3].getdescr()
  1384. bridge = getattr(d, '_llgraph_bridge', None)
  1385. if bridge is not None:
  1386. l = [op for op in
  1387. bridge.operations if op.getopnum() == rop.SETFIELD_GC]
  1388. assert "'inst_x'" in str(l[1].getdescr().realdescrref())
  1389. assert len(l) == 2 # vable token set to null
  1390. l = [op for op in bridge.operations if
  1391. op.getopnum() == rop.GUARD_NOT_FORCED_2]
  1392. assert len(l) == 0
  1393. def test_two_virtualizable_types(self):
  1394. class A:
  1395. _virtualizable_ = ['x']
  1396. def __init__(self, x):
  1397. self.x = x
  1398. class B:
  1399. _virtualizable_ = ['lst[*]']
  1400. def __init__(self, lst):
  1401. self.lst = lst
  1402. driver_a = JitDriver(greens=[], reds=['a'], virtualizables=['a'])
  1403. driver_b = JitDriver(greens=[], reds=['b'], virtualizables=['b'])
  1404. def foo_a(a):
  1405. while a.x > 0:
  1406. driver_a.jit_merge_point(a=a)
  1407. a.x -= 2
  1408. return a.x
  1409. def foo_b(b):
  1410. while b.lst[0] > 0:
  1411. driver_b.jit_merge_point(b=b)
  1412. b.lst[0] -= 2
  1413. return b.lst[0]
  1414. def f():
  1415. return foo_a(A(13)) * 100 + foo_b(B([13]))
  1416. assert f() == -101
  1417. res = self.meta_interp(f, [], listops=True)
  1418. assert res == -101
  1419. def test_same_virtualizable_for_two_invocations(self):
  1420. class A:
  1421. _virtualizable_ = ['x']
  1422. def __init__(self, x):
  1423. self.x = x
  1424. driver = JitDriver(greens=['k'], reds=['a'], virtualizables=['a'])
  1425. def foo(a, k):
  1426. while True:
  1427. driver.jit_merge_point(a=a, k=k)
  1428. if k == 99:
  1429. return 61
  1430. if a.x <= k:
  1431. return 0
  1432. a.x -= 1
  1433. def f():
  1434. # first, compile foo(k=2) fully, including the exit bridge
  1435. for i in range(10):
  1436. a = A(5)
  1437. foo(a, 2)
  1438. #
  1439. for i in range(5):
  1440. # then take a 'a' still virtualized
  1441. a = A(5)
  1442. foo(a, 2)
  1443. # and use it in foo(k=99), which will be compiled (as a
  1444. # trivial finish) if we repeat the whole procedure a
  1445. # few times
  1446. foo(a, 99)
  1447. #
  1448. return 0
  1449. res = self.meta_interp(f, [], listops=True)
  1450. assert res == 0
  1451. def test_constant_virtualizable(self):
  1452. class A:
  1453. _virtualizable_ = ['x']
  1454. def __init__(self, x):
  1455. self.x = x
  1456. driver = JitDriver(greens=['b'], reds=['a'], virtualizables=['a'])
  1457. def f():
  1458. a = A(10)
  1459. b = promote(a)
  1460. while a.x > 0:
  1461. driver.jit_merge_point(a=a, b=b)
  1462. a.x = b.x - 1
  1463. return a.x
  1464. res = self.meta_interp(f, [], listops=True)
  1465. assert res == 0
  1466. def test_tracing_sees_nonstandard_vable_twice(self):
  1467. # This test might fall we try to remove heapcache.clear_caches()'s
  1468. # call to reset_keep_likely_virtuals() for CALL_MAY_FORCE, and doing
  1469. # so, we forget to clean up the "nonstandard_virtualizable" fields.
  1470. class A:
  1471. _virtualizable_ = ['x']
  1472. @dont_look_inside
  1473. def __init__(self, x):
  1474. self.x = x
  1475. def check(self, expected_x):
  1476. if self.x != expected_x:
  1477. raise ValueError
  1478. driver1 = JitDriver(greens=[], reds=['a'], virtualizables=['a'])
  1479. driver2 = JitDriver(greens=[], reds=['i'])
  1480. def f(a):
  1481. while a.x > 0:
  1482. driver1.jit_merge_point(a=a)
  1483. a.x -= 1
  1484. def main():
  1485. i = 10
  1486. while i > 0:
  1487. driver2.jit_merge_point(i=i)
  1488. a = A(10)
  1489. a.check(10) # first time, 'a' has got no vable_token
  1490. f(a)
  1491. a.check(0) # second time, the same 'a' has got one!
  1492. i -= 1
  1493. return 42
  1494. res = self.meta_interp(main, [], listops=True)
  1495. assert res == 42
  1496. def test_blackhole_should_also_force_virtualizables(self):
  1497. class A:
  1498. _virtualizable_ = ['x']
  1499. def __init__(self, x):
  1500. self.x = x
  1501. driver1 = JitDriver(greens=[], reds=['a'], virtualizables=['a'])
  1502. driver2 = JitDriver(greens=[], reds=['i'])
  1503. def f(a):
  1504. while a.x > 0:
  1505. driver1.jit_merge_point(a=a)
  1506. a.x -= 1
  1507. def main():
  1508. i = 10
  1509. while i > 0:
  1510. driver2.jit_merge_point(i=i)
  1511. a = A(10)
  1512. f(a)
  1513. # The interesting case is i==2. We're running the rest of
  1514. # this function in the blackhole interp, because of this:
  1515. if i == 2:
  1516. pass
  1517. # Here, 'a' has got a non-null vtable_token because f()
  1518. # is already completely JITted. But the blackhole interp
  1519. # ignores it and reads the bogus value currently physically
  1520. # stored in a.x...
  1521. if a.x != 0:
  1522. raise ValueError
  1523. i -= 1
  1524. return 42
  1525. res = self.meta_interp(main, [], listops=True, repeat=7)
  1526. assert res == 42
  1527. class TestLLtype(ExplicitVirtualizableTests,
  1528. ImplicitVirtualizableTests,
  1529. LLJitMixin):
  1530. pass