blob: b0336407c3b297572653a2d3920a5f2820ae45c9 [file] [log] [blame]
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00001import dis
Antoine Pitroub7fbcd32010-01-16 18:37:38 +00002import re
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00003import sys
Victor Stinner51d8c522016-02-08 17:57:02 +01004import textwrap
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00005import unittest
6
Nick Coghland6245172013-05-07 00:03:00 +10007from test.bytecode_helper import BytecodeTestCase
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00008
Nick Coghland6245172013-05-07 00:03:00 +10009class TestTranforms(BytecodeTestCase):
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000010
11 def test_unot(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000012 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE'
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000013 def unot(x):
14 if not x == 2:
15 del x
Nick Coghland6245172013-05-07 00:03:00 +100016 self.assertNotInBytecode(unot, 'UNARY_NOT')
17 self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE')
18 self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000019
20 def test_elim_inversion_of_is_or_in(self):
Nick Coghland6245172013-05-07 00:03:00 +100021 for line, cmp_op in (
22 ('not a is b', 'is not',),
23 ('not a in b', 'not in',),
24 ('not a is not b', 'is',),
25 ('not a not in b', 'in',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000026 ):
Nick Coghland6245172013-05-07 00:03:00 +100027 code = compile(line, '', 'single')
28 self.assertInBytecode(code, 'COMPARE_OP', cmp_op)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000029
Guido van Rossumcd16bf62007-06-13 18:07:49 +000030 def test_global_as_constant(self):
31 # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
Victor Stinner51d8c522016-02-08 17:57:02 +010032 def f():
33 x = None
34 x = None
Tim Peters66cb0182004-08-26 05:23:19 +000035 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010036 def g():
37 x = True
Guido van Rossumcd16bf62007-06-13 18:07:49 +000038 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010039 def h():
40 x = False
Guido van Rossumcd16bf62007-06-13 18:07:49 +000041 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010042
Nick Coghland6245172013-05-07 00:03:00 +100043 for func, elem in ((f, None), (g, True), (h, False)):
44 self.assertNotInBytecode(func, 'LOAD_GLOBAL')
45 self.assertInBytecode(func, 'LOAD_CONST', elem)
Victor Stinner51d8c522016-02-08 17:57:02 +010046
Guido van Rossumd8faa362007-04-27 19:54:29 +000047 def f():
48 'Adding a docstring made this test fail in Py2.5.0'
49 return None
Victor Stinner51d8c522016-02-08 17:57:02 +010050
Nick Coghland6245172013-05-07 00:03:00 +100051 self.assertNotInBytecode(f, 'LOAD_GLOBAL')
52 self.assertInBytecode(f, 'LOAD_CONST', None)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000053
54 def test_while_one(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000055 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000056 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000057 while 1:
58 pass
59 return list
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000060 for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
Nick Coghland6245172013-05-07 00:03:00 +100061 self.assertNotInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000062 for elem in ('JUMP_ABSOLUTE',):
Nick Coghland6245172013-05-07 00:03:00 +100063 self.assertInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000064
65 def test_pack_unpack(self):
66 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000067 ('a, = a,', 'LOAD_CONST',),
68 ('a, b = a, b', 'ROT_TWO',),
69 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000070 ):
Nick Coghland6245172013-05-07 00:03:00 +100071 code = compile(line,'','single')
72 self.assertInBytecode(code, elem)
73 self.assertNotInBytecode(code, 'BUILD_TUPLE')
74 self.assertNotInBytecode(code, 'UNPACK_TUPLE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000075
Raymond Hettinger2c31a052004-09-22 18:44:21 +000076 def test_folding_of_tuples_of_constants(self):
77 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +100078 ('a = 1,2,3', (1, 2, 3)),
79 ('("a","b","c")', ('a', 'b', 'c')),
80 ('a,b,c = 1,2,3', (1, 2, 3)),
81 ('(None, 1, None)', (None, 1, None)),
82 ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000083 ):
Nick Coghland6245172013-05-07 00:03:00 +100084 code = compile(line,'','single')
85 self.assertInBytecode(code, 'LOAD_CONST', elem)
86 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Raymond Hettinger2c31a052004-09-22 18:44:21 +000087
Antoine Pitrou17b880a2011-03-11 17:27:02 +010088 # Long tuples should be folded too.
Nick Coghland6245172013-05-07 00:03:00 +100089 code = compile(repr(tuple(range(10000))),'','single')
90 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Antoine Pitrou17b880a2011-03-11 17:27:02 +010091 # One LOAD_CONST for the tuple, one for the None return value
Nick Coghland6245172013-05-07 00:03:00 +100092 load_consts = [instr for instr in dis.get_instructions(code)
93 if instr.opname == 'LOAD_CONST']
94 self.assertEqual(len(load_consts), 2)
Antoine Pitrou17b880a2011-03-11 17:27:02 +010095
Raymond Hettinger23109ef2004-10-26 08:59:14 +000096 # Bug 1053819: Tuple of constants misidentified when presented with:
97 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
98 # The following would segfault upon compilation
99 def crater():
100 (~[
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 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
109 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
110 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
111 ],)
112
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000113 def test_folding_of_lists_of_constants(self):
114 for line, elem in (
115 # in/not in constants with BUILD_LIST should be folded to a tuple:
Nick Coghland6245172013-05-07 00:03:00 +1000116 ('a in [1,2,3]', (1, 2, 3)),
117 ('a not in ["a","b","c"]', ('a', 'b', 'c')),
118 ('a in [None, 1, None]', (None, 1, None)),
119 ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000120 ):
Nick Coghland6245172013-05-07 00:03:00 +1000121 code = compile(line, '', 'single')
122 self.assertInBytecode(code, 'LOAD_CONST', elem)
123 self.assertNotInBytecode(code, 'BUILD_LIST')
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000124
125 def test_folding_of_sets_of_constants(self):
126 for line, elem in (
127 # in/not in constants with BUILD_SET should be folded to a frozenset:
128 ('a in {1,2,3}', frozenset({1, 2, 3})),
129 ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
130 ('a in {None, 1, None}', frozenset({1, None})),
131 ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
132 ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
133 ):
Nick Coghland6245172013-05-07 00:03:00 +1000134 code = compile(line, '', 'single')
135 self.assertNotInBytecode(code, 'BUILD_SET')
136 self.assertInBytecode(code, 'LOAD_CONST', elem)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000137
138 # Ensure that the resulting code actually works:
139 def f(a):
140 return a in {1, 2, 3}
141
142 def g(a):
143 return a not in {1, 2, 3}
144
145 self.assertTrue(f(3))
146 self.assertTrue(not f(4))
147
148 self.assertTrue(not g(3))
149 self.assertTrue(g(4))
150
151
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000152 def test_folding_of_binops_on_constants(self):
153 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000154 ('a = 2+3+4', 9), # chained fold
155 ('"@"*4', '@@@@'), # check string ops
156 ('a="abc" + "def"', 'abcdef'), # check string ops
157 ('a = 3**4', 81), # binary power
158 ('a = 3*4', 12), # binary multiply
159 ('a = 13//4', 3), # binary floor divide
160 ('a = 14%4', 2), # binary modulo
161 ('a = 2+3', 5), # binary add
162 ('a = 13-4', 9), # binary subtract
163 ('a = (12,13)[1]', 13), # binary subscr
164 ('a = 13 << 2', 52), # binary lshift
165 ('a = 13 >> 2', 3), # binary rshift
166 ('a = 13 & 7', 5), # binary and
167 ('a = 13 ^ 7', 10), # binary xor
168 ('a = 13 | 7', 15), # binary or
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000169 ):
Nick Coghland6245172013-05-07 00:03:00 +1000170 code = compile(line, '', 'single')
171 self.assertInBytecode(code, 'LOAD_CONST', elem)
172 for instr in dis.get_instructions(code):
173 self.assertFalse(instr.opname.startswith('BINARY_'))
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000174
175 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000176 code = compile('a=2+"b"', '', 'single')
177 self.assertInBytecode(code, 'LOAD_CONST', 2)
178 self.assertInBytecode(code, 'LOAD_CONST', 'b')
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000179
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000180 # Verify that large sequences do not result from folding
Nick Coghland6245172013-05-07 00:03:00 +1000181 code = compile('a="x"*1000', '', 'single')
182 self.assertInBytecode(code, 'LOAD_CONST', 1000)
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000183
Ezio Melotti2df6a932011-04-15 16:38:34 +0300184 def test_binary_subscr_on_unicode(self):
185 # valid code get optimized
Nick Coghland6245172013-05-07 00:03:00 +1000186 code = compile('"foo"[0]', '', 'single')
187 self.assertInBytecode(code, 'LOAD_CONST', 'f')
188 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
189 code = compile('"\u0061\uffff"[1]', '', 'single')
190 self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
191 self.assertNotInBytecode(code,'BINARY_SUBSCR')
192
193 # With PEP 393, non-BMP char get optimized
194 code = compile('"\U00012345"[0]', '', 'single')
195 self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
196 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300197
198 # invalid code doesn't get optimized
199 # out of range
Nick Coghland6245172013-05-07 00:03:00 +1000200 code = compile('"fuu"[10]', '', 'single')
201 self.assertInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300202
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000203 def test_folding_of_unaryops_on_constants(self):
204 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000205 ('-0.5', -0.5), # unary negative
206 ('-0.0', -0.0), # -0.0
207 ('-(1.0-1.0)', -0.0), # -0.0 after folding
208 ('-0', 0), # -0
209 ('~-2', 1), # unary invert
210 ('+1', 1), # unary positive
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000211 ):
Nick Coghland6245172013-05-07 00:03:00 +1000212 code = compile(line, '', 'single')
213 self.assertInBytecode(code, 'LOAD_CONST', elem)
214 for instr in dis.get_instructions(code):
215 self.assertFalse(instr.opname.startswith('UNARY_'))
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000216
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000217 # Check that -0.0 works after marshaling
218 def negzero():
219 return -(1.0-1.0)
220
Nick Coghland6245172013-05-07 00:03:00 +1000221 for instr in dis.get_instructions(code):
222 self.assertFalse(instr.opname.startswith('UNARY_'))
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000223
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000224 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000225 for line, elem, opname in (
226 ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
227 ('~"abc"', 'abc', 'UNARY_INVERT'),
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 self.assertInBytecode(code, opname)
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000232
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000233 def test_elim_extra_return(self):
234 # RETURN LOAD_CONST None RETURN --> RETURN
235 def f(x):
236 return x
Nick Coghland6245172013-05-07 00:03:00 +1000237 self.assertNotInBytecode(f, 'LOAD_CONST', None)
238 returns = [instr for instr in dis.get_instructions(f)
239 if instr.opname == 'RETURN_VALUE']
240 self.assertEqual(len(returns), 1)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000241
Thomas Wouters89f507f2006-12-13 04:49:30 +0000242 def test_elim_jump_to_return(self):
243 # JUMP_FORWARD to RETURN --> RETURN
244 def f(cond, true_value, false_value):
245 return true_value if cond else false_value
Nick Coghland6245172013-05-07 00:03:00 +1000246 self.assertNotInBytecode(f, 'JUMP_FORWARD')
247 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
248 returns = [instr for instr in dis.get_instructions(f)
249 if instr.opname == 'RETURN_VALUE']
250 self.assertEqual(len(returns), 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000251
252 def test_elim_jump_after_return1(self):
253 # Eliminate dead code: jumps immediately after returns can't be reached
254 def f(cond1, cond2):
255 if cond1: return 1
256 if cond2: return 2
257 while 1:
258 return 3
259 while 1:
260 if cond1: return 4
261 return 5
262 return 6
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), 6)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000268
269 def test_elim_jump_after_return2(self):
270 # Eliminate dead code: jumps immediately after returns can't be reached
271 def f(cond1, cond2):
272 while 1:
273 if cond1: return 4
Nick Coghland6245172013-05-07 00:03:00 +1000274 self.assertNotInBytecode(f, 'JUMP_FORWARD')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000275 # There should be one jump for the while loop.
Nick Coghland6245172013-05-07 00:03:00 +1000276 returns = [instr for instr in dis.get_instructions(f)
277 if instr.opname == 'JUMP_ABSOLUTE']
278 self.assertEqual(len(returns), 1)
279 returns = [instr for instr in dis.get_instructions(f)
280 if instr.opname == 'RETURN_VALUE']
281 self.assertEqual(len(returns), 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000282
Guido van Rossum0240b922007-02-26 21:23:50 +0000283 def test_make_function_doesnt_bail(self):
284 def f():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000285 def g()->1+1:
Guido van Rossum0240b922007-02-26 21:23:50 +0000286 pass
287 return g
Nick Coghland6245172013-05-07 00:03:00 +1000288 self.assertNotInBytecode(f, 'BINARY_ADD')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000289
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100290 def test_constant_folding(self):
291 # Issue #11244: aggressive constant folding.
292 exprs = [
Nick Coghland6245172013-05-07 00:03:00 +1000293 '3 * -5',
294 '-3 * 5',
295 '2 * (3 * 4)',
296 '(2 * 3) * 4',
297 '(-1, 2, 3)',
298 '(1, -2, 3)',
299 '(1, 2, -3)',
300 '(1, 2, -3) * 6',
301 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100302 ]
303 for e in exprs:
Nick Coghland6245172013-05-07 00:03:00 +1000304 code = compile(e, '', 'single')
305 for instr in dis.get_instructions(code):
306 self.assertFalse(instr.opname.startswith('UNARY_'))
307 self.assertFalse(instr.opname.startswith('BINARY_'))
308 self.assertFalse(instr.opname.startswith('BUILD_'))
309
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100310
Raymond Hettinger0661e912011-03-15 15:03:36 -0700311class TestBuglets(unittest.TestCase):
312
Raymond Hettinger5bd75b82011-03-15 15:07:38 -0700313 def test_bug_11510(self):
314 # folded constant set optimization was commingled with the tuple
315 # unpacking optimization which would fail if the set had duplicate
316 # elements so that the set length was unexpected
317 def f():
318 x, y = {1, 1}
319 return x, y
320 with self.assertRaises(ValueError):
321 f()
Raymond Hettinger0661e912011-03-15 15:03:36 -0700322
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000323
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000324if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500325 unittest.main()