diff --git a/Doc/data/python3.11.abi b/Doc/data/python3.11.abi
index 6e478d78a9e15a..79b3ca3995c246 100644
--- a/Doc/data/python3.11.abi
+++ b/Doc/data/python3.11.abi
@@ -5858,119 +5858,122 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -7451,93 +7454,93 @@
-
-
-
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -7591,8 +7594,8 @@
-
-
+
+
@@ -8279,7 +8282,7 @@
-
+
@@ -9255,307 +9258,307 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
-
-
-
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
-
+
-
+
-
-
+
+
-
-
-
-
+
+
+
+
-
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
-
-
-
+
+
+
+
-
+
-
+
-
-
-
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
@@ -10031,48 +10034,48 @@
-
-
+
+
-
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
@@ -10104,83 +10107,83 @@
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
@@ -10742,8 +10745,8 @@
-
-
+
+
@@ -11101,54 +11104,54 @@
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
@@ -11169,32 +11172,32 @@
-
+
-
-
+
+
-
-
+
+
-
+
-
-
-
+
+
+
-
+
-
+
@@ -11208,33 +11211,33 @@
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
-
+
+
+
@@ -11360,131 +11363,131 @@
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
-
+
+
@@ -13014,7 +13017,7 @@
-
+
@@ -13085,9 +13088,9 @@
-
-
-
+
+
+
@@ -13171,7 +13174,7 @@
-
+
@@ -13205,8 +13208,8 @@
-
-
+
+
@@ -13238,7 +13241,7 @@
-
+
@@ -14204,41 +14207,41 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -14531,7 +14534,7 @@
-
+
@@ -14540,7 +14543,7 @@
-
+
@@ -14785,7 +14788,7 @@
-
+
@@ -14812,7 +14815,7 @@
-
+
@@ -14872,7 +14875,7 @@
-
+
@@ -14916,7 +14919,7 @@
-
+
@@ -15043,7 +15046,7 @@
-
+
@@ -15588,7 +15591,7 @@
-
+
@@ -15602,7 +15605,7 @@
-
+
@@ -15759,80 +15762,80 @@
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
-
+
+
+
@@ -16274,10 +16277,10 @@
-
-
-
-
+
+
+
+
@@ -16365,7 +16368,7 @@
-
+
diff --git a/Include/cpython/code.h b/Include/cpython/code.h
index d7c9aee46440b5..66cf4eccb8fcc9 100644
--- a/Include/cpython/code.h
+++ b/Include/cpython/code.h
@@ -89,6 +89,7 @@ typedef uint16_t _Py_CODEUNIT;
PyObject *co_qualname; /* unicode (qualname, for reference) */ \
PyObject *co_linetable; /* bytes object that holds location info */ \
PyObject *co_weakreflist; /* to support weakrefs to code objects */ \
+ PyObject *_co_code; /* cached co_code object/attribute */ \
char *_co_linearray; /* array of line offsets */ \
/* Scratch space for extra data relating to the code object. \
Type is a void* to keep the format private in codeobject.c to force \
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst
new file mode 100644
index 00000000000000..1fe821edf5a148
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst
@@ -0,0 +1,2 @@
+Cache the result of :c:func:`PyCode_GetCode` function to restore the O(1)
+lookup of the :attr:`~types.CodeType.co_code` attribute.
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 0e914566e30c87..8b9ca890431c6c 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -334,6 +334,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
/* not set */
co->co_weakreflist = NULL;
co->co_extra = NULL;
+ co->_co_code = NULL;
co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
co->_co_linearray_entry_size = 0;
@@ -1421,12 +1422,17 @@ deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
PyObject *
_PyCode_GetCode(PyCodeObject *co)
{
+ if (co->_co_code != NULL) {
+ return Py_NewRef(co->_co_code);
+ }
PyObject *code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co),
_PyCode_NBYTES(co));
if (code == NULL) {
return NULL;
}
deopt_code((_Py_CODEUNIT *)PyBytes_AS_STRING(code), Py_SIZE(co));
+ assert(co->_co_code == NULL);
+ co->_co_code = Py_NewRef(code);
return code;
}
@@ -1585,6 +1591,7 @@ code_dealloc(PyCodeObject *co)
Py_XDECREF(co->co_qualname);
Py_XDECREF(co->co_linetable);
Py_XDECREF(co->co_exceptiontable);
+ Py_XDECREF(co->_co_code);
if (co->co_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*)co);
}
@@ -2142,6 +2149,7 @@ _PyStaticCode_Dealloc(PyCodeObject *co)
deopt_code(_PyCode_CODE(co), Py_SIZE(co));
co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
PyMem_Free(co->co_extra);
+ Py_CLEAR(co->_co_code);
co->co_extra = NULL;
if (co->co_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *)co);
diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h
index 1c279134e94dc9..eec2e0cc6048fa 100644
--- a/Programs/test_frozenmain.h
+++ b/Programs/test_frozenmain.h
@@ -1,7 +1,7 @@
// Auto-generated by Programs/freeze_test_frozenmain.py
unsigned char M_test_frozenmain[] = {
227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,
- 0,0,0,0,0,115,176,0,0,0,151,0,100,0,100,1,
+ 0,0,0,0,0,243,176,0,0,0,151,0,100,0,100,1,
108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2,
100,2,166,1,0,0,171,1,0,0,0,0,0,0,0,0,
1,0,2,0,101,2,100,3,101,0,106,3,0,0,0,0,
@@ -24,10 +24,10 @@ unsigned char M_test_frozenmain[] = {
32,122,2,58,32,41,7,218,3,115,121,115,218,17,95,116,
101,115,116,105,110,116,101,114,110,97,108,99,97,112,105,218,
5,112,114,105,110,116,218,4,97,114,103,118,218,11,103,101,
- 116,95,99,111,110,102,105,103,115,114,2,0,0,0,218,3,
+ 116,95,99,111,110,102,105,103,115,114,3,0,0,0,218,3,
107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116,
95,102,114,111,122,101,110,109,97,105,110,46,112,121,250,8,
- 60,109,111,100,117,108,101,62,114,17,0,0,0,1,0,0,
+ 60,109,111,100,117,108,101,62,114,18,0,0,0,1,0,0,
0,115,152,0,0,0,248,240,6,0,1,11,128,10,128,10,
128,10,216,0,24,208,0,24,208,0,24,208,0,24,224,0,
5,128,5,208,6,26,209,0,27,212,0,27,208,0,27,216,
@@ -37,6 +37,6 @@ unsigned char M_test_frozenmain[] = {
7,1,42,240,0,7,1,42,128,67,240,14,0,5,10,128,
69,208,10,40,144,67,208,10,40,208,10,40,152,54,160,35,
156,59,208,10,40,208,10,40,209,4,41,212,4,41,208,4,
- 41,208,4,41,240,15,7,1,42,240,0,7,1,42,114,15,
+ 41,208,4,41,240,15,7,1,42,240,0,7,1,42,114,16,
0,0,0,
};
diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py
index 50d0b345ed407d..43a7a98fcc503c 100644
--- a/Tools/scripts/deepfreeze.py
+++ b/Tools/scripts/deepfreeze.py
@@ -279,6 +279,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
self.write(f".co_name = {co_name},")
self.write(f".co_qualname = {co_qualname},")
self.write(f".co_linetable = {co_linetable},")
+ self.write(f"._co_code = NULL,")
self.write("._co_linearray = NULL,")
self.write(f".co_code_adaptive = {co_code_adaptive},")
name_as_code = f"(PyCodeObject *)&{name}"