Skip to content

Commit 17c4edc

Browse files
authored
bpo-43693: Revert commits 2c1e258 and b2bf2bc (GH-26530)
* Revert "bpo-43693: Compute deref offsets in compiler (gh-25152)" This reverts commit b2bf2bc. * Revert "bpo-43693: Add new internal code objects fields: co_fastlocalnames and co_fastlocalkinds. (gh-26388)" This reverts commit 2c1e258. These two commits are breaking the refleak buildbots.
1 parent a46c220 commit 17c4edc

23 files changed

+5705
-6026
lines changed

Doc/library/dis.rst

+7-23
Original file line numberDiff line numberDiff line change
@@ -1058,24 +1058,17 @@ All of the following opcodes use their arguments.
10581058

10591059
.. opcode:: LOAD_CLOSURE (i)
10601060

1061-
Pushes a reference to the cell contained in slot ``i`` of the "fast locals"
1062-
storage. The name of the variable is ``co_fastlocalnames[i]``.
1063-
1064-
Note that ``LOAD_CLOSURE`` is effectively an alias for ``LOAD_FAST``.
1065-
It exists to keep bytecode a little more readable.
1066-
1067-
.. versionchanged:: 3.11
1068-
``i`` is no longer offset by the length of ``co_varnames``.
1061+
Pushes a reference to the cell contained in slot *i* of the cell and free
1062+
variable storage. The name of the variable is ``co_cellvars[i]`` if *i* is
1063+
less than the length of *co_cellvars*. Otherwise it is ``co_freevars[i -
1064+
len(co_cellvars)]``.
10691065

10701066

10711067
.. opcode:: LOAD_DEREF (i)
10721068

1073-
Loads the cell contained in slot ``i`` of the "fast locals" storage.
1069+
Loads the cell contained in slot *i* of the cell and free variable storage.
10741070
Pushes a reference to the object the cell contains on the stack.
10751071

1076-
.. versionchanged:: 3.11
1077-
``i`` is no longer offset by the length of ``co_varnames``.
1078-
10791072

10801073
.. opcode:: LOAD_CLASSDEREF (i)
10811074

@@ -1085,29 +1078,20 @@ All of the following opcodes use their arguments.
10851078

10861079
.. versionadded:: 3.4
10871080

1088-
.. versionchanged:: 3.11
1089-
``i`` is no longer offset by the length of ``co_varnames``.
1090-
10911081

10921082
.. opcode:: STORE_DEREF (i)
10931083

1094-
Stores TOS into the cell contained in slot ``i`` of the "fast locals"
1084+
Stores TOS into the cell contained in slot *i* of the cell and free variable
10951085
storage.
10961086

1097-
.. versionchanged:: 3.11
1098-
``i`` is no longer offset by the length of ``co_varnames``.
1099-
11001087

11011088
.. opcode:: DELETE_DEREF (i)
11021089

1103-
Empties the cell contained in slot ``i`` of the "fast locals" storage.
1090+
Empties the cell contained in slot *i* of the cell and free variable storage.
11041091
Used by the :keyword:`del` statement.
11051092

11061093
.. versionadded:: 3.2
11071094

1108-
.. versionchanged:: 3.11
1109-
``i`` is no longer offset by the length of ``co_varnames``.
1110-
11111095

11121096
.. opcode:: RAISE_VARARGS (argc)
11131097

Include/cpython/code.h

+5-15
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
#endif
44

55
typedef uint16_t _Py_CODEUNIT;
6-
// Each oparg must fit in the second half of _Py_CODEUNIT, hence 8 bits.
7-
#define _Py_MAX_OPARG 255
86

97
#ifdef WORDS_BIGENDIAN
108
# define _Py_OPCODE(word) ((word) >> 8)
@@ -16,11 +14,6 @@ typedef uint16_t _Py_CODEUNIT;
1614

1715
typedef struct _PyOpcache _PyOpcache;
1816

19-
20-
// These are duplicated from pycore_code.h.
21-
typedef unsigned char _PyLocalsPlusKind;
22-
typedef _PyLocalsPlusKind *_PyLocalsPlusKinds;
23-
2417
/* Bytecode object */
2518
struct PyCodeObject {
2619
PyObject_HEAD
@@ -60,8 +53,9 @@ struct PyCodeObject {
6053
int co_kwonlyargcount; /* #keyword only arguments */
6154
int co_stacksize; /* #entries needed for evaluation stack */
6255
int co_firstlineno; /* first source line number */
63-
PyObject *co_localsplusnames; /* tuple mapping offsets to names */
64-
_PyLocalsPlusKinds co_localspluskinds; /* array mapping to local kinds */
56+
PyObject *co_varnames; /* tuple of strings (local variable names) */
57+
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
58+
PyObject *co_freevars; /* tuple of strings (free variable names) */
6559
PyObject *co_filename; /* unicode (where it was loaded from) */
6660
PyObject *co_name; /* unicode (name, for reference) */
6761
PyObject *co_linetable; /* string (encoding addr<->lineno mapping) See
@@ -71,15 +65,11 @@ struct PyCodeObject {
7165
/* These fields are set with computed values on new code objects. */
7266

7367
int *co_cell2arg; /* Maps cell vars which are arguments. */
74-
// redundant values (derived from co_localsplusnames and co_localspluskinds)
68+
// These are redundant but offer some performance benefit.
7569
int co_nlocalsplus; /* number of local + cell + free variables */
7670
int co_nlocals; /* number of local variables */
7771
int co_ncellvars; /* number of cell variables */
7872
int co_nfreevars; /* number of free variables */
79-
// lazily-computed values
80-
PyObject *co_varnames; /* tuple of strings (local variable names) */
81-
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
82-
PyObject *co_freevars; /* tuple of strings (free variable names) */
8373

8474
/* The remaining fields are zeroed out on new code objects. */
8575

@@ -153,7 +143,7 @@ struct PyCodeObject {
153143
PyAPI_DATA(PyTypeObject) PyCode_Type;
154144

155145
#define PyCode_Check(op) Py_IS_TYPE(op, &PyCode_Type)
156-
#define PyCode_GetNumFree(op) ((op)->co_nfreevars)
146+
#define PyCode_GetNumFree(op) (PyTuple_GET_SIZE((op)->co_freevars))
157147

158148
/* Public interface */
159149
PyAPI_FUNC(PyCodeObject *) PyCode_New(

Include/internal/pycore_code.h

+3-59
Original file line numberDiff line numberDiff line change
@@ -26,57 +26,6 @@ struct _PyOpcache {
2626
};
2727

2828

29-
/* "Locals plus" for a code object is the set of locals + cell vars +
30-
* free vars. This relates to variable names as well as offsets into
31-
* the "fast locals" storage array of execution frames. The compiler
32-
* builds the list of names, their offsets, and the corresponding
33-
* kind of local.
34-
*
35-
* Those kinds represent the source of the initial value and the
36-
* variable's scope (as related to closures). A "local" is an
37-
* argument or other variable defined in the current scope. A "free"
38-
* variable is one that is defined in an outer scope and comes from
39-
* the function's closure. A "cell" variable is a local that escapes
40-
* into an inner function as part of a closure, and thus must be
41-
* wrapped in a cell. Any "local" can also be a "cell", but the
42-
* "free" kind is mutually exclusive with both.
43-
*/
44-
45-
// We would use an enum if C let us specify the storage type.
46-
typedef unsigned char _PyLocalsPlusKind;
47-
/* Note that these all fit within _PyLocalsPlusKind, as do combinations. */
48-
// Later, we will use the smaller numbers to differentiate the different
49-
// kinds of locals (e.g. pos-only arg, varkwargs, local-only).
50-
#define CO_FAST_LOCAL 0x20
51-
#define CO_FAST_CELL 0x40
52-
#define CO_FAST_FREE 0x80
53-
54-
typedef _PyLocalsPlusKind *_PyLocalsPlusKinds;
55-
56-
static inline int
57-
_PyCode_InitLocalsPlusKinds(int num, _PyLocalsPlusKinds *pkinds)
58-
{
59-
if (num == 0) {
60-
*pkinds = NULL;
61-
return 0;
62-
}
63-
_PyLocalsPlusKinds kinds = PyMem_NEW(_PyLocalsPlusKind, num);
64-
if (kinds == NULL) {
65-
PyErr_NoMemory();
66-
return -1;
67-
}
68-
*pkinds = kinds;
69-
return 0;
70-
}
71-
72-
static inline void
73-
_PyCode_ClearLocalsPlusKinds(_PyLocalsPlusKinds kinds)
74-
{
75-
if (kinds != NULL) {
76-
PyMem_Free(kinds);
77-
}
78-
}
79-
8029
struct _PyCodeConstructor {
8130
/* metadata */
8231
PyObject *filename;
@@ -93,13 +42,13 @@ struct _PyCodeConstructor {
9342
PyObject *names;
9443

9544
/* mapping frame offsets to information */
96-
PyObject *localsplusnames;
97-
_PyLocalsPlusKinds localspluskinds;
45+
PyObject *varnames;
46+
PyObject *cellvars;
47+
PyObject *freevars;
9848

9949
/* args (within varnames) */
10050
int argcount;
10151
int posonlyargcount;
102-
// XXX Replace argcount with posorkwargcount (argcount - posonlyargcount).
10352
int kwonlyargcount;
10453

10554
/* needed to create the frame */
@@ -126,11 +75,6 @@ PyAPI_FUNC(PyCodeObject *) _PyCode_New(struct _PyCodeConstructor *);
12675

12776
int _PyCode_InitOpcache(PyCodeObject *co);
12877

129-
/* Getters for internal PyCodeObject data. */
130-
PyAPI_FUNC(PyObject *) _PyCode_GetVarnames(PyCodeObject *);
131-
PyAPI_FUNC(PyObject *) _PyCode_GetCellvars(PyCodeObject *);
132-
PyAPI_FUNC(PyObject *) _PyCode_GetFreevars(PyCodeObject *);
133-
13478

13579
#ifdef __cplusplus
13680
}

Lib/ctypes/test/test_values.py

+3-3
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__", 128),
84-
("__phello__", -128),
85-
("__phello__.spam", 128),
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/dis.py

+26-27
Original file line numberDiff line numberDiff line change
@@ -273,15 +273,15 @@ def get_instructions(x, *, first_line=None):
273273
the disassembled code object.
274274
"""
275275
co = _get_code_object(x)
276+
cell_names = co.co_cellvars + co.co_freevars
276277
linestarts = dict(findlinestarts(co))
277278
if first_line is not None:
278279
line_offset = first_line - co.co_firstlineno
279280
else:
280281
line_offset = 0
281-
return _get_instructions_bytes(co.co_code,
282-
co._varname_from_oparg,
283-
co.co_names, co.co_consts,
284-
linestarts, line_offset)
282+
return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
283+
co.co_consts, cell_names, linestarts,
284+
line_offset)
285285

286286
def _get_const_info(const_index, const_list):
287287
"""Helper to get optional details about const references
@@ -295,16 +295,16 @@ def _get_const_info(const_index, const_list):
295295
argval = const_list[const_index]
296296
return argval, repr(argval)
297297

298-
def _get_name_info(name_index, get_name, **extrainfo):
298+
def _get_name_info(name_index, name_list):
299299
"""Helper to get optional details about named references
300300
301301
Returns the dereferenced name as both value and repr if the name
302302
list is defined.
303303
Otherwise returns the name index and its repr().
304304
"""
305305
argval = name_index
306-
if get_name is not None:
307-
argval = get_name(name_index, **extrainfo)
306+
if name_list is not None:
307+
argval = name_list[name_index]
308308
argrepr = argval
309309
else:
310310
argrepr = repr(argval)
@@ -336,10 +336,8 @@ def parse_exception_table(code):
336336
except StopIteration:
337337
return entries
338338

339-
def _get_instructions_bytes(code, varname_from_oparg=None,
340-
names=None, constants=None,
341-
linestarts=None, line_offset=0,
342-
exception_entries=()):
339+
def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
340+
cells=None, linestarts=None, line_offset=0, exception_entries=()):
343341
"""Iterate over the instructions in a bytecode string.
344342
345343
Generates a sequence of Instruction namedtuples giving the details of each
@@ -348,7 +346,6 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
348346
arguments.
349347
350348
"""
351-
get_name = None if names is None else names.__getitem__
352349
labels = set(findlabels(code))
353350
for start, end, target, _, _ in exception_entries:
354351
for i in range(start, end):
@@ -371,18 +368,20 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
371368
if op in hasconst:
372369
argval, argrepr = _get_const_info(arg, constants)
373370
elif op in hasname:
374-
argval, argrepr = _get_name_info(arg, get_name)
371+
argval, argrepr = _get_name_info(arg, names)
375372
elif op in hasjabs:
376373
argval = arg*2
377374
argrepr = "to " + repr(argval)
378375
elif op in hasjrel:
379376
argval = offset + 2 + arg*2
380377
argrepr = "to " + repr(argval)
381-
elif op in haslocal or op in hasfree:
382-
argval, argrepr = _get_name_info(arg, varname_from_oparg)
378+
elif op in haslocal:
379+
argval, argrepr = _get_name_info(arg, varnames)
383380
elif op in hascompare:
384381
argval = cmp_op[arg]
385382
argrepr = argval
383+
elif op in hasfree:
384+
argval, argrepr = _get_name_info(arg, cells)
386385
elif op == FORMAT_VALUE:
387386
argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]
388387
argval = (argval, bool(arg & 0x4))
@@ -399,11 +398,11 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
399398

400399
def disassemble(co, lasti=-1, *, file=None):
401400
"""Disassemble a code object."""
401+
cell_names = co.co_cellvars + co.co_freevars
402402
linestarts = dict(findlinestarts(co))
403403
exception_entries = parse_exception_table(co)
404-
_disassemble_bytes(co.co_code, lasti,
405-
co._varname_from_oparg,
406-
co.co_names, co.co_consts, linestarts, file=file,
404+
_disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
405+
co.co_consts, cell_names, linestarts, file=file,
407406
exception_entries=exception_entries)
408407

409408
def _disassemble_recursive(co, *, file=None, depth=None):
@@ -417,8 +416,8 @@ def _disassemble_recursive(co, *, file=None, depth=None):
417416
print("Disassembly of %r:" % (x,), file=file)
418417
_disassemble_recursive(x, file=file, depth=depth)
419418

420-
def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
421-
names=None, constants=None, linestarts=None,
419+
def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
420+
constants=None, cells=None, linestarts=None,
422421
*, file=None, line_offset=0, exception_entries=()):
423422
# Omit the line number column entirely if we have no line number info
424423
show_lineno = bool(linestarts)
@@ -435,8 +434,8 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
435434
offset_width = len(str(maxoffset))
436435
else:
437436
offset_width = 4
438-
for instr in _get_instructions_bytes(code, varname_from_oparg, names,
439-
constants, linestarts,
437+
for instr in _get_instructions_bytes(code, varnames, names,
438+
constants, cells, linestarts,
440439
line_offset=line_offset, exception_entries=exception_entries):
441440
new_source_line = (show_lineno and
442441
instr.starts_line is not None and
@@ -518,16 +517,16 @@ def __init__(self, x, *, first_line=None, current_offset=None):
518517
else:
519518
self.first_line = first_line
520519
self._line_offset = first_line - co.co_firstlineno
520+
self._cell_names = co.co_cellvars + co.co_freevars
521521
self._linestarts = dict(findlinestarts(co))
522522
self._original_object = x
523523
self.current_offset = current_offset
524524
self.exception_entries = parse_exception_table(co)
525525

526526
def __iter__(self):
527527
co = self.codeobj
528-
return _get_instructions_bytes(co.co_code,
529-
co._varname_from_oparg,
530-
co.co_names, co.co_consts,
528+
return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
529+
co.co_consts, self._cell_names,
531530
self._linestarts,
532531
line_offset=self._line_offset,
533532
exception_entries=self.exception_entries)
@@ -555,9 +554,9 @@ def dis(self):
555554
else:
556555
offset = -1
557556
with io.StringIO() as output:
558-
_disassemble_bytes(co.co_code,
559-
varname_from_oparg=co._varname_from_oparg,
557+
_disassemble_bytes(co.co_code, varnames=co.co_varnames,
560558
names=co.co_names, constants=co.co_consts,
559+
cells=self._cell_names,
561560
linestarts=self._linestarts,
562561
line_offset=self._line_offset,
563562
file=output,

Lib/importlib/_bootstrap_external.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,6 @@ def _write_atomic(path, data, mode=0o666):
355355
# Python 3.11a1 3450 Use exception table for unwinding ("zero cost" exception handling)
356356
# Python 3.11a1 3451 (Add CALL_METHOD_KW)
357357
# Python 3.11a1 3452 (drop nlocals from marshaled code objects)
358-
# Python 3.11a1 3453 (add co_fastlocalnames and co_fastlocalkinds)
359-
# Python 3.11a1 3454 (compute cell offsets relative to locals bpo-43693)
360358

361359
#
362360
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -366,7 +364,7 @@ def _write_atomic(path, data, mode=0o666):
366364
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
367365
# in PC/launcher.c must also be updated.
368366

369-
MAGIC_NUMBER = (3454).to_bytes(2, 'little') + b'\r\n'
367+
MAGIC_NUMBER = (3452).to_bytes(2, 'little') + b'\r\n'
370368
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
371369

372370
_PYCACHE = '__pycache__'

0 commit comments

Comments
 (0)