Skip to content

Commit 8e6e406

Browse files
committed
Remove original or unused constants
1 parent 0d2e040 commit 8e6e406

File tree

4 files changed

+97
-58
lines changed

4 files changed

+97
-58
lines changed

Python/optimizer.c

Lines changed: 77 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,47 @@ sanity_check(_PyExecutorObject *executor)
11331133
#undef CHECK
11341134
#endif
11351135

1136+
static PyObject *
1137+
safe_constant_key(PyObject *o)
1138+
{
1139+
PyObject *k = _PyCode_ConstantKey(o);
1140+
// A key of tuple[int, object] is used for "other" constants, which may
1141+
// include arbitrary objects. We don't want to try to hash them or check
1142+
// their equality, so just make the key a tuple[int] (their address):
1143+
if (k && PyTuple_CheckExact(k) && PyLong_CheckExact(PyTuple_GET_ITEM(k, 0))) {
1144+
Py_SETREF(k, PyTuple_Pack(1, PyTuple_GET_ITEM(k, 0)));
1145+
}
1146+
return k;
1147+
}
1148+
1149+
static bool
1150+
safe_contains(PyObject *refs, PyObject *o)
1151+
{
1152+
assert(PyList_CheckExact(refs));
1153+
for (int i = 0; i < PyList_GET_SIZE(refs); i++) {
1154+
if (Py_Is(o, PyList_GET_ITEM(refs, i))) {
1155+
return true;
1156+
}
1157+
}
1158+
return false;
1159+
}
1160+
1161+
static int
1162+
merge_const(PyObject *refs, PyObject **o_p)
1163+
{
1164+
assert(PyDict_CheckExact(refs));
1165+
assert(!_Py_IsImmortal(*o_p));
1166+
PyObject *o = *o_p;
1167+
PyObject *k = safe_constant_key(o);
1168+
if (k == NULL) {
1169+
return -1;
1170+
}
1171+
int res = PyDict_SetDefaultRef(refs, k, o, o_p);
1172+
Py_DECREF(k);
1173+
Py_DECREF(o);
1174+
return res;
1175+
}
1176+
11361177
/* Makes an executor from a buffer of uops.
11371178
* Account for the buffer having gaps and NOPs by computing a "used"
11381179
* bit vector and only copying the used uops. Here "used" means reachable
@@ -1251,16 +1292,16 @@ uop_optimize(
12511292
assert(length < UOP_MAX_TRACE_LENGTH);
12521293
OPT_STAT_INC(traces_created);
12531294
char *env_var = Py_GETENV("PYTHON_UOPS_OPTIMIZE");
1254-
PyObject *refs = PyDict_New();
1255-
if (refs == NULL) {
1295+
PyObject *new_refs = PyList_New(0);
1296+
if (new_refs == NULL) {
12561297
return -1;
12571298
}
12581299
if (env_var == NULL || *env_var == '\0' || *env_var > '0') {
12591300
length = _Py_uop_analyze_and_optimize(frame, buffer,
12601301
length,
1261-
curr_stackentries, &dependencies, refs);
1302+
curr_stackentries, &dependencies, new_refs);
12621303
if (length <= 0) {
1263-
Py_DECREF(refs);
1304+
Py_DECREF(new_refs);
12641305
return length;
12651306
}
12661307
}
@@ -1282,29 +1323,45 @@ uop_optimize(
12821323
assert(_PyOpcode_uop_name[buffer[pc].opcode]);
12831324
assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0);
12841325
}
1326+
PyObject *used_refs = PyDict_New();
1327+
if (used_refs == NULL) {
1328+
Py_DECREF(new_refs);
1329+
return -1;
1330+
}
1331+
for (int i = 0; i < length; i++) {
1332+
if (buffer[i].opcode == _LOAD_CONST_INLINE) {
1333+
PyObject **o_p = (PyObject **)&buffer[i].operand;
1334+
if (!safe_contains(new_refs, *o_p)) {
1335+
continue;
1336+
}
1337+
Py_INCREF(*o_p);
1338+
int err = merge_const(used_refs, o_p);
1339+
Py_DECREF(*o_p);
1340+
if (err < 0) {
1341+
Py_DECREF(used_refs);
1342+
Py_DECREF(new_refs);
1343+
return -1;
1344+
}
1345+
}
1346+
}
1347+
Py_DECREF(new_refs);
1348+
Py_SETREF(used_refs, PyDict_Values(used_refs));
1349+
if (used_refs == NULL) {
1350+
return -1;
1351+
}
1352+
Py_SETREF(used_refs, PyList_AsTuple(used_refs));
1353+
if (used_refs == NULL) {
1354+
return -1;
1355+
}
12851356
OPT_HIST(effective_trace_length(buffer, length), optimized_trace_length_hist);
12861357
length = prepare_for_execution(buffer, length);
12871358
assert(length <= UOP_MAX_TRACE_LENGTH);
12881359
_PyExecutorObject *executor = make_executor_from_uops(buffer, length, &dependencies);
12891360
if (executor == NULL) {
1290-
Py_DECREF(refs);
1361+
Py_DECREF(used_refs);
12911362
return -1;
12921363
}
1293-
PyObject *refs_tuple = PyTuple_New(PyDict_GET_SIZE(refs));
1294-
if (refs_tuple == NULL) {
1295-
Py_DECREF(executor);
1296-
return -1;
1297-
}
1298-
PyObject *k, *v;
1299-
Py_ssize_t i = 0, p = 0;
1300-
Py_BEGIN_CRITICAL_SECTION(refs);
1301-
while (PyDict_Next(refs, &p, &k, &v)) {
1302-
PyTuple_SET_ITEM(refs_tuple, i++, Py_NewRef(v));
1303-
}
1304-
Py_END_CRITICAL_SECTION();
1305-
assert(i == Py_SIZE(refs_tuple));
1306-
Py_DECREF(refs);
1307-
executor->refs = refs_tuple;
1364+
executor->refs = used_refs;
13081365
assert(length <= UOP_MAX_TRACE_LENGTH);
13091366
*exec_ptr = executor;
13101367
return 1;

Python/optimizer_analysis.c

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -289,25 +289,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
289289
return 0;
290290
}
291291

292-
static int
293-
merge_const(PyObject *refs, PyObject **o_p)
294-
{
295-
PyObject *o = *o_p;
296-
PyObject *k = _PyCode_ConstantKey(o);
297-
// A key of tuple[int, object] is used for "other" constants, which may
298-
// include arbitrary objects. We don't want to try to hash them or check
299-
// their equality, so just make the key a tuple[int] (their address):
300-
if (PyTuple_CheckExact(k) && PyLong_CheckExact(PyTuple_GET_ITEM(k, 0))) {
301-
Py_SETREF(k, PyTuple_Pack(1, PyTuple_GET_ITEM(k, 0)));
302-
if (k == NULL) {
303-
return -1;
304-
}
305-
}
306-
int res = PyDict_SetDefaultRef(refs, k, o, o_p);
307-
Py_DECREF(k);
308-
Py_DECREF(o);
309-
return res;
310-
}
292+
311293

312294
#define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack))
313295
#define STACK_SIZE() ((int)(ctx->frame->stack_len))
@@ -606,7 +588,7 @@ _Py_uop_analyze_and_optimize(
606588
int length,
607589
int curr_stacklen,
608590
_PyBloomFilter *dependencies,
609-
PyObject *refs
591+
PyObject *new_refs
610592
)
611593
{
612594
OPT_STAT_INC(optimizer_attempts);
@@ -618,7 +600,7 @@ _Py_uop_analyze_and_optimize(
618600

619601
length = optimize_uops(
620602
_PyFrame_GetCode(frame), buffer,
621-
length, curr_stacklen, dependencies, refs);
603+
length, curr_stacklen, dependencies, new_refs);
622604

623605
if (length <= 0) {
624606
return length;

Python/optimizer_bytecodes.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ dummy_func(void) {
6363
_Py_UOpsContext *ctx;
6464
_PyUOpInstruction *this_instr;
6565
_PyBloomFilter *dependencies;
66-
PyObject *refs;
66+
PyObject *new_refs;
6767
int modified;
6868
int curr_space;
6969
int max_space;
@@ -206,7 +206,7 @@ dummy_func(void) {
206206
assert(this_instr[-1].opcode == _NOP);
207207
REPLACE_OP(&this_instr[-2], _POP_TOP, 0, 0);
208208
REPLACE_OP(&this_instr[-1], _POP_TOP, 0, 0);
209-
if (merge_const(refs, &temp) < 0) {
209+
if (PyList_Append(new_refs, temp)) {
210210
goto error;
211211
}
212212
int opcode = _Py_IsImmortal(temp) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
@@ -234,7 +234,7 @@ dummy_func(void) {
234234
assert(this_instr[-1].opcode == _NOP);
235235
REPLACE_OP(&this_instr[-2], _POP_TOP, 0, 0);
236236
REPLACE_OP(&this_instr[-1], _POP_TOP, 0, 0);
237-
if (merge_const(refs, &temp) < 0) {
237+
if (PyList_Append(new_refs, temp)) {
238238
goto error;
239239
}
240240
int opcode = _Py_IsImmortal(temp) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
@@ -262,7 +262,7 @@ dummy_func(void) {
262262
assert(this_instr[-1].opcode == _NOP);
263263
REPLACE_OP(&this_instr[-2], _POP_TOP, 0, 0);
264264
REPLACE_OP(&this_instr[-1], _POP_TOP, 0, 0);
265-
if (merge_const(refs, &temp) < 0) {
265+
if (PyList_Append(new_refs, temp)) {
266266
goto error;
267267
}
268268
int opcode = _Py_IsImmortal(temp) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
@@ -291,7 +291,7 @@ dummy_func(void) {
291291
assert(this_instr[-1].opcode == _NOP);
292292
REPLACE_OP(&this_instr[-2], _POP_TOP, 0, 0);
293293
REPLACE_OP(&this_instr[-1], _POP_TOP, 0, 0);
294-
if (merge_const(refs, &temp) < 0) {
294+
if (PyList_Append(new_refs, temp)) {
295295
goto error;
296296
}
297297
int opcode = _Py_IsImmortal(temp) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
@@ -320,7 +320,7 @@ dummy_func(void) {
320320
assert(this_instr[-1].opcode == _NOP);
321321
REPLACE_OP(&this_instr[-2], _POP_TOP, 0, 0);
322322
REPLACE_OP(&this_instr[-1], _POP_TOP, 0, 0);
323-
if (merge_const(refs, &temp) < 0) {
323+
if (PyList_Append(new_refs, temp)) {
324324
goto error;
325325
}
326326
int opcode = _Py_IsImmortal(temp) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
@@ -349,7 +349,7 @@ dummy_func(void) {
349349
assert(this_instr[-1].opcode == _NOP);
350350
REPLACE_OP(&this_instr[-2], _POP_TOP, 0, 0);
351351
REPLACE_OP(&this_instr[-1], _POP_TOP, 0, 0);
352-
if (merge_const(refs, &temp) < 0) {
352+
if (PyList_Append(new_refs, temp)) {
353353
goto error;
354354
}
355355
int opcode = _Py_IsImmortal(temp) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
@@ -373,7 +373,7 @@ dummy_func(void) {
373373
assert(this_instr[-1].opcode == _NOP);
374374
REPLACE_OP(&this_instr[-2], _POP_TOP, 0, 0);
375375
REPLACE_OP(&this_instr[-1], _POP_TOP, 0, 0);
376-
if (merge_const(refs, &temp) < 0) {
376+
if (PyList_Append(new_refs, temp)) {
377377
goto error;
378378
}
379379
int opcode = _Py_IsImmortal(temp) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
@@ -399,7 +399,7 @@ dummy_func(void) {
399399
assert(this_instr[-1].opcode == _NOP);
400400
REPLACE_OP(&this_instr[-3], _POP_TOP, 0, 0);
401401
REPLACE_OP(&this_instr[-2], _POP_TOP, 0, 0);
402-
if (merge_const(refs, &temp) < 0) {
402+
if (PyList_Append(new_refs, temp)) {
403403
goto error;
404404
}
405405
int opcode = _Py_IsImmortal(temp) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;

Python/optimizer_cases.c.h

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)