[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}" |