ยปCore Development>Code coverage>Lib/test/test_peepholer.py

Python code coverage for Lib/test/test_peepholer.py

#countcontent
1n/aimport dis
2n/aimport unittest
3n/a
4n/afrom test.bytecode_helper import BytecodeTestCase
5n/a
6n/aclass TestTranforms(BytecodeTestCase):
7n/a
8n/a def test_unot(self):
9n/a # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE'
10n/a def unot(x):
11n/a if not x == 2:
12n/a del x
13n/a self.assertNotInBytecode(unot, 'UNARY_NOT')
14n/a self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE')
15n/a self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE')
16n/a
17n/a def test_elim_inversion_of_is_or_in(self):
18n/a for line, cmp_op in (
19n/a ('not a is b', 'is not',),
20n/a ('not a in b', 'not in',),
21n/a ('not a is not b', 'is',),
22n/a ('not a not in b', 'in',),
23n/a ):
24n/a code = compile(line, '', 'single')
25n/a self.assertInBytecode(code, 'COMPARE_OP', cmp_op)
26n/a
27n/a def test_global_as_constant(self):
28n/a # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
29n/a def f():
30n/a x = None
31n/a x = None
32n/a return x
33n/a def g():
34n/a x = True
35n/a return x
36n/a def h():
37n/a x = False
38n/a return x
39n/a
40n/a for func, elem in ((f, None), (g, True), (h, False)):
41n/a self.assertNotInBytecode(func, 'LOAD_GLOBAL')
42n/a self.assertInBytecode(func, 'LOAD_CONST', elem)
43n/a
44n/a def f():
45n/a 'Adding a docstring made this test fail in Py2.5.0'
46n/a return None
47n/a
48n/a self.assertNotInBytecode(f, 'LOAD_GLOBAL')
49n/a self.assertInBytecode(f, 'LOAD_CONST', None)
50n/a
51n/a def test_while_one(self):
52n/a # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
53n/a def f():
54n/a while 1:
55n/a pass
56n/a return list
57n/a for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
58n/a self.assertNotInBytecode(f, elem)
59n/a for elem in ('JUMP_ABSOLUTE',):
60n/a self.assertInBytecode(f, elem)
61n/a
62n/a def test_pack_unpack(self):
63n/a for line, elem in (
64n/a ('a, = a,', 'LOAD_CONST',),
65n/a ('a, b = a, b', 'ROT_TWO',),
66n/a ('a, b, c = a, b, c', 'ROT_THREE',),
67n/a ):
68n/a code = compile(line,'','single')
69n/a self.assertInBytecode(code, elem)
70n/a self.assertNotInBytecode(code, 'BUILD_TUPLE')
71n/a self.assertNotInBytecode(code, 'UNPACK_TUPLE')
72n/a
73n/a def test_folding_of_tuples_of_constants(self):
74n/a for line, elem in (
75n/a ('a = 1,2,3', (1, 2, 3)),
76n/a ('("a","b","c")', ('a', 'b', 'c')),
77n/a ('a,b,c = 1,2,3', (1, 2, 3)),
78n/a ('(None, 1, None)', (None, 1, None)),
79n/a ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
80n/a ):
81n/a code = compile(line,'','single')
82n/a self.assertInBytecode(code, 'LOAD_CONST', elem)
83n/a self.assertNotInBytecode(code, 'BUILD_TUPLE')
84n/a
85n/a # Long tuples should be folded too.
86n/a code = compile(repr(tuple(range(10000))),'','single')
87n/a self.assertNotInBytecode(code, 'BUILD_TUPLE')
88n/a # One LOAD_CONST for the tuple, one for the None return value
89n/a load_consts = [instr for instr in dis.get_instructions(code)
90n/a if instr.opname == 'LOAD_CONST']
91n/a self.assertEqual(len(load_consts), 2)
92n/a
93n/a # Bug 1053819: Tuple of constants misidentified when presented with:
94n/a # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
95n/a # The following would segfault upon compilation
96n/a def crater():
97n/a (~[
98n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
99n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
100n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
101n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
102n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
103n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
104n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
105n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
106n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
107n/a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
108n/a ],)
109n/a
110n/a def test_folding_of_lists_of_constants(self):
111n/a for line, elem in (
112n/a # in/not in constants with BUILD_LIST should be folded to a tuple:
113n/a ('a in [1,2,3]', (1, 2, 3)),
114n/a ('a not in ["a","b","c"]', ('a', 'b', 'c')),
115n/a ('a in [None, 1, None]', (None, 1, None)),
116n/a ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
117n/a ):
118n/a code = compile(line, '', 'single')
119n/a self.assertInBytecode(code, 'LOAD_CONST', elem)
120n/a self.assertNotInBytecode(code, 'BUILD_LIST')
121n/a
122n/a def test_folding_of_sets_of_constants(self):
123n/a for line, elem in (
124n/a # in/not in constants with BUILD_SET should be folded to a frozenset:
125n/a ('a in {1,2,3}', frozenset({1, 2, 3})),
126n/a ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
127n/a ('a in {None, 1, None}', frozenset({1, None})),
128n/a ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
129n/a ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
130n/a ):
131n/a code = compile(line, '', 'single')
132n/a self.assertNotInBytecode(code, 'BUILD_SET')
133n/a self.assertInBytecode(code, 'LOAD_CONST', elem)
134n/a
135n/a # Ensure that the resulting code actually works:
136n/a def f(a):
137n/a return a in {1, 2, 3}
138n/a
139n/a def g(a):
140n/a return a not in {1, 2, 3}
141n/a
142n/a self.assertTrue(f(3))
143n/a self.assertTrue(not f(4))
144n/a
145n/a self.assertTrue(not g(3))
146n/a self.assertTrue(g(4))
147n/a
148n/a
149n/a def test_folding_of_binops_on_constants(self):
150n/a for line, elem in (
151n/a ('a = 2+3+4', 9), # chained fold
152n/a ('"@"*4', '@@@@'), # check string ops
153n/a ('a="abc" + "def"', 'abcdef'), # check string ops
154n/a ('a = 3**4', 81), # binary power
155n/a ('a = 3*4', 12), # binary multiply
156n/a ('a = 13//4', 3), # binary floor divide
157n/a ('a = 14%4', 2), # binary modulo
158n/a ('a = 2+3', 5), # binary add
159n/a ('a = 13-4', 9), # binary subtract
160n/a ('a = (12,13)[1]', 13), # binary subscr
161n/a ('a = 13 << 2', 52), # binary lshift
162n/a ('a = 13 >> 2', 3), # binary rshift
163n/a ('a = 13 & 7', 5), # binary and
164n/a ('a = 13 ^ 7', 10), # binary xor
165n/a ('a = 13 | 7', 15), # binary or
166n/a ):
167n/a code = compile(line, '', 'single')
168n/a self.assertInBytecode(code, 'LOAD_CONST', elem)
169n/a for instr in dis.get_instructions(code):
170n/a self.assertFalse(instr.opname.startswith('BINARY_'))
171n/a
172n/a # Verify that unfoldables are skipped
173n/a code = compile('a=2+"b"', '', 'single')
174n/a self.assertInBytecode(code, 'LOAD_CONST', 2)
175n/a self.assertInBytecode(code, 'LOAD_CONST', 'b')
176n/a
177n/a # Verify that large sequences do not result from folding
178n/a code = compile('a="x"*1000', '', 'single')
179n/a self.assertInBytecode(code, 'LOAD_CONST', 1000)
180n/a
181n/a def test_binary_subscr_on_unicode(self):
182n/a # valid code get optimized
183n/a code = compile('"foo"[0]', '', 'single')
184n/a self.assertInBytecode(code, 'LOAD_CONST', 'f')
185n/a self.assertNotInBytecode(code, 'BINARY_SUBSCR')
186n/a code = compile('"\u0061\uffff"[1]', '', 'single')
187n/a self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
188n/a self.assertNotInBytecode(code,'BINARY_SUBSCR')
189n/a
190n/a # With PEP 393, non-BMP char get optimized
191n/a code = compile('"\U00012345"[0]', '', 'single')
192n/a self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
193n/a self.assertNotInBytecode(code, 'BINARY_SUBSCR')
194n/a
195n/a # invalid code doesn't get optimized
196n/a # out of range
197n/a code = compile('"fuu"[10]', '', 'single')
198n/a self.assertInBytecode(code, 'BINARY_SUBSCR')
199n/a
200n/a def test_folding_of_unaryops_on_constants(self):
201n/a for line, elem in (
202n/a ('-0.5', -0.5), # unary negative
203n/a ('-0.0', -0.0), # -0.0
204n/a ('-(1.0-1.0)', -0.0), # -0.0 after folding
205n/a ('-0', 0), # -0
206n/a ('~-2', 1), # unary invert
207n/a ('+1', 1), # unary positive
208n/a ):
209n/a code = compile(line, '', 'single')
210n/a self.assertInBytecode(code, 'LOAD_CONST', elem)
211n/a for instr in dis.get_instructions(code):
212n/a self.assertFalse(instr.opname.startswith('UNARY_'))
213n/a
214n/a # Check that -0.0 works after marshaling
215n/a def negzero():
216n/a return -(1.0-1.0)
217n/a
218n/a for instr in dis.get_instructions(code):
219n/a self.assertFalse(instr.opname.startswith('UNARY_'))
220n/a
221n/a # Verify that unfoldables are skipped
222n/a for line, elem, opname in (
223n/a ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
224n/a ('~"abc"', 'abc', 'UNARY_INVERT'),
225n/a ):
226n/a code = compile(line, '', 'single')
227n/a self.assertInBytecode(code, 'LOAD_CONST', elem)
228n/a self.assertInBytecode(code, opname)
229n/a
230n/a def test_elim_extra_return(self):
231n/a # RETURN LOAD_CONST None RETURN --> RETURN
232n/a def f(x):
233n/a return x
234n/a self.assertNotInBytecode(f, 'LOAD_CONST', None)
235n/a returns = [instr for instr in dis.get_instructions(f)
236n/a if instr.opname == 'RETURN_VALUE']
237n/a self.assertEqual(len(returns), 1)
238n/a
239n/a def test_elim_jump_to_return(self):
240n/a # JUMP_FORWARD to RETURN --> RETURN
241n/a def f(cond, true_value, false_value):
242n/a return true_value if cond else false_value
243n/a self.assertNotInBytecode(f, 'JUMP_FORWARD')
244n/a self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
245n/a returns = [instr for instr in dis.get_instructions(f)
246n/a if instr.opname == 'RETURN_VALUE']
247n/a self.assertEqual(len(returns), 2)
248n/a
249n/a def test_elim_jump_after_return1(self):
250n/a # Eliminate dead code: jumps immediately after returns can't be reached
251n/a def f(cond1, cond2):
252n/a if cond1: return 1
253n/a if cond2: return 2
254n/a while 1:
255n/a return 3
256n/a while 1:
257n/a if cond1: return 4
258n/a return 5
259n/a return 6
260n/a self.assertNotInBytecode(f, 'JUMP_FORWARD')
261n/a self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
262n/a returns = [instr for instr in dis.get_instructions(f)
263n/a if instr.opname == 'RETURN_VALUE']
264n/a self.assertEqual(len(returns), 6)
265n/a
266n/a def test_elim_jump_after_return2(self):
267n/a # Eliminate dead code: jumps immediately after returns can't be reached
268n/a def f(cond1, cond2):
269n/a while 1:
270n/a if cond1: return 4
271n/a self.assertNotInBytecode(f, 'JUMP_FORWARD')
272n/a # There should be one jump for the while loop.
273n/a returns = [instr for instr in dis.get_instructions(f)
274n/a if instr.opname == 'JUMP_ABSOLUTE']
275n/a self.assertEqual(len(returns), 1)
276n/a returns = [instr for instr in dis.get_instructions(f)
277n/a if instr.opname == 'RETURN_VALUE']
278n/a self.assertEqual(len(returns), 2)
279n/a
280n/a def test_make_function_doesnt_bail(self):
281n/a def f():
282n/a def g()->1+1:
283n/a pass
284n/a return g
285n/a self.assertNotInBytecode(f, 'BINARY_ADD')
286n/a
287n/a def test_constant_folding(self):
288n/a # Issue #11244: aggressive constant folding.
289n/a exprs = [
290n/a '3 * -5',
291n/a '-3 * 5',
292n/a '2 * (3 * 4)',
293n/a '(2 * 3) * 4',
294n/a '(-1, 2, 3)',
295n/a '(1, -2, 3)',
296n/a '(1, 2, -3)',
297n/a '(1, 2, -3) * 6',
298n/a 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
299n/a ]
300n/a for e in exprs:
301n/a code = compile(e, '', 'single')
302n/a for instr in dis.get_instructions(code):
303n/a self.assertFalse(instr.opname.startswith('UNARY_'))
304n/a self.assertFalse(instr.opname.startswith('BINARY_'))
305n/a self.assertFalse(instr.opname.startswith('BUILD_'))
306n/a
307n/a
308n/aclass TestBuglets(unittest.TestCase):
309n/a
310n/a def test_bug_11510(self):
311n/a # folded constant set optimization was commingled with the tuple
312n/a # unpacking optimization which would fail if the set had duplicate
313n/a # elements so that the set length was unexpected
314n/a def f():
315n/a x, y = {1, 1}
316n/a return x, y
317n/a with self.assertRaises(ValueError):
318n/a f()
319n/a
320n/a
321n/aif __name__ == "__main__":
322n/a unittest.main()