Skip to content

Commit d52ffc1

Browse files
Fidget-Spinnerkumaraditya303sweeneyde
authored
gh-93382: Cache result of PyCode_GetCode in codeobject (GH-93383)
Co-authored-by: Kumar Aditya <[email protected]> Co-authored-by: Dennis Sweeney <[email protected]>
1 parent d8f40ea commit d52ffc1

File tree

5 files changed

+21
-4
lines changed

5 files changed

+21
-4
lines changed

Include/cpython/code.h

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ typedef uint16_t _Py_CODEUNIT;
8888
PyObject *co_qualname; /* unicode (qualname, for reference) */ \
8989
PyObject *co_linetable; /* bytes object that holds location info */ \
9090
PyObject *co_weakreflist; /* to support weakrefs to code objects */ \
91+
void *_co_code; /* cached co_code object/attribute */ \
9192
/* Scratch space for extra data relating to the code object. \
9293
Type is a void* to keep the format private in codeobject.c to force \
9394
people to go through the proper APIs. */ \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Speed up the :c:func:`PyCode_GetCode` function which also improves accessing the :attr:`~types.CodeType.co_code` attribute in Python.

Objects/codeobject.c

+7
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
334334
/* not set */
335335
co->co_weakreflist = NULL;
336336
co->co_extra = NULL;
337+
co->_co_code = NULL;
337338

338339
co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
339340
memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code),
@@ -1367,12 +1368,17 @@ deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
13671368
PyObject *
13681369
_PyCode_GetCode(PyCodeObject *co)
13691370
{
1371+
if (co->_co_code != NULL) {
1372+
return Py_NewRef(co->_co_code);
1373+
}
13701374
PyObject *code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co),
13711375
_PyCode_NBYTES(co));
13721376
if (code == NULL) {
13731377
return NULL;
13741378
}
13751379
deopt_code((_Py_CODEUNIT *)PyBytes_AS_STRING(code), Py_SIZE(co));
1380+
assert(co->_co_code == NULL);
1381+
co->_co_code = (void *)Py_NewRef(code);
13761382
return code;
13771383
}
13781384

@@ -1531,6 +1537,7 @@ code_dealloc(PyCodeObject *co)
15311537
Py_XDECREF(co->co_qualname);
15321538
Py_XDECREF(co->co_linetable);
15331539
Py_XDECREF(co->co_exceptiontable);
1540+
Py_XDECREF(co->_co_code);
15341541
if (co->co_weakreflist != NULL) {
15351542
PyObject_ClearWeakRefs((PyObject*)co);
15361543
}

Objects/frameobject.c

+8
Original file line numberDiff line numberDiff line change
@@ -458,22 +458,30 @@ _PyFrame_GetState(PyFrameObject *frame)
458458
static void
459459
add_load_fast_null_checks(PyCodeObject *co)
460460
{
461+
int changed = 0;
461462
_Py_CODEUNIT *instructions = _PyCode_CODE(co);
462463
for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) {
463464
switch (_Py_OPCODE(instructions[i])) {
464465
case LOAD_FAST:
465466
case LOAD_FAST__LOAD_FAST:
466467
case LOAD_FAST__LOAD_CONST:
468+
changed = 1;
467469
_Py_SET_OPCODE(instructions[i], LOAD_FAST_CHECK);
468470
break;
469471
case LOAD_CONST__LOAD_FAST:
472+
changed = 1;
470473
_Py_SET_OPCODE(instructions[i], LOAD_CONST);
471474
break;
472475
case STORE_FAST__LOAD_FAST:
476+
changed = 1;
473477
_Py_SET_OPCODE(instructions[i], STORE_FAST);
474478
break;
475479
}
476480
}
481+
if (changed) {
482+
// invalidate cached co_code object
483+
Py_CLEAR(co->_co_code);
484+
}
477485
}
478486

479487
/* Setter for f_lineno - you can set f_lineno from within a trace function in

Programs/test_frozenmain.h

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)