blob: 794d104d5919bdffde44dbd4facd472c2810fae2 [file] [log] [blame]
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00001import dis
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00002import unittest
3
Nick Coghland6245172013-05-07 00:03:00 +10004from test.bytecode_helper import BytecodeTestCase
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00005
Serhiy Storchaka3f7e9aa2018-03-11 10:54:47 +02006def count_instr_recursively(f, opname):
7 count = 0
8 for instr in dis.get_instructions(f):
9 if instr.opname == opname:
10 count += 1
11 if hasattr(f, '__code__'):
12 f = f.__code__
13 for c in f.co_consts:
14 if hasattr(c, 'co_code'):
15 count += count_instr_recursively(c, opname)
16 return count
17
18
Nick Coghland6245172013-05-07 00:03:00 +100019class TestTranforms(BytecodeTestCase):
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000020
21 def test_unot(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000022 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE'
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000023 def unot(x):
24 if not x == 2:
25 del x
Nick Coghland6245172013-05-07 00:03:00 +100026 self.assertNotInBytecode(unot, 'UNARY_NOT')
27 self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE')
28 self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000029
30 def test_elim_inversion_of_is_or_in(self):
Nick Coghland6245172013-05-07 00:03:00 +100031 for line, cmp_op in (
32 ('not a is b', 'is not',),
33 ('not a in b', 'not in',),
34 ('not a is not b', 'is',),
35 ('not a not in b', 'in',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000036 ):
Nick Coghland6245172013-05-07 00:03:00 +100037 code = compile(line, '', 'single')
38 self.assertInBytecode(code, 'COMPARE_OP', cmp_op)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000039
Guido van Rossumcd16bf62007-06-13 18:07:49 +000040 def test_global_as_constant(self):
41 # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
Victor Stinner51d8c522016-02-08 17:57:02 +010042 def f():
43 x = None
44 x = None
Tim Peters66cb0182004-08-26 05:23:19 +000045 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010046 def g():
47 x = True
Guido van Rossumcd16bf62007-06-13 18:07:49 +000048 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010049 def h():
50 x = False
Guido van Rossumcd16bf62007-06-13 18:07:49 +000051 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010052
Nick Coghland6245172013-05-07 00:03:00 +100053 for func, elem in ((f, None), (g, True), (h, False)):
54 self.assertNotInBytecode(func, 'LOAD_GLOBAL')
55 self.assertInBytecode(func, 'LOAD_CONST', elem)
Victor Stinner51d8c522016-02-08 17:57:02 +010056
Guido van Rossumd8faa362007-04-27 19:54:29 +000057 def f():
58 'Adding a docstring made this test fail in Py2.5.0'
59 return None
Victor Stinner51d8c522016-02-08 17:57:02 +010060
Nick Coghland6245172013-05-07 00:03:00 +100061 self.assertNotInBytecode(f, 'LOAD_GLOBAL')
62 self.assertInBytecode(f, 'LOAD_CONST', None)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000063
64 def test_while_one(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000065 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000066 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000067 while 1:
68 pass
69 return list
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000070 for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
Nick Coghland6245172013-05-07 00:03:00 +100071 self.assertNotInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000072 for elem in ('JUMP_ABSOLUTE',):
Nick Coghland6245172013-05-07 00:03:00 +100073 self.assertInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000074
75 def test_pack_unpack(self):
76 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000077 ('a, = a,', 'LOAD_CONST',),
78 ('a, b = a, b', 'ROT_TWO',),
79 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000080 ):
Nick Coghland6245172013-05-07 00:03:00 +100081 code = compile(line,'','single')
82 self.assertInBytecode(code, elem)
83 self.assertNotInBytecode(code, 'BUILD_TUPLE')
84 self.assertNotInBytecode(code, 'UNPACK_TUPLE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000085
Raymond Hettinger2c31a052004-09-22 18:44:21 +000086 def test_folding_of_tuples_of_constants(self):
87 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +100088 ('a = 1,2,3', (1, 2, 3)),
89 ('("a","b","c")', ('a', 'b', 'c')),
90 ('a,b,c = 1,2,3', (1, 2, 3)),
91 ('(None, 1, None)', (None, 1, None)),
92 ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000093 ):
Nick Coghland6245172013-05-07 00:03:00 +100094 code = compile(line,'','single')
95 self.assertInBytecode(code, 'LOAD_CONST', elem)
96 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Raymond Hettinger2c31a052004-09-22 18:44:21 +000097
Antoine Pitrou17b880a2011-03-11 17:27:02 +010098 # Long tuples should be folded too.
Nick Coghland6245172013-05-07 00:03:00 +100099 code = compile(repr(tuple(range(10000))),'','single')
100 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100101 # One LOAD_CONST for the tuple, one for the None return value
Nick Coghland6245172013-05-07 00:03:00 +1000102 load_consts = [instr for instr in dis.get_instructions(code)
103 if instr.opname == 'LOAD_CONST']
104 self.assertEqual(len(load_consts), 2)
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100105
Raymond Hettinger23109ef2004-10-26 08:59:14 +0000106 # Bug 1053819: Tuple of constants misidentified when presented with:
107 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
108 # The following would segfault upon compilation
109 def crater():
110 (~[
111 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
112 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
113 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
114 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
115 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
116 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
117 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
118 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
119 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
120 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
121 ],)
122
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000123 def test_folding_of_lists_of_constants(self):
124 for line, elem in (
125 # in/not in constants with BUILD_LIST should be folded to a tuple:
Nick Coghland6245172013-05-07 00:03:00 +1000126 ('a in [1,2,3]', (1, 2, 3)),
127 ('a not in ["a","b","c"]', ('a', 'b', 'c')),
128 ('a in [None, 1, None]', (None, 1, None)),
129 ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000130 ):
Nick Coghland6245172013-05-07 00:03:00 +1000131 code = compile(line, '', 'single')
132 self.assertInBytecode(code, 'LOAD_CONST', elem)
133 self.assertNotInBytecode(code, 'BUILD_LIST')
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000134
135 def test_folding_of_sets_of_constants(self):
136 for line, elem in (
137 # in/not in constants with BUILD_SET should be folded to a frozenset:
138 ('a in {1,2,3}', frozenset({1, 2, 3})),
139 ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
140 ('a in {None, 1, None}', frozenset({1, None})),
141 ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
142 ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
143 ):
Nick Coghland6245172013-05-07 00:03:00 +1000144 code = compile(line, '', 'single')
145 self.assertNotInBytecode(code, 'BUILD_SET')
146 self.assertInBytecode(code, 'LOAD_CONST', elem)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000147
148 # Ensure that the resulting code actually works:
149 def f(a):
150 return a in {1, 2, 3}
151
152 def g(a):
153 return a not in {1, 2, 3}
154
155 self.assertTrue(f(3))
156 self.assertTrue(not f(4))
157
158 self.assertTrue(not g(3))
159 self.assertTrue(g(4))
160
161
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000162 def test_folding_of_binops_on_constants(self):
163 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000164 ('a = 2+3+4', 9), # chained fold
165 ('"@"*4', '@@@@'), # check string ops
166 ('a="abc" + "def"', 'abcdef'), # check string ops
167 ('a = 3**4', 81), # binary power
168 ('a = 3*4', 12), # binary multiply
169 ('a = 13//4', 3), # binary floor divide
170 ('a = 14%4', 2), # binary modulo
171 ('a = 2+3', 5), # binary add
172 ('a = 13-4', 9), # binary subtract
173 ('a = (12,13)[1]', 13), # binary subscr
174 ('a = 13 << 2', 52), # binary lshift
175 ('a = 13 >> 2', 3), # binary rshift
176 ('a = 13 & 7', 5), # binary and
177 ('a = 13 ^ 7', 10), # binary xor
178 ('a = 13 | 7', 15), # binary or
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000179 ):
Nick Coghland6245172013-05-07 00:03:00 +1000180 code = compile(line, '', 'single')
181 self.assertInBytecode(code, 'LOAD_CONST', elem)
182 for instr in dis.get_instructions(code):
183 self.assertFalse(instr.opname.startswith('BINARY_'))
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000184
185 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000186 code = compile('a=2+"b"', '', 'single')
187 self.assertInBytecode(code, 'LOAD_CONST', 2)
188 self.assertInBytecode(code, 'LOAD_CONST', 'b')
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000189
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000190 # Verify that large sequences do not result from folding
Serhiy Storchaka2e3f5702017-12-15 14:11:43 +0200191 code = compile('a="x"*10000', '', 'single')
192 self.assertInBytecode(code, 'LOAD_CONST', 10000)
193 self.assertNotIn("x"*10000, code.co_consts)
194 code = compile('a=1<<1000', '', 'single')
Nick Coghland6245172013-05-07 00:03:00 +1000195 self.assertInBytecode(code, 'LOAD_CONST', 1000)
Serhiy Storchaka2e3f5702017-12-15 14:11:43 +0200196 self.assertNotIn(1<<1000, code.co_consts)
197 code = compile('a=2**1000', '', 'single')
198 self.assertInBytecode(code, 'LOAD_CONST', 1000)
199 self.assertNotIn(2**1000, code.co_consts)
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000200
Ezio Melotti2df6a932011-04-15 16:38:34 +0300201 def test_binary_subscr_on_unicode(self):
202 # valid code get optimized
Nick Coghland6245172013-05-07 00:03:00 +1000203 code = compile('"foo"[0]', '', 'single')
204 self.assertInBytecode(code, 'LOAD_CONST', 'f')
205 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
206 code = compile('"\u0061\uffff"[1]', '', 'single')
207 self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
208 self.assertNotInBytecode(code,'BINARY_SUBSCR')
209
210 # With PEP 393, non-BMP char get optimized
211 code = compile('"\U00012345"[0]', '', 'single')
212 self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
213 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300214
215 # invalid code doesn't get optimized
216 # out of range
Nick Coghland6245172013-05-07 00:03:00 +1000217 code = compile('"fuu"[10]', '', 'single')
218 self.assertInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300219
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000220 def test_folding_of_unaryops_on_constants(self):
221 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000222 ('-0.5', -0.5), # unary negative
223 ('-0.0', -0.0), # -0.0
224 ('-(1.0-1.0)', -0.0), # -0.0 after folding
225 ('-0', 0), # -0
226 ('~-2', 1), # unary invert
227 ('+1', 1), # unary positive
Raymond Hettingerafd842f2005-02-20 12:46:54 +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('UNARY_'))
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000233
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000234 # Check that -0.0 works after marshaling
235 def negzero():
236 return -(1.0-1.0)
237
Nick Coghland6245172013-05-07 00:03:00 +1000238 for instr in dis.get_instructions(code):
239 self.assertFalse(instr.opname.startswith('UNARY_'))
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000240
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000241 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000242 for line, elem, opname in (
243 ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
244 ('~"abc"', 'abc', 'UNARY_INVERT'),
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000245 ):
Nick Coghland6245172013-05-07 00:03:00 +1000246 code = compile(line, '', 'single')
247 self.assertInBytecode(code, 'LOAD_CONST', elem)
248 self.assertInBytecode(code, opname)
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000249
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000250 def test_elim_extra_return(self):
251 # RETURN LOAD_CONST None RETURN --> RETURN
252 def f(x):
253 return x
Nick Coghland6245172013-05-07 00:03:00 +1000254 self.assertNotInBytecode(f, 'LOAD_CONST', None)
255 returns = [instr for instr in dis.get_instructions(f)
256 if instr.opname == 'RETURN_VALUE']
257 self.assertEqual(len(returns), 1)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000258
Thomas Wouters89f507f2006-12-13 04:49:30 +0000259 def test_elim_jump_to_return(self):
260 # JUMP_FORWARD to RETURN --> RETURN
261 def f(cond, true_value, false_value):
262 return true_value if cond else false_value
Nick Coghland6245172013-05-07 00:03:00 +1000263 self.assertNotInBytecode(f, 'JUMP_FORWARD')
264 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
265 returns = [instr for instr in dis.get_instructions(f)
266 if instr.opname == 'RETURN_VALUE']
267 self.assertEqual(len(returns), 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000268
269 def test_elim_jump_after_return1(self):
270 # Eliminate dead code: jumps immediately after returns can't be reached
271 def f(cond1, cond2):
272 if cond1: return 1
273 if cond2: return 2
274 while 1:
275 return 3
276 while 1:
277 if cond1: return 4
278 return 5
279 return 6
Nick Coghland6245172013-05-07 00:03:00 +1000280 self.assertNotInBytecode(f, 'JUMP_FORWARD')
281 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
282 returns = [instr for instr in dis.get_instructions(f)
283 if instr.opname == 'RETURN_VALUE']
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200284 self.assertLessEqual(len(returns), 6)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000285
286 def test_elim_jump_after_return2(self):
287 # Eliminate dead code: jumps immediately after returns can't be reached
288 def f(cond1, cond2):
289 while 1:
290 if cond1: return 4
Nick Coghland6245172013-05-07 00:03:00 +1000291 self.assertNotInBytecode(f, 'JUMP_FORWARD')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000292 # There should be one jump for the while loop.
Nick Coghland6245172013-05-07 00:03:00 +1000293 returns = [instr for instr in dis.get_instructions(f)
294 if instr.opname == 'JUMP_ABSOLUTE']
295 self.assertEqual(len(returns), 1)
296 returns = [instr for instr in dis.get_instructions(f)
297 if instr.opname == 'RETURN_VALUE']
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200298 self.assertLessEqual(len(returns), 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000299
Guido van Rossum0240b922007-02-26 21:23:50 +0000300 def test_make_function_doesnt_bail(self):
301 def f():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000302 def g()->1+1:
Guido van Rossum0240b922007-02-26 21:23:50 +0000303 pass
304 return g
Nick Coghland6245172013-05-07 00:03:00 +1000305 self.assertNotInBytecode(f, 'BINARY_ADD')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000306
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100307 def test_constant_folding(self):
308 # Issue #11244: aggressive constant folding.
309 exprs = [
Nick Coghland6245172013-05-07 00:03:00 +1000310 '3 * -5',
311 '-3 * 5',
312 '2 * (3 * 4)',
313 '(2 * 3) * 4',
314 '(-1, 2, 3)',
315 '(1, -2, 3)',
316 '(1, 2, -3)',
317 '(1, 2, -3) * 6',
318 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100319 ]
320 for e in exprs:
Nick Coghland6245172013-05-07 00:03:00 +1000321 code = compile(e, '', 'single')
322 for instr in dis.get_instructions(code):
323 self.assertFalse(instr.opname.startswith('UNARY_'))
324 self.assertFalse(instr.opname.startswith('BINARY_'))
325 self.assertFalse(instr.opname.startswith('BUILD_'))
326
Serhiy Storchaka3f7e9aa2018-03-11 10:54:47 +0200327 def test_in_literal_list(self):
328 def containtest():
329 return x in [a, b]
330 self.assertEqual(count_instr_recursively(containtest, 'BUILD_LIST'), 0)
331
332 def test_iterate_literal_list(self):
333 def forloop():
334 for x in [a, b]:
335 pass
336 self.assertEqual(count_instr_recursively(forloop, 'BUILD_LIST'), 0)
337
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100338
Raymond Hettinger0661e912011-03-15 15:03:36 -0700339class TestBuglets(unittest.TestCase):
340
Raymond Hettinger5bd75b82011-03-15 15:07:38 -0700341 def test_bug_11510(self):
342 # folded constant set optimization was commingled with the tuple
343 # unpacking optimization which would fail if the set had duplicate
344 # elements so that the set length was unexpected
345 def f():
346 x, y = {1, 1}
347 return x, y
348 with self.assertRaises(ValueError):
349 f()
Raymond Hettinger0661e912011-03-15 15:03:36 -0700350
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000351
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000352if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500353 unittest.main()