Skip to content

Commit 87010e8

Browse files
authored
bpo-29469: peephole: Remove const_stack (GH-4879)
Constant folding was moved to AST optimizer. But compiler may emit LOAD_CONSTs + BUILD_TUPLE. For example, default arguments can be constant tuple if all arguments are constant. This commit makes peephole's tuple folding simple. It doesn't support nested tuples because nested tuples are folded by AST optimizer already.
1 parent 902ab80 commit 87010e8

File tree

1 file changed

+21
-81
lines changed

1 file changed

+21
-81
lines changed

Python/peephole.c

Lines changed: 21 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -23,51 +23,6 @@
2323
(blocks[start]==blocks[end])
2424

2525

26-
#define CONST_STACK_CREATE() { \
27-
const_stack_size = 256; \
28-
const_stack = PyMem_New(PyObject *, const_stack_size); \
29-
if (!const_stack) { \
30-
PyErr_NoMemory(); \
31-
goto exitError; \
32-
} \
33-
}
34-
35-
#define CONST_STACK_DELETE() do { \
36-
if (const_stack) \
37-
PyMem_Free(const_stack); \
38-
} while(0)
39-
40-
#define CONST_STACK_LEN() ((unsigned)(const_stack_top + 1))
41-
42-
#define CONST_STACK_PUSH_OP(i) do { \
43-
PyObject *_x; \
44-
assert(_Py_OPCODE(codestr[i]) == LOAD_CONST); \
45-
assert(PyList_GET_SIZE(consts) > (Py_ssize_t)get_arg(codestr, i)); \
46-
_x = PyList_GET_ITEM(consts, get_arg(codestr, i)); \
47-
if (++const_stack_top >= const_stack_size) { \
48-
const_stack_size *= 2; \
49-
PyMem_Resize(const_stack, PyObject *, const_stack_size); \
50-
if (!const_stack) { \
51-
PyErr_NoMemory(); \
52-
goto exitError; \
53-
} \
54-
} \
55-
const_stack[const_stack_top] = _x; \
56-
in_consts = 1; \
57-
} while(0)
58-
59-
#define CONST_STACK_RESET() do { \
60-
const_stack_top = -1; \
61-
} while(0)
62-
63-
#define CONST_STACK_LASTN(i) \
64-
&const_stack[CONST_STACK_LEN() - i]
65-
66-
#define CONST_STACK_POP(i) do { \
67-
assert(CONST_STACK_LEN() >= i); \
68-
const_stack_top -= i; \
69-
} while(0)
70-
7126
/* Scans back N consecutive LOAD_CONST instructions, skipping NOPs,
7227
returns index of the Nth last's LOAD_CONST's EXTENDED_ARG prefix.
7328
Callers are responsible to check CONST_STACK_LEN beforehand.
@@ -88,8 +43,7 @@ lastn_const_start(const _Py_CODEUNIT *codestr, Py_ssize_t i, Py_ssize_t n)
8843
}
8944
}
9045
else {
91-
assert(_Py_OPCODE(codestr[i]) == NOP ||
92-
_Py_OPCODE(codestr[i]) == EXTENDED_ARG);
46+
assert(_Py_OPCODE(codestr[i]) == EXTENDED_ARG);
9347
}
9448
}
9549
}
@@ -172,39 +126,40 @@ copy_op_arg(_Py_CODEUNIT *codestr, Py_ssize_t i, unsigned char op,
172126
The consts table must still be in list form so that the
173127
new constant (c1, c2, ... cn) can be appended.
174128
Called with codestr pointing to the first LOAD_CONST.
175-
Bails out with no change if one or more of the LOAD_CONSTs is missing.
176129
*/
177130
static Py_ssize_t
178131
fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
179-
Py_ssize_t opcode_end, unsigned char opcode,
180-
PyObject *consts, PyObject **objs, int n)
132+
Py_ssize_t opcode_end, PyObject *consts, int n)
181133
{
182-
PyObject *newconst, *constant;
183-
Py_ssize_t i, len_consts;
184-
185134
/* Pre-conditions */
186135
assert(PyList_CheckExact(consts));
187136

188137
/* Buildup new tuple of constants */
189-
newconst = PyTuple_New(n);
138+
PyObject *newconst = PyTuple_New(n);
190139
if (newconst == NULL) {
191140
return -1;
192141
}
193-
for (i=0 ; i<n ; i++) {
194-
constant = objs[i];
142+
143+
for (Py_ssize_t i = 0, pos = c_start; i < n; i++, pos++) {
144+
assert(pos < opcode_end);
145+
pos = find_op(codestr, pos);
146+
assert(_Py_OPCODE(codestr[pos]) == LOAD_CONST);
147+
148+
unsigned int arg = get_arg(codestr, pos);
149+
PyObject *constant = PyList_GET_ITEM(consts, arg);
195150
Py_INCREF(constant);
196151
PyTuple_SET_ITEM(newconst, i, constant);
197152
}
198153

199154
/* Append folded constant onto consts */
200-
len_consts = PyList_GET_SIZE(consts);
201155
if (PyList_Append(consts, newconst)) {
202156
Py_DECREF(newconst);
203157
return -1;
204158
}
205159
Py_DECREF(newconst);
206160

207-
return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
161+
return copy_op_arg(codestr, c_start, LOAD_CONST,
162+
PyList_GET_SIZE(consts)-1, opcode_end);
208163
}
209164

210165
static unsigned int *
@@ -274,10 +229,8 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
274229
unsigned char *lnotab;
275230
unsigned int cum_orig_offset, last_offset;
276231
Py_ssize_t tabsiz;
277-
PyObject **const_stack = NULL;
278-
Py_ssize_t const_stack_top = -1;
279-
Py_ssize_t const_stack_size = 0;
280-
int in_consts = 0; /* whether we are in a LOAD_CONST sequence */
232+
// Count runs of consecutive LOAD_CONSTs
233+
unsigned int cumlc = 0, lastlc = 0;
281234
unsigned int *blocks = NULL;
282235

283236
/* Bail out if an exception is set */
@@ -314,8 +267,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
314267
goto exitError;
315268
assert(PyList_Check(consts));
316269

317-
CONST_STACK_CREATE();
318-
319270
for (i=find_op(codestr, 0) ; i<codelen ; i=nexti) {
320271
opcode = _Py_OPCODE(codestr[i]);
321272
op_start = i;
@@ -328,23 +279,21 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
328279
nexti++;
329280
nextop = nexti < codelen ? _Py_OPCODE(codestr[nexti]) : 0;
330281

331-
if (!in_consts) {
332-
CONST_STACK_RESET();
333-
}
334-
in_consts = 0;
282+
lastlc = cumlc;
283+
cumlc = 0;
335284

336285
switch (opcode) {
337286
/* Skip over LOAD_CONST trueconst
338287
POP_JUMP_IF_FALSE xx. This improves
339288
"while 1" performance. */
340289
case LOAD_CONST:
341-
CONST_STACK_PUSH_OP(i);
290+
cumlc = lastlc + 1;
342291
if (nextop != POP_JUMP_IF_FALSE ||
343292
!ISBASICBLOCK(blocks, op_start, i + 1) ||
344293
!PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
345294
break;
346295
fill_nops(codestr, op_start, nexti + 1);
347-
CONST_STACK_POP(1);
296+
cumlc = 0;
348297
break;
349298

350299
/* Try to fold tuples of constants.
@@ -353,15 +302,10 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
353302
Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
354303
case BUILD_TUPLE:
355304
j = get_arg(codestr, i);
356-
if (j > 0 && CONST_STACK_LEN() >= j) {
305+
if (j > 0 && lastlc >= j) {
357306
h = lastn_const_start(codestr, op_start, j);
358307
if (ISBASICBLOCK(blocks, h, op_start)) {
359-
h = fold_tuple_on_constants(codestr, h, i + 1, opcode,
360-
consts, CONST_STACK_LASTN(j), j);
361-
if (h >= 0) {
362-
CONST_STACK_POP(j);
363-
CONST_STACK_PUSH_OP(h);
364-
}
308+
h = fold_tuple_on_constants(codestr, h, i+1, consts, j);
365309
break;
366310
}
367311
}
@@ -374,12 +318,10 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
374318
} else if (j == 2) {
375319
codestr[op_start] = PACKOPARG(ROT_TWO, 0);
376320
fill_nops(codestr, op_start + 1, nexti + 1);
377-
CONST_STACK_RESET();
378321
} else if (j == 3) {
379322
codestr[op_start] = PACKOPARG(ROT_THREE, 0);
380323
codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
381324
fill_nops(codestr, op_start + 2, nexti + 1);
382-
CONST_STACK_RESET();
383325
}
384326
break;
385327

@@ -538,7 +480,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
538480
}
539481
assert(h + (Py_ssize_t)nops == codelen);
540482

541-
CONST_STACK_DELETE();
542483
PyMem_Free(blocks);
543484
code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
544485
PyMem_Free(codestr);
@@ -549,7 +490,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
549490

550491
exitUnchanged:
551492
Py_XINCREF(code);
552-
CONST_STACK_DELETE();
553493
PyMem_Free(blocks);
554494
PyMem_Free(codestr);
555495
return code;

0 commit comments

Comments
 (0)