blob: 11a4d1740b8dcecb35982ea1fd1a9bf18b591053 [file] [log] [blame]
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00001import dis
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00002import unittest
3
Joannah Nanjekye92777d52019-09-12 10:02:59 +01004from test.support.bytecode_helper import BytecodeTestCase
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00005
Victor Stinner8f4ef3b2019-07-01 18:28:25 +02006
Serhiy Storchaka3f7e9aa2018-03-11 10:54:47 +02007def count_instr_recursively(f, opname):
8 count = 0
9 for instr in dis.get_instructions(f):
10 if instr.opname == opname:
11 count += 1
12 if hasattr(f, '__code__'):
13 f = f.__code__
14 for c in f.co_consts:
15 if hasattr(c, 'co_code'):
16 count += count_instr_recursively(c, opname)
17 return count
18
19
Nick Coghland6245172013-05-07 00:03:00 +100020class TestTranforms(BytecodeTestCase):
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000021
Pablo Galindo3498c642019-06-13 19:16:22 +010022 def check_jump_targets(self, code):
23 instructions = list(dis.get_instructions(code))
24 targets = {instr.offset: instr for instr in instructions}
25 for instr in instructions:
26 if 'JUMP_' not in instr.opname:
27 continue
28 tgt = targets[instr.argval]
29 # jump to unconditional jump
30 if tgt.opname in ('JUMP_ABSOLUTE', 'JUMP_FORWARD'):
31 self.fail(f'{instr.opname} at {instr.offset} '
32 f'jumps to {tgt.opname} at {tgt.offset}')
33 # unconditional jump to RETURN_VALUE
34 if (instr.opname in ('JUMP_ABSOLUTE', 'JUMP_FORWARD') and
35 tgt.opname == 'RETURN_VALUE'):
36 self.fail(f'{instr.opname} at {instr.offset} '
37 f'jumps to {tgt.opname} at {tgt.offset}')
38 # JUMP_IF_*_OR_POP jump to conditional jump
39 if '_OR_POP' in instr.opname and 'JUMP_IF_' in tgt.opname:
40 self.fail(f'{instr.opname} at {instr.offset} '
41 f'jumps to {tgt.opname} at {tgt.offset}')
42
T. Woutersc8165032019-09-28 16:49:15 +020043 def check_lnotab(self, code):
44 "Check that the lnotab byte offsets are sensible."
45 code = dis._get_code_object(code)
46 lnotab = list(dis.findlinestarts(code))
47 # Don't bother checking if the line info is sensible, because
48 # most of the line info we can get at comes from lnotab.
49 min_bytecode = min(t[0] for t in lnotab)
50 max_bytecode = max(t[0] for t in lnotab)
51 self.assertGreaterEqual(min_bytecode, 0)
52 self.assertLess(max_bytecode, len(code.co_code))
53 # This could conceivably test more (and probably should, as there
54 # aren't very many tests of lnotab), if peepholer wasn't scheduled
55 # to be replaced anyway.
56
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000057 def test_unot(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000058 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE'
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000059 def unot(x):
60 if not x == 2:
61 del x
Nick Coghland6245172013-05-07 00:03:00 +100062 self.assertNotInBytecode(unot, 'UNARY_NOT')
63 self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE')
64 self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE')
T. Woutersc8165032019-09-28 16:49:15 +020065 self.check_lnotab(unot)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000066
67 def test_elim_inversion_of_is_or_in(self):
Mark Shannon9af0e472020-01-14 10:12:45 +000068 for line, cmp_op, invert in (
69 ('not a is b', 'IS_OP', 1,),
70 ('not a is not b', 'IS_OP', 0,),
71 ('not a in b', 'CONTAINS_OP', 1,),
72 ('not a not in b', 'CONTAINS_OP', 0,),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000073 ):
Nick Coghland6245172013-05-07 00:03:00 +100074 code = compile(line, '', 'single')
Mark Shannon9af0e472020-01-14 10:12:45 +000075 self.assertInBytecode(code, cmp_op, invert)
T. Woutersc8165032019-09-28 16:49:15 +020076 self.check_lnotab(code)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000077
Guido van Rossumcd16bf62007-06-13 18:07:49 +000078 def test_global_as_constant(self):
79 # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
Victor Stinner51d8c522016-02-08 17:57:02 +010080 def f():
81 x = None
82 x = None
Tim Peters66cb0182004-08-26 05:23:19 +000083 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010084 def g():
85 x = True
Guido van Rossumcd16bf62007-06-13 18:07:49 +000086 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010087 def h():
88 x = False
Guido van Rossumcd16bf62007-06-13 18:07:49 +000089 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010090
Nick Coghland6245172013-05-07 00:03:00 +100091 for func, elem in ((f, None), (g, True), (h, False)):
92 self.assertNotInBytecode(func, 'LOAD_GLOBAL')
93 self.assertInBytecode(func, 'LOAD_CONST', elem)
T. Woutersc8165032019-09-28 16:49:15 +020094 self.check_lnotab(func)
Victor Stinner51d8c522016-02-08 17:57:02 +010095
Guido van Rossumd8faa362007-04-27 19:54:29 +000096 def f():
97 'Adding a docstring made this test fail in Py2.5.0'
98 return None
Victor Stinner51d8c522016-02-08 17:57:02 +010099
Nick Coghland6245172013-05-07 00:03:00 +1000100 self.assertNotInBytecode(f, 'LOAD_GLOBAL')
101 self.assertInBytecode(f, 'LOAD_CONST', None)
T. Woutersc8165032019-09-28 16:49:15 +0200102 self.check_lnotab(f)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000103
104 def test_while_one(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +0000105 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000106 def f():
Tim Peters66cb0182004-08-26 05:23:19 +0000107 while 1:
108 pass
109 return list
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +0000110 for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
Nick Coghland6245172013-05-07 00:03:00 +1000111 self.assertNotInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000112 for elem in ('JUMP_ABSOLUTE',):
Nick Coghland6245172013-05-07 00:03:00 +1000113 self.assertInBytecode(f, elem)
T. Woutersc8165032019-09-28 16:49:15 +0200114 self.check_lnotab(f)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000115
116 def test_pack_unpack(self):
117 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +0000118 ('a, = a,', 'LOAD_CONST',),
119 ('a, b = a, b', 'ROT_TWO',),
120 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000121 ):
Nick Coghland6245172013-05-07 00:03:00 +1000122 code = compile(line,'','single')
123 self.assertInBytecode(code, elem)
124 self.assertNotInBytecode(code, 'BUILD_TUPLE')
125 self.assertNotInBytecode(code, 'UNPACK_TUPLE')
T. Woutersc8165032019-09-28 16:49:15 +0200126 self.check_lnotab(code)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000127
Raymond Hettinger2c31a052004-09-22 18:44:21 +0000128 def test_folding_of_tuples_of_constants(self):
129 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000130 ('a = 1,2,3', (1, 2, 3)),
131 ('("a","b","c")', ('a', 'b', 'c')),
132 ('a,b,c = 1,2,3', (1, 2, 3)),
133 ('(None, 1, None)', (None, 1, None)),
134 ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
Raymond Hettinger2c31a052004-09-22 18:44:21 +0000135 ):
Nick Coghland6245172013-05-07 00:03:00 +1000136 code = compile(line,'','single')
137 self.assertInBytecode(code, 'LOAD_CONST', elem)
138 self.assertNotInBytecode(code, 'BUILD_TUPLE')
T. Woutersc8165032019-09-28 16:49:15 +0200139 self.check_lnotab(code)
Raymond Hettinger2c31a052004-09-22 18:44:21 +0000140
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100141 # Long tuples should be folded too.
Nick Coghland6245172013-05-07 00:03:00 +1000142 code = compile(repr(tuple(range(10000))),'','single')
143 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100144 # One LOAD_CONST for the tuple, one for the None return value
Nick Coghland6245172013-05-07 00:03:00 +1000145 load_consts = [instr for instr in dis.get_instructions(code)
146 if instr.opname == 'LOAD_CONST']
147 self.assertEqual(len(load_consts), 2)
T. Woutersc8165032019-09-28 16:49:15 +0200148 self.check_lnotab(code)
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100149
Raymond Hettinger23109ef2004-10-26 08:59:14 +0000150 # Bug 1053819: Tuple of constants misidentified when presented with:
151 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
152 # The following would segfault upon compilation
153 def crater():
154 (~[
155 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
156 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
157 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
158 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
159 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
160 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
161 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
162 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
163 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
164 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
165 ],)
T. Woutersc8165032019-09-28 16:49:15 +0200166 self.check_lnotab(crater)
Raymond Hettinger23109ef2004-10-26 08:59:14 +0000167
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000168 def test_folding_of_lists_of_constants(self):
169 for line, elem in (
170 # in/not in constants with BUILD_LIST should be folded to a tuple:
Nick Coghland6245172013-05-07 00:03:00 +1000171 ('a in [1,2,3]', (1, 2, 3)),
172 ('a not in ["a","b","c"]', ('a', 'b', 'c')),
173 ('a in [None, 1, None]', (None, 1, None)),
174 ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000175 ):
Nick Coghland6245172013-05-07 00:03:00 +1000176 code = compile(line, '', 'single')
177 self.assertInBytecode(code, 'LOAD_CONST', elem)
178 self.assertNotInBytecode(code, 'BUILD_LIST')
T. Woutersc8165032019-09-28 16:49:15 +0200179 self.check_lnotab(code)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000180
181 def test_folding_of_sets_of_constants(self):
182 for line, elem in (
183 # in/not in constants with BUILD_SET should be folded to a frozenset:
184 ('a in {1,2,3}', frozenset({1, 2, 3})),
185 ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
186 ('a in {None, 1, None}', frozenset({1, None})),
187 ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
188 ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
189 ):
Nick Coghland6245172013-05-07 00:03:00 +1000190 code = compile(line, '', 'single')
191 self.assertNotInBytecode(code, 'BUILD_SET')
192 self.assertInBytecode(code, 'LOAD_CONST', elem)
T. Woutersc8165032019-09-28 16:49:15 +0200193 self.check_lnotab(code)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000194
195 # Ensure that the resulting code actually works:
196 def f(a):
197 return a in {1, 2, 3}
198
199 def g(a):
200 return a not in {1, 2, 3}
201
202 self.assertTrue(f(3))
203 self.assertTrue(not f(4))
T. Woutersc8165032019-09-28 16:49:15 +0200204 self.check_lnotab(f)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000205
206 self.assertTrue(not g(3))
207 self.assertTrue(g(4))
T. Woutersc8165032019-09-28 16:49:15 +0200208 self.check_lnotab(g)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000209
210
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000211 def test_folding_of_binops_on_constants(self):
212 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000213 ('a = 2+3+4', 9), # chained fold
214 ('"@"*4', '@@@@'), # check string ops
215 ('a="abc" + "def"', 'abcdef'), # check string ops
216 ('a = 3**4', 81), # binary power
217 ('a = 3*4', 12), # binary multiply
218 ('a = 13//4', 3), # binary floor divide
219 ('a = 14%4', 2), # binary modulo
220 ('a = 2+3', 5), # binary add
221 ('a = 13-4', 9), # binary subtract
222 ('a = (12,13)[1]', 13), # binary subscr
223 ('a = 13 << 2', 52), # binary lshift
224 ('a = 13 >> 2', 3), # binary rshift
225 ('a = 13 & 7', 5), # binary and
226 ('a = 13 ^ 7', 10), # binary xor
227 ('a = 13 | 7', 15), # binary or
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000228 ):
Nick Coghland6245172013-05-07 00:03:00 +1000229 code = compile(line, '', 'single')
230 self.assertInBytecode(code, 'LOAD_CONST', elem)
231 for instr in dis.get_instructions(code):
232 self.assertFalse(instr.opname.startswith('BINARY_'))
T. Woutersc8165032019-09-28 16:49:15 +0200233 self.check_lnotab(code)
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000234
235 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000236 code = compile('a=2+"b"', '', 'single')
237 self.assertInBytecode(code, 'LOAD_CONST', 2)
238 self.assertInBytecode(code, 'LOAD_CONST', 'b')
T. Woutersc8165032019-09-28 16:49:15 +0200239 self.check_lnotab(code)
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000240
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000241 # Verify that large sequences do not result from folding
Serhiy Storchaka2e3f5702017-12-15 14:11:43 +0200242 code = compile('a="x"*10000', '', 'single')
243 self.assertInBytecode(code, 'LOAD_CONST', 10000)
244 self.assertNotIn("x"*10000, code.co_consts)
T. Woutersc8165032019-09-28 16:49:15 +0200245 self.check_lnotab(code)
Serhiy Storchaka2e3f5702017-12-15 14:11:43 +0200246 code = compile('a=1<<1000', '', 'single')
Nick Coghland6245172013-05-07 00:03:00 +1000247 self.assertInBytecode(code, 'LOAD_CONST', 1000)
Serhiy Storchaka2e3f5702017-12-15 14:11:43 +0200248 self.assertNotIn(1<<1000, code.co_consts)
T. Woutersc8165032019-09-28 16:49:15 +0200249 self.check_lnotab(code)
Serhiy Storchaka2e3f5702017-12-15 14:11:43 +0200250 code = compile('a=2**1000', '', 'single')
251 self.assertInBytecode(code, 'LOAD_CONST', 1000)
252 self.assertNotIn(2**1000, code.co_consts)
T. Woutersc8165032019-09-28 16:49:15 +0200253 self.check_lnotab(code)
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000254
Ezio Melotti2df6a932011-04-15 16:38:34 +0300255 def test_binary_subscr_on_unicode(self):
256 # valid code get optimized
Nick Coghland6245172013-05-07 00:03:00 +1000257 code = compile('"foo"[0]', '', 'single')
258 self.assertInBytecode(code, 'LOAD_CONST', 'f')
259 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
T. Woutersc8165032019-09-28 16:49:15 +0200260 self.check_lnotab(code)
Nick Coghland6245172013-05-07 00:03:00 +1000261 code = compile('"\u0061\uffff"[1]', '', 'single')
262 self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
263 self.assertNotInBytecode(code,'BINARY_SUBSCR')
T. Woutersc8165032019-09-28 16:49:15 +0200264 self.check_lnotab(code)
Nick Coghland6245172013-05-07 00:03:00 +1000265
266 # With PEP 393, non-BMP char get optimized
267 code = compile('"\U00012345"[0]', '', 'single')
268 self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
269 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
T. Woutersc8165032019-09-28 16:49:15 +0200270 self.check_lnotab(code)
Ezio Melotti2df6a932011-04-15 16:38:34 +0300271
272 # invalid code doesn't get optimized
273 # out of range
Nick Coghland6245172013-05-07 00:03:00 +1000274 code = compile('"fuu"[10]', '', 'single')
275 self.assertInBytecode(code, 'BINARY_SUBSCR')
T. Woutersc8165032019-09-28 16:49:15 +0200276 self.check_lnotab(code)
Ezio Melotti2df6a932011-04-15 16:38:34 +0300277
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000278 def test_folding_of_unaryops_on_constants(self):
279 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000280 ('-0.5', -0.5), # unary negative
281 ('-0.0', -0.0), # -0.0
282 ('-(1.0-1.0)', -0.0), # -0.0 after folding
283 ('-0', 0), # -0
284 ('~-2', 1), # unary invert
285 ('+1', 1), # unary positive
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000286 ):
Nick Coghland6245172013-05-07 00:03:00 +1000287 code = compile(line, '', 'single')
288 self.assertInBytecode(code, 'LOAD_CONST', elem)
289 for instr in dis.get_instructions(code):
290 self.assertFalse(instr.opname.startswith('UNARY_'))
T. Woutersc8165032019-09-28 16:49:15 +0200291 self.check_lnotab(code)
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000292
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000293 # Check that -0.0 works after marshaling
294 def negzero():
295 return -(1.0-1.0)
296
T. Woutersc8165032019-09-28 16:49:15 +0200297 for instr in dis.get_instructions(negzero):
Nick Coghland6245172013-05-07 00:03:00 +1000298 self.assertFalse(instr.opname.startswith('UNARY_'))
T. Woutersc8165032019-09-28 16:49:15 +0200299 self.check_lnotab(negzero)
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000300
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000301 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000302 for line, elem, opname in (
303 ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
304 ('~"abc"', 'abc', 'UNARY_INVERT'),
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000305 ):
Nick Coghland6245172013-05-07 00:03:00 +1000306 code = compile(line, '', 'single')
307 self.assertInBytecode(code, 'LOAD_CONST', elem)
308 self.assertInBytecode(code, opname)
T. Woutersc8165032019-09-28 16:49:15 +0200309 self.check_lnotab(code)
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000310
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000311 def test_elim_extra_return(self):
312 # RETURN LOAD_CONST None RETURN --> RETURN
313 def f(x):
314 return x
Nick Coghland6245172013-05-07 00:03:00 +1000315 self.assertNotInBytecode(f, 'LOAD_CONST', None)
316 returns = [instr for instr in dis.get_instructions(f)
317 if instr.opname == 'RETURN_VALUE']
318 self.assertEqual(len(returns), 1)
T. Woutersc8165032019-09-28 16:49:15 +0200319 self.check_lnotab(f)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000320
Thomas Wouters89f507f2006-12-13 04:49:30 +0000321 def test_elim_jump_to_return(self):
322 # JUMP_FORWARD to RETURN --> RETURN
323 def f(cond, true_value, false_value):
Pablo Galindo3498c642019-06-13 19:16:22 +0100324 # Intentionally use two-line expression to test issue37213.
325 return (true_value if cond
326 else false_value)
327 self.check_jump_targets(f)
Nick Coghland6245172013-05-07 00:03:00 +1000328 self.assertNotInBytecode(f, 'JUMP_FORWARD')
329 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
330 returns = [instr for instr in dis.get_instructions(f)
331 if instr.opname == 'RETURN_VALUE']
332 self.assertEqual(len(returns), 2)
T. Woutersc8165032019-09-28 16:49:15 +0200333 self.check_lnotab(f)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000334
Pablo Galindo3498c642019-06-13 19:16:22 +0100335 def test_elim_jump_to_uncond_jump(self):
336 # POP_JUMP_IF_FALSE to JUMP_FORWARD --> POP_JUMP_IF_FALSE to non-jump
337 def f():
338 if a:
339 # Intentionally use two-line expression to test issue37213.
340 if (c
341 or d):
342 foo()
343 else:
344 baz()
345 self.check_jump_targets(f)
T. Woutersc8165032019-09-28 16:49:15 +0200346 self.check_lnotab(f)
Pablo Galindo3498c642019-06-13 19:16:22 +0100347
348 def test_elim_jump_to_uncond_jump2(self):
349 # POP_JUMP_IF_FALSE to JUMP_ABSOLUTE --> POP_JUMP_IF_FALSE to non-jump
350 def f():
351 while a:
352 # Intentionally use two-line expression to test issue37213.
353 if (c
354 or d):
355 a = foo()
356 self.check_jump_targets(f)
T. Woutersc8165032019-09-28 16:49:15 +0200357 self.check_lnotab(f)
Pablo Galindo3498c642019-06-13 19:16:22 +0100358
359 def test_elim_jump_to_uncond_jump3(self):
360 # Intentionally use two-line expressions to test issue37213.
361 # JUMP_IF_FALSE_OR_POP to JUMP_IF_FALSE_OR_POP --> JUMP_IF_FALSE_OR_POP to non-jump
362 def f(a, b, c):
363 return ((a and b)
364 and c)
365 self.check_jump_targets(f)
T. Woutersc8165032019-09-28 16:49:15 +0200366 self.check_lnotab(f)
Pablo Galindo3498c642019-06-13 19:16:22 +0100367 self.assertEqual(count_instr_recursively(f, 'JUMP_IF_FALSE_OR_POP'), 2)
368 # JUMP_IF_TRUE_OR_POP to JUMP_IF_TRUE_OR_POP --> JUMP_IF_TRUE_OR_POP to non-jump
369 def f(a, b, c):
370 return ((a or b)
371 or c)
372 self.check_jump_targets(f)
T. Woutersc8165032019-09-28 16:49:15 +0200373 self.check_lnotab(f)
Pablo Galindo3498c642019-06-13 19:16:22 +0100374 self.assertEqual(count_instr_recursively(f, 'JUMP_IF_TRUE_OR_POP'), 2)
375 # JUMP_IF_FALSE_OR_POP to JUMP_IF_TRUE_OR_POP --> POP_JUMP_IF_FALSE to non-jump
376 def f(a, b, c):
377 return ((a and b)
378 or c)
379 self.check_jump_targets(f)
T. Woutersc8165032019-09-28 16:49:15 +0200380 self.check_lnotab(f)
Pablo Galindo3498c642019-06-13 19:16:22 +0100381 self.assertNotInBytecode(f, 'JUMP_IF_FALSE_OR_POP')
382 self.assertInBytecode(f, 'JUMP_IF_TRUE_OR_POP')
383 self.assertInBytecode(f, 'POP_JUMP_IF_FALSE')
384 # JUMP_IF_TRUE_OR_POP to JUMP_IF_FALSE_OR_POP --> POP_JUMP_IF_TRUE to non-jump
385 def f(a, b, c):
386 return ((a or b)
387 and c)
388 self.check_jump_targets(f)
T. Woutersc8165032019-09-28 16:49:15 +0200389 self.check_lnotab(f)
Pablo Galindo3498c642019-06-13 19:16:22 +0100390 self.assertNotInBytecode(f, 'JUMP_IF_TRUE_OR_POP')
391 self.assertInBytecode(f, 'JUMP_IF_FALSE_OR_POP')
392 self.assertInBytecode(f, 'POP_JUMP_IF_TRUE')
393
Thomas Wouters89f507f2006-12-13 04:49:30 +0000394 def test_elim_jump_after_return1(self):
395 # Eliminate dead code: jumps immediately after returns can't be reached
396 def f(cond1, cond2):
397 if cond1: return 1
398 if cond2: return 2
399 while 1:
400 return 3
401 while 1:
402 if cond1: return 4
403 return 5
404 return 6
Nick Coghland6245172013-05-07 00:03:00 +1000405 self.assertNotInBytecode(f, 'JUMP_FORWARD')
406 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
407 returns = [instr for instr in dis.get_instructions(f)
408 if instr.opname == 'RETURN_VALUE']
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200409 self.assertLessEqual(len(returns), 6)
T. Woutersc8165032019-09-28 16:49:15 +0200410 self.check_lnotab(f)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000411
Guido van Rossum0240b922007-02-26 21:23:50 +0000412 def test_make_function_doesnt_bail(self):
413 def f():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000414 def g()->1+1:
Guido van Rossum0240b922007-02-26 21:23:50 +0000415 pass
416 return g
Nick Coghland6245172013-05-07 00:03:00 +1000417 self.assertNotInBytecode(f, 'BINARY_ADD')
T. Woutersc8165032019-09-28 16:49:15 +0200418 self.check_lnotab(f)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000419
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100420 def test_constant_folding(self):
421 # Issue #11244: aggressive constant folding.
422 exprs = [
Nick Coghland6245172013-05-07 00:03:00 +1000423 '3 * -5',
424 '-3 * 5',
425 '2 * (3 * 4)',
426 '(2 * 3) * 4',
427 '(-1, 2, 3)',
428 '(1, -2, 3)',
429 '(1, 2, -3)',
430 '(1, 2, -3) * 6',
431 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100432 ]
433 for e in exprs:
Nick Coghland6245172013-05-07 00:03:00 +1000434 code = compile(e, '', 'single')
435 for instr in dis.get_instructions(code):
436 self.assertFalse(instr.opname.startswith('UNARY_'))
437 self.assertFalse(instr.opname.startswith('BINARY_'))
438 self.assertFalse(instr.opname.startswith('BUILD_'))
T. Woutersc8165032019-09-28 16:49:15 +0200439 self.check_lnotab(code)
Nick Coghland6245172013-05-07 00:03:00 +1000440
Serhiy Storchaka3f7e9aa2018-03-11 10:54:47 +0200441 def test_in_literal_list(self):
442 def containtest():
443 return x in [a, b]
444 self.assertEqual(count_instr_recursively(containtest, 'BUILD_LIST'), 0)
T. Woutersc8165032019-09-28 16:49:15 +0200445 self.check_lnotab(containtest)
Serhiy Storchaka3f7e9aa2018-03-11 10:54:47 +0200446
447 def test_iterate_literal_list(self):
448 def forloop():
449 for x in [a, b]:
450 pass
451 self.assertEqual(count_instr_recursively(forloop, 'BUILD_LIST'), 0)
T. Woutersc8165032019-09-28 16:49:15 +0200452 self.check_lnotab(forloop)
Serhiy Storchaka3f7e9aa2018-03-11 10:54:47 +0200453
Pablo Galindo05f83182019-06-14 06:54:53 +0100454 def test_condition_with_binop_with_bools(self):
455 def f():
456 if True or False:
457 return 1
458 return 0
459 self.assertEqual(f(), 1)
T. Woutersc8165032019-09-28 16:49:15 +0200460 self.check_lnotab(f)
Pablo Galindo05f83182019-06-14 06:54:53 +0100461
Pablo Galindo1e615042019-06-20 22:17:03 +0100462 def test_if_with_if_expression(self):
463 # Check bpo-37289
464 def f(x):
465 if (True if x else False):
466 return True
467 return False
468 self.assertTrue(f(True))
T. Woutersc8165032019-09-28 16:49:15 +0200469 self.check_lnotab(f)
470
471 def test_trailing_nops(self):
472 # Check the lnotab of a function that even after trivial
473 # optimization has trailing nops, which the lnotab adjustment has to
474 # handle properly (bpo-38115).
475 def f(x):
476 while 1:
477 return 3
478 while 1:
479 return 5
480 return 6
481 self.check_lnotab(f)
Pablo Galindo1e615042019-06-20 22:17:03 +0100482
Serhiy Storchaka8c579b12020-02-12 12:18:59 +0200483 def test_assignment_idiom_in_comprehensions(self):
484 def listcomp():
485 return [y for x in a for y in [f(x)]]
486 self.assertEqual(count_instr_recursively(listcomp, 'FOR_ITER'), 1)
487 def setcomp():
488 return {y for x in a for y in [f(x)]}
489 self.assertEqual(count_instr_recursively(setcomp, 'FOR_ITER'), 1)
490 def dictcomp():
491 return {y: y for x in a for y in [f(x)]}
492 self.assertEqual(count_instr_recursively(dictcomp, 'FOR_ITER'), 1)
493 def genexpr():
494 return (y for x in a for y in [f(x)])
495 self.assertEqual(count_instr_recursively(genexpr, 'FOR_ITER'), 1)
496
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100497
Raymond Hettinger0661e912011-03-15 15:03:36 -0700498class TestBuglets(unittest.TestCase):
499
Raymond Hettinger5bd75b82011-03-15 15:07:38 -0700500 def test_bug_11510(self):
501 # folded constant set optimization was commingled with the tuple
502 # unpacking optimization which would fail if the set had duplicate
503 # elements so that the set length was unexpected
504 def f():
505 x, y = {1, 1}
506 return x, y
507 with self.assertRaises(ValueError):
508 f()
Raymond Hettinger0661e912011-03-15 15:03:36 -0700509
Mark Shannonb52432c2020-10-22 16:42:26 +0100510 def test_bpo_42057(self):
511 for i in range(10):
512 try:
513 raise Exception
514 except Exception or Exception:
515 pass
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000516
Brandt Buchera89bbde2021-11-11 13:52:43 -0800517 def test_bpo_45773_pop_jump_if_true(self):
518 compile("while True or spam: pass", "<test>", "exec")
519
520 def test_bpo_45773_pop_jump_if_false(self):
521 compile("while True or not spam: pass", "<test>", "exec")
522
523
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000524if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500525 unittest.main()