[3.11] gh-93382: Cache result of PyCode_GetCode in codeobject (GH-9… · python/cpython@852b4d4 (original) (raw)

6 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -89,6 +89,7 @@ typedef uint16_t _Py_CODEUNIT;
89 89 PyObject *co_qualname; /* unicode (qualname, for reference) */ \
90 90 PyObject *co_linetable; /* bytes object that holds location info */ \
91 91 PyObject *co_weakreflist; /* to support weakrefs to code objects */ \
92 +PyObject *_co_code; /* cached co_code object/attribute */ \
92 93 char *_co_linearray; /* array of line offsets */ \
93 94 /* Scratch space for extra data relating to the code object. \
94 95 Type is a void* to keep the format private in codeobject.c to force \
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1 +Cache the result of :c:func:`PyCode_GetCode` function to restore the O(1)
2 +lookup of the :attr:`~types.CodeType.co_code` attribute.
Original file line number Diff line number Diff line change
@@ -334,6 +334,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
334 334 /* not set */
335 335 co->co_weakreflist = NULL;
336 336 co->co_extra = NULL;
337 +co->_co_code = NULL;
337 338
338 339 co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
339 340 co->_co_linearray_entry_size = 0;
@@ -1421,12 +1422,17 @@ deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
1421 1422 PyObject *
1422 1423 _PyCode_GetCode(PyCodeObject *co)
1423 1424 {
1425 +if (co->_co_code != NULL) {
1426 +return Py_NewRef(co->_co_code);
1427 + }
1424 1428 PyObject *code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co),
1425 1429 _PyCode_NBYTES(co));
1426 1430 if (code == NULL) {
1427 1431 return NULL;
1428 1432 }
1429 1433 deopt_code((_Py_CODEUNIT *)PyBytes_AS_STRING(code), Py_SIZE(co));
1434 +assert(co->_co_code == NULL);
1435 +co->_co_code = Py_NewRef(code);
1430 1436 return code;
1431 1437 }
1432 1438
@@ -1585,6 +1591,7 @@ code_dealloc(PyCodeObject *co)
1585 1591 Py_XDECREF(co->co_qualname);
1586 1592 Py_XDECREF(co->co_linetable);
1587 1593 Py_XDECREF(co->co_exceptiontable);
1594 +Py_XDECREF(co->_co_code);
1588 1595 if (co->co_weakreflist != NULL) {
1589 1596 PyObject_ClearWeakRefs((PyObject*)co);
1590 1597 }
@@ -2142,6 +2149,7 @@ _PyStaticCode_Dealloc(PyCodeObject *co)
2142 2149 deopt_code(_PyCode_CODE(co), Py_SIZE(co));
2143 2150 co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
2144 2151 PyMem_Free(co->co_extra);
2152 +Py_CLEAR(co->_co_code);
2145 2153 co->co_extra = NULL;
2146 2154 if (co->co_weakreflist != NULL) {
2147 2155 PyObject_ClearWeakRefs((PyObject *)co);
Original file line number Diff line number Diff line change
@@ -279,6 +279,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
279 279 self.write(f".co_name = {co_name},")
280 280 self.write(f".co_qualname = {co_qualname},")
281 281 self.write(f".co_linetable = {co_linetable},")
282 +self.write(f"._co_code = NULL,")
282 283 self.write("._co_linearray = NULL,")
283 284 self.write(f".co_code_adaptive = {co_code_adaptive},")
284 285 name_as_code = f"(PyCodeObject *)&{name}"