blob: 0cc1e92907b52b8c68cc0bcebd55cfa75935ce98 [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
Nick Coghland6245172013-05-07 00:03:00 +10006class TestTranforms(BytecodeTestCase):
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00007
8 def test_unot(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +00009 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE'
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000010 def unot(x):
11 if not x == 2:
12 del x
Nick Coghland6245172013-05-07 00:03:00 +100013 self.assertNotInBytecode(unot, 'UNARY_NOT')
14 self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE')
15 self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000016
17 def test_elim_inversion_of_is_or_in(self):
Nick Coghland6245172013-05-07 00:03:00 +100018 for line, cmp_op in (
19 ('not a is b', 'is not',),
20 ('not a in b', 'not in',),
21 ('not a is not b', 'is',),
22 ('not a not in b', 'in',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000023 ):
Nick Coghland6245172013-05-07 00:03:00 +100024 code = compile(line, '', 'single')
25 self.assertInBytecode(code, 'COMPARE_OP', cmp_op)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000026
Guido van Rossumcd16bf62007-06-13 18:07:49 +000027 def test_global_as_constant(self):
28 # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
Victor Stinner51d8c522016-02-08 17:57:02 +010029 def f():
30 x = None
31 x = None
Tim Peters66cb0182004-08-26 05:23:19 +000032 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010033 def g():
34 x = True
Guido van Rossumcd16bf62007-06-13 18:07:49 +000035 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010036 def h():
37 x = False
Guido van Rossumcd16bf62007-06-13 18:07:49 +000038 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010039
Nick Coghland6245172013-05-07 00:03:00 +100040 for func, elem in ((f, None), (g, True), (h, False)):
41 self.assertNotInBytecode(func, 'LOAD_GLOBAL')
42 self.assertInBytecode(func, 'LOAD_CONST', elem)
Victor Stinner51d8c522016-02-08 17:57:02 +010043
Guido van Rossumd8faa362007-04-27 19:54:29 +000044 def f():
45 'Adding a docstring made this test fail in Py2.5.0'
46 return None
Victor Stinner51d8c522016-02-08 17:57:02 +010047
Nick Coghland6245172013-05-07 00:03:00 +100048 self.assertNotInBytecode(f, 'LOAD_GLOBAL')
49 self.assertInBytecode(f, 'LOAD_CONST', None)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000050
51 def test_while_one(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000052 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000053 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000054 while 1:
55 pass
56 return list
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000057 for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
Nick Coghland6245172013-05-07 00:03:00 +100058 self.assertNotInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000059 for elem in ('JUMP_ABSOLUTE',):
Nick Coghland6245172013-05-07 00:03:00 +100060 self.assertInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000061
62 def test_pack_unpack(self):
63 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000064 ('a, = a,', 'LOAD_CONST',),
65 ('a, b = a, b', 'ROT_TWO',),
66 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000067 ):
Nick Coghland6245172013-05-07 00:03:00 +100068 code = compile(line,'','single')
69 self.assertInBytecode(code, elem)
70 self.assertNotInBytecode(code, 'BUILD_TUPLE')
71 self.assertNotInBytecode(code, 'UNPACK_TUPLE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000072
Raymond Hettinger2c31a052004-09-22 18:44:21 +000073 def test_folding_of_tuples_of_constants(self):
74 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +100075 ('a = 1,2,3', (1, 2, 3)),
76 ('("a","b","c")', ('a', 'b', 'c')),
77 ('a,b,c = 1,2,3', (1, 2, 3)),
78 ('(None, 1, None)', (None, 1, None)),
79 ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000080 ):
Nick Coghland6245172013-05-07 00:03:00 +100081 code = compile(line,'','single')
82 self.assertInBytecode(code, 'LOAD_CONST', elem)
83 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Raymond Hettinger2c31a052004-09-22 18:44:21 +000084
Antoine Pitrou17b880a2011-03-11 17:27:02 +010085 # Long tuples should be folded too.
Nick Coghland6245172013-05-07 00:03:00 +100086 code = compile(repr(tuple(range(10000))),'','single')
87 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Antoine Pitrou17b880a2011-03-11 17:27:02 +010088 # One LOAD_CONST for the tuple, one for the None return value
Nick Coghland6245172013-05-07 00:03:00 +100089 load_consts = [instr for instr in dis.get_instructions(code)
90 if instr.opname == 'LOAD_CONST']
91 self.assertEqual(len(load_consts), 2)
Antoine Pitrou17b880a2011-03-11 17:27:02 +010092
Raymond Hettinger23109ef2004-10-26 08:59:14 +000093 # Bug 1053819: Tuple of constants misidentified when presented with:
94 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
95 # The following would segfault upon compilation
96 def crater():
97 (~[
98 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
99 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
100 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
101 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
102 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
103 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
104 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
105 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
106 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
107 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
108 ],)
109
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000110 def test_folding_of_lists_of_constants(self):
111 for line, elem in (
112 # in/not in constants with BUILD_LIST should be folded to a tuple:
Nick Coghland6245172013-05-07 00:03:00 +1000113 ('a in [1,2,3]', (1, 2, 3)),
114 ('a not in ["a","b","c"]', ('a', 'b', 'c')),
115 ('a in [None, 1, None]', (None, 1, None)),
116 ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000117 ):
Nick Coghland6245172013-05-07 00:03:00 +1000118 code = compile(line, '', 'single')
119 self.assertInBytecode(code, 'LOAD_CONST', elem)
120 self.assertNotInBytecode(code, 'BUILD_LIST')
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000121
122 def test_folding_of_sets_of_constants(self):
123 for line, elem in (
124 # in/not in constants with BUILD_SET should be folded to a frozenset:
125 ('a in {1,2,3}', frozenset({1, 2, 3})),
126 ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
127 ('a in {None, 1, None}', frozenset({1, None})),
128 ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
129 ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
130 ):
Nick Coghland6245172013-05-07 00:03:00 +1000131 code = compile(line, '', 'single')
132 self.assertNotInBytecode(code, 'BUILD_SET')
133 self.assertInBytecode(code, 'LOAD_CONST', elem)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000134
135 # Ensure that the resulting code actually works:
136 def f(a):
137 return a in {1, 2, 3}
138
139 def g(a):
140 return a not in {1, 2, 3}
141
142 self.assertTrue(f(3))
143 self.assertTrue(not f(4))
144
145 self.assertTrue(not g(3))
146 self.assertTrue(g(4))
147
148
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000149 def test_folding_of_binops_on_constants(self):
150 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000151 ('a = 2+3+4', 9), # chained fold
152 ('"@"*4', '@@@@'), # check string ops
153 ('a="abc" + "def"', 'abcdef'), # check string ops
154 ('a = 3**4', 81), # binary power
155 ('a = 3*4', 12), # binary multiply
156 ('a = 13//4', 3), # binary floor divide
157 ('a = 14%4', 2), # binary modulo
158 ('a = 2+3', 5), # binary add
159 ('a = 13-4', 9), # binary subtract
160 ('a = (12,13)[1]', 13), # binary subscr
161 ('a = 13 << 2', 52), # binary lshift
162 ('a = 13 >> 2', 3), # binary rshift
163 ('a = 13 & 7', 5), # binary and
164 ('a = 13 ^ 7', 10), # binary xor
165 ('a = 13 | 7', 15), # binary or
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000166 ):
Nick Coghland6245172013-05-07 00:03:00 +1000167 code = compile(line, '', 'single')
168 self.assertInBytecode(code, 'LOAD_CONST', elem)
169 for instr in dis.get_instructions(code):
170 self.assertFalse(instr.opname.startswith('BINARY_'))
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000171
172 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000173 code = compile('a=2+"b"', '', 'single')
174 self.assertInBytecode(code, 'LOAD_CONST', 2)
175 self.assertInBytecode(code, 'LOAD_CONST', 'b')
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000176
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000177 # Verify that large sequences do not result from folding
Serhiy Storchaka2e3f5702017-12-15 14:11:43 +0200178 code = compile('a="x"*10000', '', 'single')
179 self.assertInBytecode(code, 'LOAD_CONST', 10000)
180 self.assertNotIn("x"*10000, code.co_consts)
181 code = compile('a=1<<1000', '', 'single')
Nick Coghland6245172013-05-07 00:03:00 +1000182 self.assertInBytecode(code, 'LOAD_CONST', 1000)
Serhiy Storchaka2e3f5702017-12-15 14:11:43 +0200183 self.assertNotIn(1<<1000, code.co_consts)
184 code = compile('a=2**1000', '', 'single')
185 self.assertInBytecode(code, 'LOAD_CONST', 1000)
186 self.assertNotIn(2**1000, code.co_consts)
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000187
Ezio Melotti2df6a932011-04-15 16:38:34 +0300188 def test_binary_subscr_on_unicode(self):
189 # valid code get optimized
Nick Coghland6245172013-05-07 00:03:00 +1000190 code = compile('"foo"[0]', '', 'single')
191 self.assertInBytecode(code, 'LOAD_CONST', 'f')
192 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
193 code = compile('"\u0061\uffff"[1]', '', 'single')
194 self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
195 self.assertNotInBytecode(code,'BINARY_SUBSCR')
196
197 # With PEP 393, non-BMP char get optimized
198 code = compile('"\U00012345"[0]', '', 'single')
199 self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
200 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300201
202 # invalid code doesn't get optimized
203 # out of range
Nick Coghland6245172013-05-07 00:03:00 +1000204 code = compile('"fuu"[10]', '', 'single')
205 self.assertInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300206
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000207 def test_folding_of_unaryops_on_constants(self):
208 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000209 ('-0.5', -0.5), # unary negative
210 ('-0.0', -0.0), # -0.0
211 ('-(1.0-1.0)', -0.0), # -0.0 after folding
212 ('-0', 0), # -0
213 ('~-2', 1), # unary invert
214 ('+1', 1), # unary positive
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000215 ):
Nick Coghland6245172013-05-07 00:03:00 +1000216 code = compile(line, '', 'single')
217 self.assertInBytecode(code, 'LOAD_CONST', elem)
218 for instr in dis.get_instructions(code):
219 self.assertFalse(instr.opname.startswith('UNARY_'))
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000220
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000221 # Check that -0.0 works after marshaling
222 def negzero():
223 return -(1.0-1.0)
224
Nick Coghland6245172013-05-07 00:03:00 +1000225 for instr in dis.get_instructions(code):
226 self.assertFalse(instr.opname.startswith('UNARY_'))
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000227
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000228 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000229 for line, elem, opname in (
230 ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
231 ('~"abc"', 'abc', 'UNARY_INVERT'),
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000232 ):
Nick Coghland6245172013-05-07 00:03:00 +1000233 code = compile(line, '', 'single')
234 self.assertInBytecode(code, 'LOAD_CONST', elem)
235 self.assertInBytecode(code, opname)
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000236
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000237 def test_elim_extra_return(self):
238 # RETURN LOAD_CONST None RETURN --> RETURN
239 def f(x):
240 return x
Nick Coghland6245172013-05-07 00:03:00 +1000241 self.assertNotInBytecode(f, 'LOAD_CONST', None)
242 returns = [instr for instr in dis.get_instructions(f)
243 if instr.opname == 'RETURN_VALUE']
244 self.assertEqual(len(returns), 1)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000245
Thomas Wouters89f507f2006-12-13 04:49:30 +0000246 def test_elim_jump_to_return(self):
247 # JUMP_FORWARD to RETURN --> RETURN
248 def f(cond, true_value, false_value):
249 return true_value if cond else false_value
Nick Coghland6245172013-05-07 00:03:00 +1000250 self.assertNotInBytecode(f, 'JUMP_FORWARD')
251 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
252 returns = [instr for instr in dis.get_instructions(f)
253 if instr.opname == 'RETURN_VALUE']
254 self.assertEqual(len(returns), 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000255
256 def test_elim_jump_after_return1(self):
257 # Eliminate dead code: jumps immediately after returns can't be reached
258 def f(cond1, cond2):
259 if cond1: return 1
260 if cond2: return 2
261 while 1:
262 return 3
263 while 1:
264 if cond1: return 4
265 return 5
266 return 6
Nick Coghland6245172013-05-07 00:03:00 +1000267 self.assertNotInBytecode(f, 'JUMP_FORWARD')
268 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
269 returns = [instr for instr in dis.get_instructions(f)
270 if instr.opname == 'RETURN_VALUE']
271 self.assertEqual(len(returns), 6)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000272
273 def test_elim_jump_after_return2(self):
274 # Eliminate dead code: jumps immediately after returns can't be reached
275 def f(cond1, cond2):
276 while 1:
277 if cond1: return 4
Nick Coghland6245172013-05-07 00:03:00 +1000278 self.assertNotInBytecode(f, 'JUMP_FORWARD')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000279 # There should be one jump for the while loop.
Nick Coghland6245172013-05-07 00:03:00 +1000280 returns = [instr for instr in dis.get_instructions(f)
281 if instr.opname == 'JUMP_ABSOLUTE']
282 self.assertEqual(len(returns), 1)
283 returns = [instr for instr in dis.get_instructions(f)
284 if instr.opname == 'RETURN_VALUE']
285 self.assertEqual(len(returns), 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000286
Guido van Rossum0240b922007-02-26 21:23:50 +0000287 def test_make_function_doesnt_bail(self):
288 def f():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000289 def g()->1+1:
Guido van Rossum0240b922007-02-26 21:23:50 +0000290 pass
291 return g
Nick Coghland6245172013-05-07 00:03:00 +1000292 self.assertNotInBytecode(f, 'BINARY_ADD')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000293
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100294 def test_constant_folding(self):
295 # Issue #11244: aggressive constant folding.
296 exprs = [
Nick Coghland6245172013-05-07 00:03:00 +1000297 '3 * -5',
298 '-3 * 5',
299 '2 * (3 * 4)',
300 '(2 * 3) * 4',
301 '(-1, 2, 3)',
302 '(1, -2, 3)',
303 '(1, 2, -3)',
304 '(1, 2, -3) * 6',
305 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100306 ]
307 for e in exprs:
Nick Coghland6245172013-05-07 00:03:00 +1000308 code = compile(e, '', 'single')
309 for instr in dis.get_instructions(code):
310 self.assertFalse(instr.opname.startswith('UNARY_'))
311 self.assertFalse(instr.opname.startswith('BINARY_'))
312 self.assertFalse(instr.opname.startswith('BUILD_'))
313
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100314
Raymond Hettinger0661e912011-03-15 15:03:36 -0700315class TestBuglets(unittest.TestCase):
316
Raymond Hettinger5bd75b82011-03-15 15:07:38 -0700317 def test_bug_11510(self):
318 # folded constant set optimization was commingled with the tuple
319 # unpacking optimization which would fail if the set had duplicate
320 # elements so that the set length was unexpected
321 def f():
322 x, y = {1, 1}
323 return x, y
324 with self.assertRaises(ValueError):
325 f()
Raymond Hettinger0661e912011-03-15 15:03:36 -0700326
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000327
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000328if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500329 unittest.main()