/rpython/flowspace/test/test_objspace.py

https://bitbucket.org/pypy/pypy/ · Python · 1380 lines · 1139 code · 181 blank · 60 comment · 181 complexity · 2dd36bf0896f5161c4e948f0cd6231b0 MD5 · raw file

  1. from __future__ import with_statement
  2. import types
  3. import py
  4. from contextlib import contextmanager
  5. from rpython.flowspace.model import (
  6. Constant, mkentrymap, const)
  7. from rpython.translator.simplify import simplify_graph
  8. from rpython.flowspace.objspace import build_flow
  9. from rpython.flowspace.flowcontext import FlowingError, FlowContext
  10. from rpython.conftest import option
  11. from rpython.tool.stdlib_opcode import host_bytecode_spec
  12. import os
  13. import operator
  14. is_operator = getattr(operator, 'is_', operator.eq) # it's not there 2.2
  15. @contextmanager
  16. def patching_opcodes(**opcodes):
  17. meth_names = host_bytecode_spec.method_names
  18. old_name = {}
  19. for name, num in opcodes.items():
  20. old_name[num] = meth_names[num]
  21. meth_names[num] = name
  22. yield
  23. for name in opcodes:
  24. meth_names[num] = old_name[num]
  25. class Base:
  26. def codetest(self, func, **kwds):
  27. import inspect
  28. try:
  29. func = func.im_func
  30. except AttributeError:
  31. pass
  32. #name = func.func_name
  33. graph = build_flow(func, **kwds)
  34. graph.source = inspect.getsource(func)
  35. self.show(graph)
  36. return graph
  37. def show(self, graph):
  38. if option.view:
  39. graph.show()
  40. def all_operations(self, graph):
  41. result = {}
  42. for node in graph.iterblocks():
  43. for op in node.operations:
  44. result.setdefault(op.opname, 0)
  45. result[op.opname] += 1
  46. return result
  47. def test_all_opcodes_defined():
  48. opnames = set(host_bytecode_spec.method_names)
  49. methods = set([name for name in dir(FlowContext) if name.upper() == name])
  50. handled_elsewhere = set(['EXTENDED_ARG'])
  51. missing = opnames - methods - handled_elsewhere
  52. assert not missing
  53. class TestFlowObjSpace(Base):
  54. def nothing():
  55. pass
  56. def test_nothing(self):
  57. x = self.codetest(self.nothing)
  58. assert len(x.startblock.exits) == 1
  59. link, = x.startblock.exits
  60. assert link.target == x.returnblock
  61. #__________________________________________________________
  62. def simplefunc(x):
  63. return x+1
  64. def test_simplefunc(self):
  65. graph = self.codetest(self.simplefunc)
  66. assert self.all_operations(graph) == {'add': 1}
  67. #__________________________________________________________
  68. def simplebranch(i, j):
  69. if i < 0:
  70. return i
  71. return j
  72. def test_simplebranch(self):
  73. x = self.codetest(self.simplebranch)
  74. #__________________________________________________________
  75. def ifthenelse(i, j):
  76. if i < 0:
  77. i = j
  78. return user_defined_function(i) + 1
  79. def test_ifthenelse(self):
  80. x = self.codetest(self.ifthenelse)
  81. #__________________________________________________________
  82. def loop(x):
  83. x = abs(x)
  84. while x:
  85. x = x - 1
  86. def test_loop(self):
  87. graph = self.codetest(self.loop)
  88. assert self.all_operations(graph) == {'abs': 1,
  89. 'bool': 1,
  90. 'sub': 1}
  91. #__________________________________________________________
  92. def print_(i):
  93. print i
  94. def test_print(self):
  95. x = self.codetest(self.print_)
  96. def test_bad_print(self):
  97. def f(x):
  98. print >> x, "Hello"
  99. with py.test.raises(FlowingError):
  100. self.codetest(f)
  101. #__________________________________________________________
  102. def while_(i):
  103. while i > 0:
  104. i = i - 1
  105. def test_while(self):
  106. x = self.codetest(self.while_)
  107. #__________________________________________________________
  108. def union_easy(i):
  109. if i:
  110. pass
  111. else:
  112. i = 5
  113. return i
  114. def test_union_easy(self):
  115. x = self.codetest(self.union_easy)
  116. #__________________________________________________________
  117. def union_hard(i):
  118. if i:
  119. i = 5
  120. return i
  121. def test_union_hard(self):
  122. x = self.codetest(self.union_hard)
  123. #__________________________________________________________
  124. def while_union(i):
  125. total = 0
  126. while i > 0:
  127. total += i
  128. i = i - 1
  129. return total
  130. def test_while_union(self):
  131. x = self.codetest(self.while_union)
  132. #__________________________________________________________
  133. def simple_for(lst):
  134. total = 0
  135. for i in lst:
  136. total += i
  137. return total
  138. def test_simple_for(self):
  139. x = self.codetest(self.simple_for)
  140. #__________________________________________________________
  141. def nested_whiles(i, j):
  142. s = ''
  143. z = 5
  144. while z > 0:
  145. z = z - 1
  146. u = i
  147. while u < j:
  148. u = u + 1
  149. s = s + '.'
  150. s = s + '!'
  151. return s
  152. def test_nested_whiles(self):
  153. x = self.codetest(self.nested_whiles)
  154. #__________________________________________________________
  155. def break_continue(x):
  156. result = []
  157. i = 0
  158. while 1:
  159. i = i + 1
  160. try:
  161. if i&1:
  162. continue
  163. if i >= x:
  164. break
  165. finally:
  166. result.append(i)
  167. i = i + 1
  168. return result
  169. def test_break_continue(self):
  170. x = self.codetest(self.break_continue)
  171. def test_break_from_handler(self):
  172. def f(x):
  173. while True:
  174. try:
  175. x()
  176. except TypeError:
  177. if x:
  178. raise
  179. break
  180. assert f(0) is None
  181. graph = self.codetest(f)
  182. simplify_graph(graph)
  183. entrymap = mkentrymap(graph)
  184. links = entrymap[graph.returnblock]
  185. assert len(links) == 1
  186. #__________________________________________________________
  187. def unpack_tuple(lst):
  188. a, b, c = lst
  189. def test_unpack_tuple(self):
  190. x = self.codetest(self.unpack_tuple)
  191. #__________________________________________________________
  192. def reverse_3(lst):
  193. try:
  194. a, b, c = lst
  195. except:
  196. return 0, 0, 0
  197. else:
  198. return c, b, a
  199. def test_reverse_3(self):
  200. x = self.codetest(self.reverse_3)
  201. #__________________________________________________________
  202. def finallys(lst):
  203. x = 1
  204. try:
  205. x = 2
  206. try:
  207. x = 3
  208. a, = lst
  209. x = 4
  210. except KeyError:
  211. return 5
  212. except ValueError:
  213. return 6
  214. b, = lst
  215. x = 7
  216. finally:
  217. x = 8
  218. return x
  219. def test_finallys(self):
  220. x = self.codetest(self.finallys)
  221. def test_branching_in_finally(self):
  222. def f(x, y):
  223. try:
  224. return x
  225. finally:
  226. if x:
  227. x = 0
  228. if y > 0:
  229. y -= 1
  230. return y
  231. self.codetest(f)
  232. #__________________________________________________________
  233. def const_pow():
  234. return 2 ** 5
  235. def test_const_pow(self):
  236. x = self.codetest(self.const_pow)
  237. #__________________________________________________________
  238. def implicitException(lst):
  239. try:
  240. x = lst[5]
  241. except Exception:
  242. return 'catch'
  243. return lst[3] # not caught
  244. def test_implicitException(self):
  245. x = self.codetest(self.implicitException)
  246. simplify_graph(x)
  247. self.show(x)
  248. for link in x.iterlinks():
  249. assert link.target is not x.exceptblock
  250. def implicitAttributeError(x):
  251. try:
  252. x = getattr(x, "y")
  253. except AttributeError:
  254. return 'catch'
  255. return getattr(x, "z") # not caught
  256. def test_implicitAttributeError(self):
  257. x = self.codetest(self.implicitAttributeError)
  258. simplify_graph(x)
  259. self.show(x)
  260. for link in x.iterlinks():
  261. assert link.target is not x.exceptblock
  262. #__________________________________________________________
  263. def implicitException_int_and_id(x):
  264. try:
  265. return int(x) + id(x)
  266. except TypeError: # not captured by the flow graph!
  267. return 0
  268. def test_implicitException_int_and_id(self):
  269. x = self.codetest(self.implicitException_int_and_id)
  270. simplify_graph(x)
  271. self.show(x)
  272. assert len(x.startblock.exits) == 1
  273. assert x.startblock.exits[0].target is x.returnblock
  274. #__________________________________________________________
  275. def implicitException_os_stat(x):
  276. try:
  277. return os.stat(x)
  278. except OSError: # *captured* by the flow graph!
  279. return 0
  280. def test_implicitException_os_stat(self):
  281. x = self.codetest(self.implicitException_os_stat)
  282. simplify_graph(x)
  283. self.show(x)
  284. assert len(x.startblock.exits) == 3
  285. d = {}
  286. for link in x.startblock.exits:
  287. d[link.exitcase] = True
  288. assert d == {None: True, OSError: True, Exception: True}
  289. #__________________________________________________________
  290. def reraiseAnythingDicCase(dic):
  291. try:
  292. dic[5]
  293. except:
  294. raise
  295. def test_reraiseAnythingDicCase(self):
  296. x = self.codetest(self.reraiseAnythingDicCase)
  297. simplify_graph(x)
  298. self.show(x)
  299. found = {}
  300. for link in x.iterlinks():
  301. if link.target is x.exceptblock:
  302. if isinstance(link.args[0], Constant):
  303. found[link.args[0].value] = True
  304. else:
  305. found[link.exitcase] = None
  306. assert found == {IndexError: True, KeyError: True, Exception: None}
  307. def reraiseAnything(x):
  308. try:
  309. pow(x, 5)
  310. except:
  311. raise
  312. def test_reraiseAnything(self):
  313. x = self.codetest(self.reraiseAnything)
  314. simplify_graph(x)
  315. self.show(x)
  316. found = {}
  317. for link in x.iterlinks():
  318. if link.target is x.exceptblock:
  319. assert isinstance(link.args[0], Constant)
  320. found[link.args[0].value] = True
  321. assert found == {ValueError: True, ZeroDivisionError: True, OverflowError: True}
  322. def loop_in_bare_except_bug(lst):
  323. try:
  324. for x in lst:
  325. pass
  326. except:
  327. lst.append(5)
  328. raise
  329. def test_loop_in_bare_except_bug(self):
  330. x = self.codetest(self.loop_in_bare_except_bug)
  331. simplify_graph(x)
  332. self.show(x)
  333. #__________________________________________________________
  334. def freevar(self, x):
  335. def adder(y):
  336. return x+y
  337. return adder
  338. def test_freevar(self):
  339. x = self.codetest(self.freevar(3))
  340. #__________________________________________________________
  341. def raise1(msg):
  342. raise IndexError
  343. def test_raise1(self):
  344. x = self.codetest(self.raise1)
  345. simplify_graph(x)
  346. self.show(x)
  347. ops = x.startblock.operations
  348. assert len(ops) == 2
  349. assert ops[0].opname == 'simple_call'
  350. assert ops[0].args == [Constant(IndexError)]
  351. assert ops[1].opname == 'type'
  352. assert ops[1].args == [ops[0].result]
  353. assert x.startblock.exits[0].args == [ops[1].result, ops[0].result]
  354. assert x.startblock.exits[0].target is x.exceptblock
  355. def test_simple_raise(self):
  356. def f():
  357. raise ValueError('ouch')
  358. x = self.codetest(f)
  359. simplify_graph(x)
  360. self.show(x)
  361. ops = x.startblock.operations
  362. assert ops[0].opname == 'simple_call'
  363. assert ops[0].args == [Constant(ValueError), Constant('ouch')]
  364. def test_raise_prebuilt(self):
  365. error = ValueError('ouch')
  366. def g(x): return x
  367. def f():
  368. raise g(error)
  369. x = self.codetest(f)
  370. simplify_graph(x)
  371. self.show(x)
  372. ops = x.startblock.operations
  373. assert ops[0].opname == 'simple_call'
  374. assert ops[0].args == [const(g), const(error)]
  375. #__________________________________________________________
  376. def raise2(msg):
  377. raise IndexError, msg
  378. def test_raise2(self):
  379. x = self.codetest(self.raise2)
  380. # XXX can't check the shape of the graph, too complicated...
  381. #__________________________________________________________
  382. def raise3(msg):
  383. raise IndexError(msg)
  384. def test_raise3(self):
  385. x = self.codetest(self.raise3)
  386. # XXX can't check the shape of the graph, too complicated...
  387. #__________________________________________________________
  388. def raise4(stuff):
  389. raise stuff
  390. def test_raise4(self):
  391. x = self.codetest(self.raise4)
  392. #__________________________________________________________
  393. def raisez(z, tb):
  394. raise z.__class__,z, tb
  395. def test_raisez(self):
  396. x = self.codetest(self.raisez)
  397. #__________________________________________________________
  398. def raise_and_catch_1(exception_instance):
  399. try:
  400. raise exception_instance
  401. except IndexError:
  402. return -1
  403. return 0
  404. def test_raise_and_catch_1(self):
  405. x = self.codetest(self.raise_and_catch_1)
  406. #__________________________________________________________
  407. def catch_simple_call():
  408. try:
  409. user_defined_function()
  410. except IndexError:
  411. return -1
  412. return 0
  413. def test_catch_simple_call(self):
  414. x = self.codetest(self.catch_simple_call)
  415. #__________________________________________________________
  416. def multiple_catch_simple_call():
  417. try:
  418. user_defined_function()
  419. except (IndexError, OSError):
  420. return -1
  421. return 0
  422. def test_multiple_catch_simple_call(self):
  423. graph = self.codetest(self.multiple_catch_simple_call)
  424. simplify_graph(graph)
  425. assert self.all_operations(graph) == {'simple_call': 1}
  426. entrymap = mkentrymap(graph)
  427. links = entrymap[graph.returnblock]
  428. assert len(links) == 3
  429. assert (dict.fromkeys([link.exitcase for link in links]) ==
  430. dict.fromkeys([None, IndexError, OSError]))
  431. links = entrymap[graph.exceptblock]
  432. assert len(links) == 1
  433. assert links[0].exitcase is Exception
  434. #__________________________________________________________
  435. def dellocal():
  436. x = 1
  437. del x
  438. for i in range(10):
  439. pass
  440. def test_dellocal(self):
  441. x = self.codetest(self.dellocal)
  442. #__________________________________________________________
  443. def globalconstdict(name):
  444. x = DATA['x']
  445. z = DATA[name]
  446. return x, z
  447. def test_globalconstdict(self):
  448. x = self.codetest(self.globalconstdict)
  449. def test_dont_write_globals(self):
  450. def f():
  451. global DATA
  452. DATA = 5
  453. with py.test.raises(FlowingError) as excinfo:
  454. self.codetest(f)
  455. assert "modify global" in str(excinfo.value)
  456. assert DATA == {'x': 5, 'y': 6}
  457. #__________________________________________________________
  458. def dictliteral(name):
  459. x = {'x': 1}
  460. return x
  461. def test_dictliteral(self):
  462. x = self.codetest(self.dictliteral)
  463. #__________________________________________________________
  464. def specialcases(x):
  465. operator.lt(x,3)
  466. operator.le(x,3)
  467. operator.eq(x,3)
  468. operator.ne(x,3)
  469. operator.gt(x,3)
  470. operator.ge(x,3)
  471. is_operator(x,3)
  472. operator.__lt__(x,3)
  473. operator.__le__(x,3)
  474. operator.__eq__(x,3)
  475. operator.__ne__(x,3)
  476. operator.__gt__(x,3)
  477. operator.__ge__(x,3)
  478. operator.xor(x,3)
  479. # the following ones are constant-folded
  480. operator.eq(2,3)
  481. operator.__gt__(2,3)
  482. def test_specialcases(self):
  483. x = self.codetest(self.specialcases)
  484. from rpython.translator.simplify import join_blocks
  485. join_blocks(x)
  486. assert len(x.startblock.operations) == 14
  487. for op in x.startblock.operations:
  488. assert op.opname in ['lt', 'le', 'eq', 'ne',
  489. 'gt', 'ge', 'is_', 'xor']
  490. assert len(op.args) == 2
  491. assert op.args[1].value == 3
  492. def test_unary_ops(self):
  493. def f(x):
  494. return not ~-x
  495. graph = self.codetest(f)
  496. assert self.all_operations(graph) == {'bool': 1, 'invert': 1, 'neg': 1}
  497. #__________________________________________________________
  498. def wearetranslated(x):
  499. from rpython.rlib.objectmodel import we_are_translated
  500. if we_are_translated():
  501. return x
  502. else:
  503. some_name_error_here
  504. def test_wearetranslated(self):
  505. x = self.codetest(self.wearetranslated)
  506. from rpython.translator.simplify import join_blocks
  507. join_blocks(x)
  508. # check that 'x' is an empty graph
  509. assert len(x.startblock.operations) == 0
  510. assert len(x.startblock.exits) == 1
  511. assert x.startblock.exits[0].target is x.returnblock
  512. #__________________________________________________________
  513. def jump_target_specialization(x):
  514. if x:
  515. n = 5
  516. else:
  517. n = 6
  518. return n*2
  519. def test_jump_target_specialization(self):
  520. x = self.codetest(self.jump_target_specialization)
  521. for block in x.iterblocks():
  522. for op in block.operations:
  523. assert op.opname != 'mul', "mul should have disappeared"
  524. #__________________________________________________________
  525. def highly_branching_example(a,b,c,d,e,f,g,h,i,j):
  526. if a:
  527. x1 = 1
  528. else:
  529. x1 = 2
  530. if b:
  531. x2 = 1
  532. else:
  533. x2 = 2
  534. if c:
  535. x3 = 1
  536. else:
  537. x3 = 2
  538. if d:
  539. x4 = 1
  540. else:
  541. x4 = 2
  542. if e:
  543. x5 = 1
  544. else:
  545. x5 = 2
  546. if f:
  547. x6 = 1
  548. else:
  549. x6 = 2
  550. if g:
  551. x7 = 1
  552. else:
  553. x7 = 2
  554. if h:
  555. x8 = 1
  556. else:
  557. x8 = 2
  558. if i:
  559. x9 = 1
  560. else:
  561. x9 = 2
  562. if j:
  563. x10 = 1
  564. else:
  565. x10 = 2
  566. return (x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)
  567. def test_highly_branching_example(self):
  568. x = self.codetest(self.highly_branching_example)
  569. simplify_graph(x)
  570. # roughly 20 blocks + 30 links
  571. assert len(list(x.iterblocks())) + len(list(x.iterlinks())) < 60
  572. #__________________________________________________________
  573. def test_unfrozen_user_class1(self):
  574. class C:
  575. def __nonzero__(self):
  576. return True
  577. c = C()
  578. def f():
  579. if c:
  580. return 1
  581. else:
  582. return 2
  583. graph = self.codetest(f)
  584. results = []
  585. for link in graph.iterlinks():
  586. if link.target == graph.returnblock:
  587. results.extend(link.args)
  588. assert len(results) == 2
  589. def test_unfrozen_user_class2(self):
  590. class C:
  591. def __add__(self, other):
  592. return 4
  593. c = C()
  594. d = C()
  595. def f():
  596. return c+d
  597. graph = self.codetest(f)
  598. results = []
  599. for link in graph.iterlinks():
  600. if link.target == graph.returnblock:
  601. results.extend(link.args)
  602. assert not isinstance(results[0], Constant)
  603. def test_frozen_user_class1(self):
  604. class C:
  605. def __nonzero__(self):
  606. return True
  607. def _freeze_(self):
  608. return True
  609. c = C()
  610. def f():
  611. if c:
  612. return 1
  613. else:
  614. return 2
  615. graph = self.codetest(f)
  616. results = []
  617. for link in graph.iterlinks():
  618. if link.target == graph.returnblock:
  619. results.extend(link.args)
  620. assert len(results) == 1
  621. def test_frozen_user_class2(self):
  622. class C:
  623. def __add__(self, other):
  624. return 4
  625. def _freeze_(self):
  626. return True
  627. c = C()
  628. d = C()
  629. def f():
  630. return c+d
  631. graph = self.codetest(f)
  632. results = []
  633. for link in graph.iterlinks():
  634. if link.target == graph.returnblock:
  635. results.extend(link.args)
  636. assert results == [Constant(4)]
  637. def test_const_star_call(self):
  638. def g(a=1,b=2,c=3):
  639. pass
  640. def f():
  641. return g(1,*(2,3))
  642. graph = self.codetest(f)
  643. for block in graph.iterblocks():
  644. for op in block.operations:
  645. assert not op.opname == "call_args"
  646. def test_starstar_call(self):
  647. """Check that CALL_FUNCTION_KW and CALL_FUNCTION_VAR_KW raise a
  648. useful error.
  649. """
  650. def g(a, b, c):
  651. return a*b*c
  652. def f1():
  653. return g(**{'a':0})
  654. with py.test.raises(FlowingError) as excinfo:
  655. graph = self.codetest(f1)
  656. assert 'Dict-unpacking' in str(excinfo.value)
  657. def f2():
  658. return g(*(0,), **{'c':3})
  659. with py.test.raises(FlowingError) as excinfo:
  660. graph = self.codetest(f2)
  661. assert 'Dict-unpacking' in str(excinfo.value)
  662. def test_kwarg_call(self):
  663. def g(x):
  664. return x
  665. def f():
  666. return g(x=2)
  667. graph = self.codetest(f)
  668. for block in graph.iterblocks():
  669. for op in block.operations:
  670. assert op.opname == "call_args"
  671. assert op.args == map(Constant, [g, (0, ('x',), False), 2])
  672. def test_catch_importerror_1(self):
  673. def f():
  674. try:
  675. import rpython.this_does_not_exist
  676. except ImportError:
  677. return 1
  678. graph = self.codetest(f)
  679. simplify_graph(graph)
  680. self.show(graph)
  681. assert not graph.startblock.operations
  682. assert len(graph.startblock.exits) == 1
  683. assert graph.startblock.exits[0].target is graph.returnblock
  684. def test_catch_importerror_2(self):
  685. def f():
  686. try:
  687. from rpython import this_does_not_exist
  688. except ImportError:
  689. return 1
  690. graph = self.codetest(f)
  691. simplify_graph(graph)
  692. self.show(graph)
  693. assert not graph.startblock.operations
  694. assert len(graph.startblock.exits) == 1
  695. assert graph.startblock.exits[0].target is graph.returnblock
  696. def test_importerror_1(self):
  697. def f():
  698. import rpython.this_does_not_exist
  699. py.test.raises(ImportError, 'self.codetest(f)')
  700. def test_importerror_2(self):
  701. def f():
  702. from rpython import this_does_not_exist
  703. py.test.raises(ImportError, 'self.codetest(f)')
  704. def test_importerror_3(self):
  705. def f():
  706. import rpython.flowspace.test.cant_import
  707. e = py.test.raises(ImportError, 'self.codetest(f)')
  708. assert "some explanation here" in str(e.value)
  709. def test_relative_import(self):
  710. def f():
  711. from ..objspace import build_flow
  712. # Check that the function works in Python
  713. assert f() is None
  714. self.codetest(f)
  715. def test_mergeable(self):
  716. def myfunc(x):
  717. if x:
  718. from rpython.flowspace.flowcontext import BytecodeCorruption
  719. s = 12
  720. else:
  721. s = x.abc
  722. return x[s]
  723. graph = self.codetest(myfunc)
  724. def test_unichr_constfold(self):
  725. py.test.skip("not working")
  726. def myfunc():
  727. return unichr(1234)
  728. graph = self.codetest(myfunc)
  729. assert graph.startblock.exits[0].target is graph.returnblock
  730. def test_unicode_constfold(self):
  731. py.test.skip("not working for now")
  732. def myfunc():
  733. return unicode("1234")
  734. graph = self.codetest(myfunc)
  735. assert graph.startblock.exits[0].target is graph.returnblock
  736. def test_unicode(self):
  737. def myfunc(n):
  738. try:
  739. return unicode(chr(n))
  740. except UnicodeDecodeError:
  741. return None
  742. graph = self.codetest(myfunc)
  743. simplify_graph(graph)
  744. assert graph.startblock.canraise
  745. assert graph.startblock.exits[0].target is graph.returnblock
  746. assert graph.startblock.exits[1].target is graph.returnblock
  747. def test_getitem(self):
  748. def f(c, x):
  749. try:
  750. return c[x]
  751. except Exception:
  752. raise
  753. graph = self.codetest(f)
  754. simplify_graph(graph)
  755. assert self.all_operations(graph) == {'getitem_idx': 1}
  756. g = lambda: None
  757. def f(c, x):
  758. try:
  759. return c[x]
  760. finally:
  761. g()
  762. graph = self.codetest(f)
  763. simplify_graph(graph)
  764. assert self.all_operations(graph) == {'getitem_idx': 1,
  765. 'simple_call': 2}
  766. def f(c, x):
  767. try:
  768. return c[x]
  769. except IndexError:
  770. raise
  771. graph = self.codetest(f)
  772. simplify_graph(graph)
  773. assert self.all_operations(graph) == {'getitem_idx': 1}
  774. def f(c, x):
  775. try:
  776. return c[x]
  777. except KeyError:
  778. raise
  779. graph = self.codetest(f)
  780. simplify_graph(graph)
  781. assert self.all_operations(graph) == {'getitem': 1}
  782. def f(c, x):
  783. try:
  784. return c[x]
  785. except ValueError:
  786. raise
  787. graph = self.codetest(f)
  788. simplify_graph(graph)
  789. assert self.all_operations(graph) == {'getitem': 1}
  790. def f(c, x):
  791. try:
  792. return c[x]
  793. except Exception:
  794. return -1
  795. graph = self.codetest(f)
  796. simplify_graph(graph)
  797. self.show(graph)
  798. assert self.all_operations(graph) == {'getitem_idx': 1}
  799. def f(c, x):
  800. try:
  801. return c[x]
  802. except IndexError:
  803. return -1
  804. graph = self.codetest(f)
  805. simplify_graph(graph)
  806. assert self.all_operations(graph) == {'getitem_idx': 1}
  807. def f(c, x):
  808. try:
  809. return c[x]
  810. except KeyError:
  811. return -1
  812. graph = self.codetest(f)
  813. simplify_graph(graph)
  814. assert self.all_operations(graph) == {'getitem': 1}
  815. def f(c, x):
  816. try:
  817. return c[x]
  818. except ValueError:
  819. return -1
  820. graph = self.codetest(f)
  821. simplify_graph(graph)
  822. assert self.all_operations(graph) == {'getitem': 1}
  823. def test_delitem(self):
  824. def f(c, x):
  825. del c[x]
  826. graph = self.codetest(f)
  827. simplify_graph(graph)
  828. assert self.all_operations(graph) == {'delitem': 1}
  829. def test_context_manager(self):
  830. def f(c, x):
  831. with x:
  832. pass
  833. graph = self.codetest(f)
  834. # 2 method calls: x.__enter__() and x.__exit__(None, None, None)
  835. assert self.all_operations(graph) == {'getattr': 2,
  836. 'simple_call': 2}
  837. #
  838. def g(): pass
  839. def f(c, x):
  840. with x:
  841. res = g()
  842. return res
  843. graph = self.codetest(f)
  844. assert self.all_operations(graph) == {
  845. 'getattr': 2, # __enter__ and __exit__
  846. 'simple_call': 4, # __enter__, g and 2 possible calls to __exit__
  847. }
  848. def test_return_in_with(self):
  849. def f(x):
  850. with x:
  851. return 1
  852. graph = self.codetest(f)
  853. simplify_graph(graph)
  854. assert self.all_operations(graph) == {'getattr': 2, 'simple_call': 2}
  855. def test_break_in_with(self):
  856. def f(n, x):
  857. for i in range(n):
  858. with x:
  859. break
  860. return 1
  861. self.codetest(f)
  862. def monkey_patch_code(self, code, stacksize, flags, codestring, names, varnames):
  863. c = code
  864. return types.CodeType(c.co_argcount, c.co_nlocals, stacksize, flags,
  865. codestring, c.co_consts, names, varnames,
  866. c.co_filename, c.co_name, c.co_firstlineno,
  867. c.co_lnotab)
  868. def test_callmethod_opcode(self):
  869. """ Tests code generated by pypy-c compiled with CALL_METHOD
  870. bytecode
  871. """
  872. with patching_opcodes(CALL_METHOD=202, LOOKUP_METHOD=201):
  873. class X:
  874. def m(self):
  875. return 3
  876. def f():
  877. x = X()
  878. return x.m()
  879. # this code is generated by pypy-c when compiling above f
  880. pypy_code = 't\x00\x00\x83\x00\x00}\x00\x00|\x00\x00\xc9\x01\x00\xca\x00\x00S'
  881. new_c = self.monkey_patch_code(f.func_code, 3, 3, pypy_code, ('X', 'x', 'm'), ('x',))
  882. f2 = types.FunctionType(new_c, locals(), 'f')
  883. graph = self.codetest(f2)
  884. all_ops = self.all_operations(graph)
  885. assert all_ops['simple_call'] == 2
  886. assert all_ops['getattr'] == 1
  887. @py.test.mark.skipif('sys.version_info < (2, 7)')
  888. def test_build_list_from_arg_opcode(self):
  889. """ Tests code generated by pypy-c compiled with BUILD_LIST_FROM_ARG
  890. bytecode
  891. """
  892. with patching_opcodes(BUILD_LIST_FROM_ARG=203):
  893. def f():
  894. return [i for i in "abc"]
  895. # this code is generated by pypy-c when compiling above f
  896. pypy_code = 'd\x01\x00\xcb\x00\x00D]\x0c\x00}\x00\x00|\x00\x00^\x02\x00q\x07\x00S'
  897. new_c = self.monkey_patch_code(f.func_code, 3, 67, pypy_code, (),
  898. ('i',))
  899. f2 = types.FunctionType(new_c, locals(), 'f')
  900. graph = self.codetest(f2)
  901. all_ops = self.all_operations(graph)
  902. assert all_ops == {'newlist': 1, 'getattr': 1, 'simple_call': 1,
  903. 'iter': 1, 'next': 1}
  904. def test_dont_capture_RuntimeError(self):
  905. class Foo:
  906. def __hash__(self):
  907. return hash(self)
  908. foolist = [Foo()]
  909. def f():
  910. return foolist[0]
  911. py.test.raises(RuntimeError, "self.codetest(f)")
  912. def test_getslice_constfold(self):
  913. def check(f, expected):
  914. graph = self.codetest(f)
  915. assert graph.startblock.operations == []
  916. [link] = graph.startblock.exits
  917. assert link.target is graph.returnblock
  918. assert isinstance(link.args[0], Constant)
  919. assert link.args[0].value == expected
  920. def f1():
  921. s = 'hello'
  922. return s[:-2]
  923. check(f1, 'hel')
  924. def f2():
  925. s = 'hello'
  926. return s[:]
  927. check(f2, 'hello')
  928. def f3():
  929. s = 'hello'
  930. return s[-3:]
  931. check(f3, 'llo')
  932. def test_constfold_attribute_error(self):
  933. def f(x):
  934. try:
  935. "".invalid
  936. finally:
  937. if x and 0:
  938. raise TypeError()
  939. with py.test.raises(FlowingError) as excinfo:
  940. self.codetest(f)
  941. assert 'getattr' in str(excinfo.value)
  942. def test_constfold_exception(self):
  943. def f():
  944. return (3 + 2) / (4 - 2 * 2)
  945. with py.test.raises(FlowingError) as excinfo:
  946. self.codetest(f)
  947. assert 'div(5, 0)' in str(excinfo.value)
  948. def test_nonconstant_except(self):
  949. def f(exc_cls):
  950. try:
  951. raise AttributeError
  952. except exc_cls:
  953. pass
  954. with py.test.raises(FlowingError):
  955. self.codetest(f)
  956. def test__flowspace_rewrite_directly_as_(self):
  957. def g(x):
  958. pass
  959. def f(x):
  960. pass
  961. f._flowspace_rewrite_directly_as_ = g
  962. def h(x):
  963. f(x)
  964. graph = self.codetest(h)
  965. assert self.all_operations(graph) == {'simple_call': 1}
  966. for block in graph.iterblocks():
  967. if block.operations:
  968. op = block.operations[0]
  969. assert op.opname == 'simple_call'
  970. assert op.args[0] == Constant(g)
  971. def test_cannot_catch_special_exceptions(self):
  972. def f():
  973. try:
  974. f()
  975. except NotImplementedError:
  976. pass
  977. py.test.raises(FlowingError, "self.codetest(f)")
  978. #
  979. def f():
  980. try:
  981. f()
  982. except AssertionError:
  983. pass
  984. py.test.raises(FlowingError, "self.codetest(f)")
  985. def test_locals_dict(self):
  986. def f():
  987. x = 5
  988. return x
  989. exec "None"
  990. graph = self.codetest(f)
  991. assert len(graph.startblock.exits) == 1
  992. assert graph.startblock.exits[0].target == graph.returnblock
  993. def test_global_variable(self):
  994. def global_var_missing():
  995. return a
  996. with py.test.raises(FlowingError) as rex:
  997. self.codetest(global_var_missing)
  998. assert str(rex.exconly()).find("global variable 'a' undeclared")
  999. def test_eval(self):
  1000. exec("def f(): return a")
  1001. with py.test.raises(FlowingError):
  1002. self.codetest(f)
  1003. @py.test.mark.xfail(reason="closures aren't supported")
  1004. def test_cellvar_store(self):
  1005. def f():
  1006. x = 5
  1007. return x
  1008. lambda: x # turn x into a cell variable
  1009. graph = self.codetest(f)
  1010. assert len(graph.startblock.exits) == 1
  1011. assert graph.startblock.exits[0].target == graph.returnblock
  1012. @py.test.mark.xfail(reason="closures aren't supported")
  1013. def test_arg_as_cellvar(self):
  1014. def f(x, y, z):
  1015. a, b, c = 1, 2, 3
  1016. z = b
  1017. return z
  1018. lambda: (a, b, x, z) # make cell variables
  1019. graph = self.codetest(f)
  1020. assert len(graph.startblock.exits) == 1
  1021. assert graph.startblock.exits[0].target == graph.returnblock
  1022. assert not graph.startblock.operations
  1023. assert graph.startblock.exits[0].args[0].value == 2
  1024. def test_lambda(self):
  1025. def f():
  1026. g = lambda m, n: n*m
  1027. return g
  1028. graph = self.codetest(f)
  1029. assert len(graph.startblock.exits) == 1
  1030. assert graph.startblock.exits[0].target == graph.returnblock
  1031. g = graph.startblock.exits[0].args[0].value
  1032. assert g(4, 4) == 16
  1033. def test_lambda_with_defaults(self):
  1034. def f():
  1035. g = lambda m, n=5: n*m
  1036. return g
  1037. graph = self.codetest(f)
  1038. assert len(graph.startblock.exits) == 1
  1039. assert graph.startblock.exits[0].target == graph.returnblock
  1040. g = graph.startblock.exits[0].args[0].value
  1041. assert g(4) == 20
  1042. def f2(x):
  1043. g = lambda m, n=x: n*m
  1044. return g
  1045. with py.test.raises(FlowingError):
  1046. self.codetest(f2)
  1047. @py.test.mark.xfail(reason="closures aren't supported")
  1048. def test_closure(self):
  1049. def f():
  1050. m = 5
  1051. return lambda n: m * n
  1052. graph = self.codetest(f)
  1053. assert len(graph.startblock.exits) == 1
  1054. assert graph.startblock.exits[0].target == graph.returnblock
  1055. g = graph.startblock.exits[0].args[0].value
  1056. assert g(4) == 20
  1057. def test_closure_error(self):
  1058. def f():
  1059. m = 5
  1060. return lambda n: m * n
  1061. with py.test.raises(ValueError) as excinfo:
  1062. self.codetest(f)
  1063. assert "closure" in str(excinfo.value)
  1064. def test_unbound_local(self):
  1065. def f():
  1066. x += 1
  1067. with py.test.raises(FlowingError):
  1068. self.codetest(f)
  1069. def test_aug_assign(self):
  1070. # test for DUP_TOPX
  1071. lst = [2, 3, 4]
  1072. def f(x, y):
  1073. lst[x] += y
  1074. graph = self.codetest(f)
  1075. assert self.all_operations(graph) == {'getitem': 1,
  1076. 'inplace_add': 1,
  1077. 'setitem': 1}
  1078. def test_list_append(self):
  1079. def f(iterable):
  1080. return [5 for x in iterable]
  1081. graph = self.codetest(f)
  1082. assert self.all_operations(graph) == {'getattr': 1,
  1083. 'iter': 1, 'newlist': 1,
  1084. 'next': 1, 'simple_call': 1}
  1085. def test_mutate_const_list(self):
  1086. lst = list('abcdef')
  1087. def f():
  1088. lst[0] = 'x'
  1089. return lst
  1090. graph = self.codetest(f)
  1091. assert 'setitem' in self.all_operations(graph)
  1092. def test_sys_getattr(self):
  1093. def f():
  1094. import sys
  1095. return sys.modules
  1096. graph = self.codetest(f)
  1097. assert 'getattr' in self.all_operations(graph)
  1098. def test_sys_import_from(self):
  1099. def f():
  1100. from sys import modules
  1101. return modules
  1102. graph = self.codetest(f)
  1103. assert 'getattr' in self.all_operations(graph)
  1104. def test_empty_cell_unused(self):
  1105. def test(flag):
  1106. if flag:
  1107. b = 5
  1108. def g():
  1109. if flag:
  1110. return b
  1111. else:
  1112. return 1
  1113. return g
  1114. g1 = test(False)
  1115. graph = self.codetest(g1)
  1116. assert not self.all_operations(graph)
  1117. g2 = test(True)
  1118. graph = self.codetest(g2)
  1119. assert not self.all_operations(graph)
  1120. def test_empty_cell_error(self):
  1121. def test(flag):
  1122. if not flag:
  1123. b = 5
  1124. def g():
  1125. if flag:
  1126. return b
  1127. else:
  1128. return 1
  1129. return g
  1130. g = test(True)
  1131. with py.test.raises(FlowingError) as excinfo:
  1132. graph = self.codetest(g)
  1133. assert "Undefined closure variable 'b'" in str(excinfo.value)
  1134. def call_os_remove(msg):
  1135. os.remove(msg)
  1136. os.unlink(msg)
  1137. def test_call_os_remove(self):
  1138. x = self.codetest(self.call_os_remove)
  1139. simplify_graph(x)
  1140. self.show(x)
  1141. ops = x.startblock.operations
  1142. assert ops[0].opname == 'simple_call'
  1143. assert ops[0].args[0].value is os.unlink
  1144. assert ops[1].opname == 'simple_call'
  1145. assert ops[1].args[0].value is os.unlink
  1146. def test_rabspath(self):
  1147. import os.path
  1148. def f(s):
  1149. return os.path.abspath(s)
  1150. graph = self.codetest(f)
  1151. simplify_graph(graph)
  1152. ops = graph.startblock.operations
  1153. assert ops[0].opname == 'simple_call'
  1154. #
  1155. from rpython.rlib import rpath
  1156. assert ops[0].args[0].value is rpath.rabspath
  1157. def test_constfold_in(self):
  1158. def f():
  1159. if 'x' in "xyz":
  1160. return 5
  1161. else:
  1162. return 6
  1163. graph = self.codetest(f)
  1164. assert graph.startblock.operations == []
  1165. [link] = graph.startblock.exits
  1166. assert link.target is graph.returnblock
  1167. assert isinstance(link.args[0], Constant)
  1168. assert link.args[0].value == 5
  1169. def test_remove_dead_ops(self):
  1170. def f():
  1171. a = [1]
  1172. b = (a, a)
  1173. c = type(b)
  1174. graph = self.codetest(f)
  1175. simplify_graph(graph)
  1176. assert graph.startblock.operations == []
  1177. [link] = graph.startblock.exits
  1178. assert link.target is graph.returnblock
  1179. def test_not_combine(self):
  1180. def f(n):
  1181. t = not n
  1182. if not n:
  1183. t += 1
  1184. return t
  1185. graph = self.codetest(f)
  1186. simplify_graph(graph)
  1187. assert self.all_operations(graph) == {'bool': 1, 'inplace_add': 1}
  1188. def test_unexpected_builtin_function(self):
  1189. import itertools
  1190. e = py.test.raises(ValueError, build_flow, itertools.permutations)
  1191. assert ' is not RPython:' in str(e.value)
  1192. e = py.test.raises(ValueError, build_flow, itertools.tee)
  1193. assert ' is not RPython:' in str(e.value)
  1194. e = py.test.raises(ValueError, build_flow, Exception.__init__)
  1195. assert ' is not RPython:' in str(e.value)
  1196. DATA = {'x': 5,
  1197. 'y': 6}
  1198. def user_defined_function():
  1199. pass