Skip to content

Commit 9f494d4

Browse files
bpo-43693: Add _PyCode_New(). (gh-26375)
This is an internal-only API that helps us manage the many values used to create a code object. https://bugs.python.org/issue43693
1 parent 318adeb commit 9f494d4

File tree

12 files changed

+4701
-4613
lines changed

12 files changed

+4701
-4613
lines changed

Include/cpython/code.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ struct PyCodeObject {
6464

6565
/* These fields are set with computed values on new code objects. */
6666

67-
Py_ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */
67+
int *co_cell2arg; /* Maps cell vars which are arguments. */
6868
// These are redundant but offer some performance benefit.
6969
int co_nlocalsplus; /* number of local + cell + free variables */
7070
int co_nlocals; /* number of local variables */

Include/internal/pycore_code.h

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
#ifdef __cplusplus
44
extern "C" {
55
#endif
6-
6+
7+
78
typedef struct {
89
PyObject *ptr; /* Cached pointer (borrowed reference) */
910
uint64_t globals_ver; /* ma_version of global dict */
@@ -24,7 +25,54 @@ struct _PyOpcache {
2425
char optimized;
2526
};
2627

28+
29+
struct _PyCodeConstructor {
30+
/* metadata */
31+
PyObject *filename;
32+
PyObject *name;
33+
int flags;
34+
35+
/* the code */
36+
PyObject *code;
37+
int firstlineno;
38+
PyObject *linetable;
39+
40+
/* used by the code */
41+
PyObject *consts;
42+
PyObject *names;
43+
44+
/* mapping frame offsets to information */
45+
PyObject *varnames;
46+
PyObject *cellvars;
47+
PyObject *freevars;
48+
49+
/* args (within varnames) */
50+
int argcount;
51+
int posonlyargcount;
52+
int kwonlyargcount;
53+
54+
/* needed to create the frame */
55+
int stacksize;
56+
57+
/* used by the eval loop */
58+
PyObject *exceptiontable;
59+
};
60+
61+
// Using an "arguments struct" like this is helpful for maintainability
62+
// in a case such as this with many parameters. It does bear a risk:
63+
// if the struct changes and callers are not updated properly then the
64+
// compiler will not catch problems (like a missing argument). This can
65+
// cause hard-to-debug problems. The risk is mitigated by the use of
66+
// check_code() in codeobject.c. However, we may decide to switch
67+
// back to a regular function signature. Regardless, this approach
68+
// wouldn't be appropriate if this weren't a strictly internal API.
69+
// (See the comments in https://github.com/python/cpython/pull/26258.)
70+
PyAPI_FUNC(int) _PyCode_Validate(struct _PyCodeConstructor *);
71+
PyAPI_FUNC(PyCodeObject *) _PyCode_New(struct _PyCodeConstructor *);
72+
73+
2774
/* Private API */
75+
2876
int _PyCode_InitOpcache(PyCodeObject *co);
2977

3078

Lib/ctypes/test/test_values.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ class struct_frozen(Structure):
8080
continue
8181
items.append((entry.name.decode("ascii"), entry.size))
8282

83-
expected = [("__hello__", 142),
84-
("__phello__", -142),
85-
("__phello__.spam", 142),
83+
expected = [("__hello__", 138),
84+
("__phello__", -138),
85+
("__phello__.spam", 138),
8686
]
8787
self.assertEqual(items, expected, "PyImport_FrozenModules example "
8888
"in Doc/library/ctypes.rst may be out of date")

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ def _write_atomic(path, data, mode=0o666):
354354
# Python 3.10b1 3439 (Add ROT_N)
355355
# Python 3.11a1 3450 Use exception table for unwinding ("zero cost" exception handling)
356356
# Python 3.11a1 3451 (Add CALL_METHOD_KW)
357+
# Python 3.11a1 3452 (drop nlocals from marshaled code objects)
357358

358359
#
359360
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -363,7 +364,7 @@ def _write_atomic(path, data, mode=0o666):
363364
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
364365
# in PC/launcher.c must also be updated.
365366

366-
MAGIC_NUMBER = (3451).to_bytes(2, 'little') + b'\r\n'
367+
MAGIC_NUMBER = (3452).to_bytes(2, 'little') + b'\r\n'
367368
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
368369

369370
_PYCACHE = '__pycache__'

0 commit comments

Comments
 (0)