Coverage Report

Created: 2026-09-03 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython3/Python/assemble.c
Line
Count
Source
1
#include "Python.h"
2
#include "pycore_code.h"            // write_location_entry_start()
3
#include "pycore_compile.h"
4
#include "pycore_instruction_sequence.h"
5
#include "pycore_opcode_utils.h"    // IS_BACKWARDS_JUMP_OPCODE
6
#include "pycore_opcode_metadata.h" // is_pseudo_target, _PyOpcode_Caches
7
#include "pycore_symtable.h"        // _Py_SourceLocation
8
9
#include <stdbool.h>
10
11
52.7k
#define DEFAULT_CODE_SIZE 128
12
52.7k
#define DEFAULT_LNOTAB_SIZE 16
13
52.7k
#define DEFAULT_CNOTAB_SIZE 32
14
15
#undef SUCCESS
16
#undef ERROR
17
5.73M
#define SUCCESS 0
18
52.7k
#define ERROR -1
19
20
#define RETURN_IF_ERROR(X)  \
21
6.00M
    if ((X) < 0) {          \
22
0
        return ERROR;       \
23
0
    }
24
25
typedef _Py_SourceLocation location;
26
typedef _PyInstruction instruction;
27
typedef _PyInstructionSequence instr_sequence;
28
29
static inline bool
30
same_location(location a, location b)
31
6.76M
{
32
6.76M
    return a.lineno == b.lineno &&
33
3.17M
           a.end_lineno == b.end_lineno &&
34
3.16M
           a.col_offset == b.col_offset &&
35
1.96M
           a.end_col_offset == b.end_col_offset;
36
6.76M
}
37
38
static int
39
instr_size(instruction *instr)
40
21.4M
{
41
21.4M
    int opcode = instr->i_opcode;
42
21.4M
    int oparg = instr->i_oparg;
43
21.4M
    assert(!IS_PSEUDO_INSTR(opcode));
44
21.4M
    assert(OPCODE_HAS_ARG(opcode) || oparg == 0);
45
21.4M
    int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg);
46
21.4M
    int caches = _PyOpcode_Caches[opcode];
47
21.4M
    return extended_args + 1 + caches;
48
21.4M
}
49
50
struct assembler {
51
    PyObject *a_bytecode;  /* bytes containing bytecode */
52
    int a_offset;              /* offset into bytecode */
53
    PyObject *a_except_table;  /* bytes containing exception table */
54
    int a_except_table_off;    /* offset into exception table */
55
    /* Location Info */
56
    int a_lineno;          /* lineno of last emitted instruction */
57
    PyBytesWriter *a_linetable_writer; /* writer containing location info */
58
    PyObject *a_linetable; /* bytes object containing location info */
59
    int a_location_off;    /* offset of last written location info frame */
60
};
61
62
static int
63
assemble_init(struct assembler *a, int firstlineno)
64
52.7k
{
65
52.7k
    memset(a, 0, sizeof(struct assembler));
66
52.7k
    a->a_lineno = firstlineno;
67
52.7k
    a->a_bytecode = PyBytes_FromStringAndSize(NULL, DEFAULT_CODE_SIZE);
68
52.7k
    if (a->a_bytecode == NULL) {
69
0
        goto error;
70
0
    }
71
52.7k
    a->a_linetable_writer = PyBytesWriter_Create(DEFAULT_CNOTAB_SIZE);
72
52.7k
    if (a->a_linetable_writer == NULL) {
73
0
        goto error;
74
0
    }
75
52.7k
    a->a_except_table = PyBytes_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE);
76
52.7k
    if (a->a_except_table == NULL) {
77
0
        goto error;
78
0
    }
79
52.7k
    return SUCCESS;
80
0
error:
81
0
    Py_CLEAR(a->a_bytecode);
82
0
    PyBytesWriter_Discard(a->a_linetable_writer);
83
0
    Py_CLEAR(a->a_except_table);
84
0
    return ERROR;
85
52.7k
}
86
87
static void
88
assemble_free(struct assembler *a)
89
52.7k
{
90
52.7k
    Py_XDECREF(a->a_bytecode);
91
52.7k
    PyBytesWriter_Discard(a->a_linetable_writer);
92
52.7k
    Py_XDECREF(a->a_linetable);
93
52.7k
    Py_XDECREF(a->a_except_table);
94
52.7k
}
95
96
static inline void
97
1.25M
write_except_byte(struct assembler *a, int byte) {
98
1.25M
    unsigned char *p = (unsigned char *) PyBytes_AS_STRING(a->a_except_table);
99
1.25M
    p[a->a_except_table_off++] = byte;
100
1.25M
}
101
102
531k
#define CONTINUATION_BIT 64
103
104
static void
105
assemble_emit_exception_table_item(struct assembler *a, int value, int msb)
106
719k
{
107
719k
    assert ((msb | 128) == 128);
108
719k
    assert(value >= 0 && value < (1 << 30));
109
719k
    if (value >= 1 << 24) {
110
0
        write_except_byte(a, (value >> 24) | CONTINUATION_BIT | msb);
111
0
        msb = 0;
112
0
    }
113
719k
    if (value >= 1 << 18) {
114
0
        write_except_byte(a, ((value >> 18)&0x3f) | CONTINUATION_BIT | msb);
115
0
        msb = 0;
116
0
    }
117
719k
    if (value >= 1 << 12) {
118
183k
        write_except_byte(a, ((value >> 12)&0x3f) | CONTINUATION_BIT | msb);
119
183k
        msb = 0;
120
183k
    }
121
719k
    if (value >= 1 << 6) {
122
347k
        write_except_byte(a, ((value >> 6)&0x3f) | CONTINUATION_BIT | msb);
123
347k
        msb = 0;
124
347k
    }
125
719k
    write_except_byte(a, (value&0x3f) | msb);
126
719k
}
127
128
/* See InternalDocs/exception_handling.md for details of layout */
129
179k
#define MAX_SIZE_OF_ENTRY 20
130
131
static int
132
assemble_emit_exception_table_entry(struct assembler *a, int start, int end,
133
                                    int handler_offset,
134
                                    _PyExceptHandlerInfo *handler)
135
179k
{
136
179k
    Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table);
137
179k
    if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) {
138
8.06k
        RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, len * 2));
139
8.06k
    }
140
179k
    int size = end-start;
141
179k
    assert(end > start);
142
179k
    int target = handler_offset;
143
179k
    int depth = handler->h_startdepth - 1;
144
179k
    if (handler->h_preserve_lasti > 0) {
145
133k
        depth -= 1;
146
133k
    }
147
179k
    assert(depth >= 0);
148
179k
    int depth_lasti = (depth<<1) | handler->h_preserve_lasti;
149
179k
    assemble_emit_exception_table_item(a, start, (1<<7));
150
179k
    assemble_emit_exception_table_item(a, size, 0);
151
179k
    assemble_emit_exception_table_item(a, target, 0);
152
179k
    assemble_emit_exception_table_item(a, depth_lasti, 0);
153
179k
    return SUCCESS;
154
179k
}
155
156
static int
157
assemble_exception_table(struct assembler *a, instr_sequence *instrs)
158
52.7k
{
159
52.7k
    int ioffset = 0;
160
52.7k
    _PyExceptHandlerInfo handler;
161
52.7k
    handler.h_label = -1;
162
52.7k
    handler.h_startdepth = -1;
163
52.7k
    handler.h_preserve_lasti = -1;
164
52.7k
    int start = -1;
165
3.43M
    for (int i = 0; i < instrs->s_used; i++) {
166
3.38M
        instruction *instr = &instrs->s_instrs[i];
167
3.38M
        if (instr->i_except_handler_info.h_label != handler.h_label) {
168
235k
            if (handler.h_label >= 0) {
169
179k
                int handler_offset = instrs->s_instrs[handler.h_label].i_offset;
170
179k
                RETURN_IF_ERROR(
171
179k
                    assemble_emit_exception_table_entry(a, start, ioffset,
172
179k
                                                        handler_offset,
173
179k
                                                        &handler));
174
179k
            }
175
235k
            start = ioffset;
176
235k
            handler = instr->i_except_handler_info;
177
235k
        }
178
3.38M
        ioffset += instr_size(instr);
179
3.38M
    }
180
52.7k
    if (handler.h_label >= 0) {
181
0
        int handler_offset = instrs->s_instrs[handler.h_label].i_offset;
182
0
        RETURN_IF_ERROR(assemble_emit_exception_table_entry(a, start, ioffset,
183
0
                                                            handler_offset,
184
0
                                                            &handler));
185
0
    }
186
52.7k
    return SUCCESS;
187
52.7k
}
188
189
190
/* Code location emitting code. See locations.md for a description of the format. */
191
192
#define MSB 0x80
193
194
static void
195
write_location_byte(struct assembler* a, int val)
196
947k
{
197
947k
    uint8_t *linetable = PyBytesWriter_GetData(a->a_linetable_writer);
198
947k
    linetable[a->a_location_off] = val & 255;
199
947k
    a->a_location_off++;
200
947k
}
201
202
203
static uint8_t *
204
location_pointer(struct assembler* a)
205
5.58M
{
206
5.58M
    uint8_t *linetable = PyBytesWriter_GetData(a->a_linetable_writer);
207
5.58M
    return linetable + a->a_location_off;
208
5.58M
}
209
210
static void
211
write_location_first_byte(struct assembler* a, int code, int length)
212
1.71M
{
213
1.71M
    a->a_location_off += write_location_entry_start(
214
1.71M
        location_pointer(a), code, length);
215
1.71M
}
216
217
static void
218
write_location_varint(struct assembler* a, unsigned int val)
219
2.90M
{
220
2.90M
    uint8_t *ptr = location_pointer(a);
221
2.90M
    a->a_location_off += write_varint(ptr, val);
222
2.90M
}
223
224
225
static void
226
write_location_signed_varint(struct assembler* a, int val)
227
969k
{
228
969k
    uint8_t *ptr = location_pointer(a);
229
969k
    a->a_location_off += write_signed_varint(ptr, val);
230
969k
}
231
232
static void
233
write_location_info_short_form(struct assembler* a, int length, int column, int end_column)
234
453k
{
235
453k
    assert(length > 0 &&  length <= 8);
236
453k
    int column_low_bits = column & 7;
237
453k
    int column_group = column >> 3;
238
453k
    assert(column < 80);
239
453k
    assert(end_column >= column);
240
453k
    assert(end_column - column < 16);
241
453k
    write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length);
242
453k
    write_location_byte(a, (column_low_bits << 4) | (end_column - column));
243
453k
}
244
245
static void
246
write_location_info_oneline_form(struct assembler* a, int length, int line_delta, int column, int end_column)
247
247k
{
248
247k
    assert(length > 0 &&  length <= 8);
249
247k
    assert(line_delta >= 0 && line_delta < 3);
250
247k
    assert(column < 128);
251
247k
    assert(end_column < 128);
252
247k
    write_location_first_byte(a, PY_CODE_LOCATION_INFO_ONE_LINE0 + line_delta, length);
253
247k
    write_location_byte(a, column);
254
247k
    write_location_byte(a, end_column);
255
247k
}
256
257
static void
258
write_location_info_long_form(struct assembler* a, location loc, int length)
259
966k
{
260
966k
    assert(length > 0 &&  length <= 8);
261
966k
    write_location_first_byte(a, PY_CODE_LOCATION_INFO_LONG, length);
262
966k
    write_location_signed_varint(a, loc.lineno - a->a_lineno);
263
966k
    assert(loc.end_lineno >= loc.lineno);
264
966k
    write_location_varint(a, loc.end_lineno - loc.lineno);
265
966k
    write_location_varint(a, loc.col_offset + 1);
266
966k
    write_location_varint(a, loc.end_col_offset + 1);
267
966k
}
268
269
static void
270
write_location_info_none(struct assembler* a, int length)
271
46.8k
{
272
46.8k
    write_location_first_byte(a, PY_CODE_LOCATION_INFO_NONE, length);
273
46.8k
}
274
275
static void
276
write_location_info_no_column(struct assembler* a, int length, int line_delta)
277
2.96k
{
278
2.96k
    write_location_first_byte(a, PY_CODE_LOCATION_INFO_NO_COLUMNS, length);
279
2.96k
    write_location_signed_varint(a, line_delta);
280
2.96k
}
281
282
1.71M
#define THEORETICAL_MAX_ENTRY_SIZE 25 /* 1 + 6 + 6 + 6 + 6 */
283
284
285
static int
286
write_location_info_entry(struct assembler* a, location loc, int isize)
287
1.71M
{
288
1.71M
    Py_ssize_t len = PyBytesWriter_GetSize(a->a_linetable_writer);
289
1.71M
    if (a->a_location_off + THEORETICAL_MAX_ENTRY_SIZE >= len) {
290
61.9k
        assert(len > THEORETICAL_MAX_ENTRY_SIZE);
291
61.9k
        RETURN_IF_ERROR(PyBytesWriter_Resize(a->a_linetable_writer, len * 2));
292
61.9k
    }
293
1.71M
    if (loc.lineno == NO_LOCATION.lineno) {
294
46.8k
        write_location_info_none(a, isize);
295
46.8k
        return SUCCESS;
296
46.8k
    }
297
1.67M
    int line_delta = loc.lineno - a->a_lineno;
298
1.67M
    int column = loc.col_offset;
299
1.67M
    int end_column = loc.end_col_offset;
300
1.67M
    if (column < 0 || end_column < 0) {
301
2.96k
        if (loc.end_lineno == loc.lineno || loc.end_lineno < 0) {
302
2.96k
            write_location_info_no_column(a, isize, line_delta);
303
2.96k
            a->a_lineno = loc.lineno;
304
2.96k
            return SUCCESS;
305
2.96k
        }
306
2.96k
    }
307
1.66M
    else if (loc.end_lineno == loc.lineno) {
308
1.62M
        if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) {
309
453k
            write_location_info_short_form(a, isize, column, end_column);
310
453k
            return SUCCESS;
311
453k
        }
312
1.17M
        if (line_delta >= 0 && line_delta < 3 && column < 128 && end_column < 128) {
313
247k
            write_location_info_oneline_form(a, isize, line_delta, column, end_column);
314
247k
            a->a_lineno = loc.lineno;
315
247k
            return SUCCESS;
316
247k
        }
317
1.17M
    }
318
966k
    write_location_info_long_form(a, loc, isize);
319
966k
    a->a_lineno = loc.lineno;
320
966k
    return SUCCESS;
321
1.67M
}
322
323
static int
324
assemble_emit_location(struct assembler* a, location loc, int isize)
325
1.53M
{
326
1.53M
    if (isize == 0) {
327
32.4k
        return SUCCESS;
328
32.4k
    }
329
1.71M
    while (isize > 8) {
330
216k
        RETURN_IF_ERROR(write_location_info_entry(a, loc, 8));
331
216k
        isize -= 8;
332
216k
    }
333
1.50M
    return write_location_info_entry(a, loc, isize);
334
1.50M
}
335
336
static int
337
assemble_location_info(struct assembler *a, instr_sequence *instrs,
338
                       int firstlineno)
339
52.7k
{
340
52.7k
    a->a_lineno = firstlineno;
341
52.7k
    location loc = NO_LOCATION;
342
3.43M
    for (int i = instrs->s_used-1; i >= 0; i--) {
343
3.38M
        instruction *instr = &instrs->s_instrs[i];
344
3.38M
        if (same_location(instr->i_loc, NEXT_LOCATION)) {
345
693
            if (IS_TERMINATOR_OPCODE(instr->i_opcode)) {
346
0
                instr->i_loc = NO_LOCATION;
347
0
            }
348
693
            else {
349
693
                assert(i < instrs->s_used-1);
350
693
                instr->i_loc = instr[1].i_loc;
351
693
            }
352
693
        }
353
3.38M
    }
354
52.7k
    int size = 0;
355
3.43M
    for (int i = 0; i < instrs->s_used; i++) {
356
3.38M
        instruction *instr = &instrs->s_instrs[i];
357
3.38M
        if (!same_location(loc, instr->i_loc)) {
358
1.48M
                RETURN_IF_ERROR(assemble_emit_location(a, loc, size));
359
1.48M
                loc = instr->i_loc;
360
1.48M
                size = 0;
361
1.48M
        }
362
3.38M
        size += instr_size(instr);
363
3.38M
    }
364
52.7k
    RETURN_IF_ERROR(assemble_emit_location(a, loc, size));
365
52.7k
    return SUCCESS;
366
52.7k
}
367
368
static void
369
write_instr(_Py_CODEUNIT *codestr, instruction *instr, int ilen)
370
3.38M
{
371
3.38M
    int opcode = instr->i_opcode;
372
3.38M
    assert(!IS_PSEUDO_INSTR(opcode));
373
3.38M
    int oparg = instr->i_oparg;
374
3.38M
    assert(OPCODE_HAS_ARG(opcode) || oparg == 0);
375
3.38M
    int caches = _PyOpcode_Caches[opcode];
376
3.38M
    switch (ilen - caches) {
377
0
        case 4:
378
0
            codestr->op.code = EXTENDED_ARG;
379
0
            codestr->op.arg = (oparg >> 24) & 0xFF;
380
0
            codestr++;
381
0
            _Py_FALLTHROUGH;
382
15
        case 3:
383
15
            codestr->op.code = EXTENDED_ARG;
384
15
            codestr->op.arg = (oparg >> 16) & 0xFF;
385
15
            codestr++;
386
15
            _Py_FALLTHROUGH;
387
53.7k
        case 2:
388
53.7k
            codestr->op.code = EXTENDED_ARG;
389
53.7k
            codestr->op.arg = (oparg >> 8) & 0xFF;
390
53.7k
            codestr++;
391
53.7k
            _Py_FALLTHROUGH;
392
3.38M
        case 1:
393
3.38M
            codestr->op.code = opcode;
394
3.38M
            codestr->op.arg = oparg & 0xFF;
395
3.38M
            codestr++;
396
3.38M
            break;
397
0
        default:
398
0
            Py_UNREACHABLE();
399
3.38M
    }
400
5.82M
    while (caches--) {
401
2.44M
        codestr->op.code = CACHE;
402
2.44M
        codestr->op.arg = 0;
403
2.44M
        codestr++;
404
2.44M
    }
405
3.38M
}
406
407
/* assemble_emit_instr()
408
   Extend the bytecode with a new instruction.
409
   Update lnotab if necessary.
410
*/
411
412
static int
413
assemble_emit_instr(struct assembler *a, instruction *instr)
414
3.38M
{
415
3.38M
    Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode);
416
3.38M
    _Py_CODEUNIT *code;
417
418
3.38M
    int size = instr_size(instr);
419
3.38M
    if (a->a_offset + size >= len / (int)sizeof(_Py_CODEUNIT)) {
420
17.7k
        if (len > PY_SSIZE_T_MAX / 2) {
421
0
            PyErr_NoMemory();
422
0
            return ERROR;
423
0
        }
424
17.7k
        RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, len * 2));
425
17.7k
    }
426
3.38M
    code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset;
427
3.38M
    a->a_offset += size;
428
3.38M
    write_instr(code, instr, size);
429
3.38M
    return SUCCESS;
430
3.38M
}
431
432
static int
433
assemble_emit(struct assembler *a, instr_sequence *instrs,
434
              int first_lineno, PyObject *const_cache)
435
52.7k
{
436
52.7k
    RETURN_IF_ERROR(assemble_init(a, first_lineno));
437
438
3.43M
    for (int i = 0; i < instrs->s_used; i++) {
439
3.38M
        instruction *instr = &instrs->s_instrs[i];
440
3.38M
        RETURN_IF_ERROR(assemble_emit_instr(a, instr));
441
3.38M
    }
442
443
52.7k
    RETURN_IF_ERROR(assemble_location_info(a, instrs, a->a_lineno));
444
445
52.7k
    RETURN_IF_ERROR(assemble_exception_table(a, instrs));
446
447
52.7k
    RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off));
448
52.7k
    RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_except_table));
449
450
52.7k
    a->a_linetable = PyBytesWriter_FinishWithSize(a->a_linetable_writer,
451
52.7k
                                                  a->a_location_off);
452
52.7k
    a->a_linetable_writer = NULL;
453
52.7k
    if (a->a_linetable == NULL) {
454
0
        return ERROR;
455
0
    }
456
52.7k
    RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_linetable));
457
458
52.7k
    RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT)));
459
52.7k
    RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_bytecode));
460
52.7k
    return SUCCESS;
461
52.7k
}
462
463
static PyObject *
464
dict_keys_inorder(PyObject *dict, Py_ssize_t offset)
465
52.7k
{
466
52.7k
    PyObject *tuple, *k, *v;
467
52.7k
    Py_ssize_t pos = 0, size = PyDict_GET_SIZE(dict);
468
469
52.7k
    tuple = PyTuple_New(size);
470
52.7k
    if (tuple == NULL)
471
0
        return NULL;
472
252k
    while (PyDict_Next(dict, &pos, &k, &v)) {
473
200k
        Py_ssize_t i = PyLong_AsSsize_t(v);
474
200k
        if (i == -1 && PyErr_Occurred()) {
475
0
            Py_DECREF(tuple);
476
0
            return NULL;
477
0
        }
478
200k
        assert((i - offset) < size);
479
200k
        assert((i - offset) >= 0);
480
200k
        PyTuple_SET_ITEM(tuple, i - offset, Py_NewRef(k));
481
200k
    }
482
52.7k
    return tuple;
483
52.7k
}
484
485
// This is in codeobject.c.
486
extern void _Py_set_localsplus_info(int, PyObject *, unsigned char,
487
                                   PyObject *, PyObject *);
488
489
static int
490
compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus,
491
                        int flags, PyObject *names, PyObject *kinds)
492
52.7k
{
493
52.7k
    PyObject *k, *v;
494
52.7k
    Py_ssize_t pos = 0;
495
496
    // Set the locals kinds.  Arg vars fill the first portion of the list.
497
52.7k
    struct {
498
52.7k
        int count;
499
52.7k
        _PyLocals_Kind kind;
500
52.7k
    }  argvarkinds[6] = {
501
52.7k
        {(int)umd->u_posonlyargcount, CO_FAST_ARG_POS},
502
52.7k
        {(int)umd->u_argcount, CO_FAST_ARG_POS | CO_FAST_ARG_KW},
503
52.7k
        {(int)umd->u_kwonlyargcount, CO_FAST_ARG_KW},
504
52.7k
        {!!(flags & CO_VARARGS), CO_FAST_ARG_VAR | CO_FAST_ARG_POS},
505
52.7k
        {!!(flags & CO_VARKEYWORDS), CO_FAST_ARG_VAR | CO_FAST_ARG_KW},
506
52.7k
        {-1, 0},  // the remaining local vars
507
52.7k
    };
508
52.7k
    int max = 0;
509
369k
    for (int i = 0; i < 6; i++) {
510
316k
        max = argvarkinds[i].count < 0
511
316k
            ? INT_MAX
512
316k
            : max + argvarkinds[i].count;
513
403k
        while (pos < max && PyDict_Next(umd->u_varnames, &pos, &k, &v)) {
514
86.6k
            int offset = PyLong_AsInt(v);
515
86.6k
            if (offset == -1 && PyErr_Occurred()) {
516
0
                return ERROR;
517
0
            }
518
86.6k
            assert(offset >= 0);
519
86.6k
            assert(offset < nlocalsplus);
520
521
86.6k
            _PyLocals_Kind kind = CO_FAST_LOCAL | argvarkinds[i].kind;
522
523
86.6k
            int has_key = PyDict_Contains(umd->u_fasthidden, k);
524
86.6k
            RETURN_IF_ERROR(has_key);
525
86.6k
            if (has_key) {
526
3.82k
                kind |= CO_FAST_HIDDEN;
527
3.82k
            }
528
529
86.6k
            has_key = PyDict_Contains(umd->u_cellvars, k);
530
86.6k
            RETURN_IF_ERROR(has_key);
531
86.6k
            if (has_key) {
532
104
                kind |= CO_FAST_CELL;
533
104
            }
534
535
86.6k
            _Py_set_localsplus_info(offset, k, kind, names, kinds);
536
86.6k
        }
537
316k
    }
538
52.7k
    int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames);
539
540
    // This counter mirrors the fix done in fix_cell_offsets().
541
52.7k
    int numdropped = 0, cellvar_offset = -1;
542
52.7k
    pos = 0;
543
64.7k
    while (PyDict_Next(umd->u_cellvars, &pos, &k, &v)) {
544
11.9k
        int has_name = PyDict_Contains(umd->u_varnames, k);
545
11.9k
        RETURN_IF_ERROR(has_name);
546
11.9k
        if (has_name) {
547
            // Skip cells that are already covered by locals.
548
104
            numdropped += 1;
549
104
            continue;
550
104
        }
551
552
11.8k
        cellvar_offset = PyLong_AsInt(v);
553
11.8k
        if (cellvar_offset == -1 && PyErr_Occurred()) {
554
0
            return ERROR;
555
0
        }
556
11.8k
        assert(cellvar_offset >= 0);
557
11.8k
        cellvar_offset += nlocals - numdropped;
558
11.8k
        assert(cellvar_offset < nlocalsplus);
559
11.8k
        _Py_set_localsplus_info(cellvar_offset, k, CO_FAST_CELL, names, kinds);
560
11.8k
    }
561
562
52.7k
    pos = 0;
563
65.1k
    while (PyDict_Next(umd->u_freevars, &pos, &k, &v)) {
564
12.3k
        int offset = PyLong_AsInt(v);
565
12.3k
        if (offset == -1 && PyErr_Occurred()) {
566
0
            return ERROR;
567
0
        }
568
12.3k
        assert(offset >= 0);
569
12.3k
        offset += nlocals - numdropped;
570
12.3k
        assert(offset < nlocalsplus);
571
        /* XXX If the assertion below fails it is most likely because a freevar
572
           was added to u_freevars with the wrong index due to not taking into
573
           account cellvars already present, see gh-128632. */
574
12.3k
        assert(offset > cellvar_offset);
575
12.3k
        _Py_set_localsplus_info(offset, k, CO_FAST_FREE, names, kinds);
576
12.3k
    }
577
52.7k
    return SUCCESS;
578
52.7k
}
579
580
static PyCodeObject *
581
makecode(_PyCompile_CodeUnitMetadata *umd, struct assembler *a, PyObject *const_cache,
582
         PyObject *constslist, int maxdepth, int nlocalsplus, int code_flags,
583
         PyObject *filename)
584
52.7k
{
585
52.7k
    PyCodeObject *co = NULL;
586
52.7k
    PyObject *names = NULL;
587
52.7k
    PyObject *consts = NULL;
588
52.7k
    PyObject *localsplusnames = NULL;
589
52.7k
    PyObject *localspluskinds = NULL;
590
52.7k
    names = dict_keys_inorder(umd->u_names, 0);
591
52.7k
    if (!names) {
592
0
        goto error;
593
0
    }
594
52.7k
    if (_PyCompile_ConstCacheMergeOne(const_cache, &names) < 0) {
595
0
        goto error;
596
0
    }
597
598
52.7k
    consts = PyList_AsTuple(constslist); /* PyCode_New requires a tuple */
599
52.7k
    if (consts == NULL) {
600
0
        goto error;
601
0
    }
602
52.7k
    if (_PyCompile_ConstCacheMergeOne(const_cache, &consts) < 0) {
603
0
        goto error;
604
0
    }
605
606
52.7k
    assert(umd->u_posonlyargcount < INT_MAX);
607
52.7k
    assert(umd->u_argcount < INT_MAX);
608
52.7k
    assert(umd->u_kwonlyargcount < INT_MAX);
609
52.7k
    int posonlyargcount = (int)umd->u_posonlyargcount;
610
52.7k
    int posorkwargcount = (int)umd->u_argcount;
611
52.7k
    assert(INT_MAX - posonlyargcount - posorkwargcount > 0);
612
52.7k
    int kwonlyargcount = (int)umd->u_kwonlyargcount;
613
614
52.7k
    localsplusnames = PyTuple_New(nlocalsplus);
615
52.7k
    if (localsplusnames == NULL) {
616
0
        goto error;
617
0
    }
618
52.7k
    localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus);
619
52.7k
    if (localspluskinds == NULL) {
620
0
        goto error;
621
0
    }
622
52.7k
    if (compute_localsplus_info(
623
52.7k
            umd, nlocalsplus, code_flags,
624
52.7k
            localsplusnames, localspluskinds) == ERROR)
625
0
    {
626
0
        goto error;
627
0
    }
628
629
52.7k
    struct _PyCodeConstructor con = {
630
52.7k
        .filename = filename,
631
52.7k
        .name = umd->u_name,
632
52.7k
        .qualname = umd->u_qualname ? umd->u_qualname : umd->u_name,
633
52.7k
        .flags = code_flags,
634
635
52.7k
        .code = a->a_bytecode,
636
52.7k
        .firstlineno = umd->u_firstlineno,
637
52.7k
        .linetable = a->a_linetable,
638
639
52.7k
        .consts = consts,
640
52.7k
        .names = names,
641
642
52.7k
        .localsplusnames = localsplusnames,
643
52.7k
        .localspluskinds = localspluskinds,
644
645
52.7k
        .argcount = posonlyargcount + posorkwargcount,
646
52.7k
        .posonlyargcount = posonlyargcount,
647
52.7k
        .kwonlyargcount = kwonlyargcount,
648
649
52.7k
        .stacksize = maxdepth,
650
651
52.7k
        .exceptiontable = a->a_except_table,
652
52.7k
    };
653
654
52.7k
   if (_PyCode_Validate(&con) < 0) {
655
0
        goto error;
656
0
    }
657
658
52.7k
    if (_PyCompile_ConstCacheMergeOne(const_cache, &localsplusnames) < 0) {
659
0
        goto error;
660
0
    }
661
52.7k
    con.localsplusnames = localsplusnames;
662
663
52.7k
    co = _PyCode_New(&con);
664
52.7k
    if (co == NULL) {
665
0
        goto error;
666
0
    }
667
668
52.7k
error:
669
52.7k
    Py_XDECREF(names);
670
52.7k
    Py_XDECREF(consts);
671
52.7k
    Py_XDECREF(localsplusnames);
672
52.7k
    Py_XDECREF(localspluskinds);
673
52.7k
    return co;
674
52.7k
}
675
676
677
// The offset (in code units) of the END_SEND from the SEND in the `yield from` sequence.
678
1.72k
#define END_SEND_OFFSET 6
679
680
static int
681
resolve_jump_offsets(instr_sequence *instrs)
682
52.7k
{
683
    /* Compute the size of each instruction and fixup jump args.
684
     * Replace instruction index with position in bytecode.
685
     */
686
687
3.43M
    for (int i = 0; i < instrs->s_used; i++) {
688
3.38M
        instruction *instr = &instrs->s_instrs[i];
689
3.38M
        if (OPCODE_HAS_JUMP(instr->i_opcode)) {
690
214k
            instr->i_target = instr->i_oparg;
691
214k
        }
692
3.38M
    }
693
694
52.7k
    int extended_arg_recompile;
695
696
54.4k
    do {
697
54.4k
        int totsize = 0;
698
5.50M
        for (int i = 0; i < instrs->s_used; i++) {
699
5.45M
            instruction *instr = &instrs->s_instrs[i];
700
5.45M
            instr->i_offset = totsize;
701
5.45M
            int isize = instr_size(instr);
702
5.45M
            totsize += isize;
703
5.45M
        }
704
54.4k
        extended_arg_recompile = 0;
705
706
54.4k
        int offset = 0;
707
5.50M
        for (int i = 0; i < instrs->s_used; i++) {
708
5.45M
            instruction *instr = &instrs->s_instrs[i];
709
5.45M
            int isize = instr_size(instr);
710
            /* jump offsets are computed relative to
711
             * the instruction pointer after fetching
712
             * the jump instruction.
713
             */
714
5.45M
            offset += isize;
715
5.45M
            if (OPCODE_HAS_JUMP(instr->i_opcode)) {
716
440k
                instruction *target = &instrs->s_instrs[instr->i_target];
717
440k
                instr->i_oparg = target->i_offset;
718
440k
                if (instr->i_opcode == END_ASYNC_FOR) {
719
                    // sys.monitoring needs to be able to find the matching END_SEND
720
                    // but the target is the SEND, so we adjust it here.
721
1.72k
                    instr->i_oparg = offset - instr->i_oparg - END_SEND_OFFSET;
722
1.72k
                }
723
438k
                else if (instr->i_oparg < offset) {
724
144k
                    assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode));
725
144k
                    instr->i_oparg = offset - instr->i_oparg;
726
144k
                }
727
294k
                else {
728
294k
                    assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode));
729
294k
                    instr->i_oparg = instr->i_oparg - offset;
730
294k
                }
731
440k
                if (instr_size(instr) != isize) {
732
117k
                    extended_arg_recompile = 1;
733
117k
                }
734
440k
            }
735
5.45M
        }
736
    /* XXX: This is an awful hack that could hurt performance, but
737
        on the bright side it should work until we come up
738
        with a better solution.
739
740
        The issue is that in the first loop instr_size() is
741
        called, and it requires i_oparg be set appropriately.
742
        There is a bootstrap problem because i_oparg is
743
        calculated in the second loop above.
744
745
        So we loop until we stop seeing new EXTENDED_ARGs.
746
        The only EXTENDED_ARGs that could be popping up are
747
        ones in jump instructions.  So this should converge
748
        fairly quickly.
749
    */
750
54.4k
    } while (extended_arg_recompile);
751
52.7k
    return SUCCESS;
752
52.7k
}
753
754
static int
755
resolve_unconditional_jumps(instr_sequence *instrs)
756
52.7k
{
757
    /* Resolve directions of unconditional jumps */
758
759
3.43M
    for (int i = 0; i < instrs->s_used; i++) {
760
3.38M
        instruction *instr = &instrs->s_instrs[i];
761
3.38M
        bool is_forward = (instr->i_oparg > i);
762
3.38M
        switch(instr->i_opcode) {
763
7.97k
            case JUMP:
764
7.97k
                assert(is_pseudo_target(JUMP, JUMP_FORWARD));
765
7.97k
                assert(is_pseudo_target(JUMP, JUMP_BACKWARD));
766
7.97k
                instr->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD;
767
7.97k
                break;
768
78.1k
            case JUMP_NO_INTERRUPT:
769
78.1k
                assert(is_pseudo_target(JUMP_NO_INTERRUPT, JUMP_FORWARD));
770
78.1k
                assert(is_pseudo_target(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT));
771
78.1k
                instr->i_opcode = is_forward ?
772
66.4k
                    JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT;
773
78.1k
                break;
774
3.29M
            default:
775
3.29M
                if (OPCODE_HAS_JUMP(instr->i_opcode) &&
776
128k
                    IS_PSEUDO_INSTR(instr->i_opcode)) {
777
0
                    Py_UNREACHABLE();
778
0
                }
779
3.38M
        }
780
3.38M
    }
781
52.7k
    return SUCCESS;
782
52.7k
}
783
784
PyCodeObject *
785
_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cache,
786
                           PyObject *consts, int maxdepth, instr_sequence *instrs,
787
                           int nlocalsplus, int code_flags, PyObject *filename)
788
52.7k
{
789
52.7k
    if (_PyInstructionSequence_ApplyLabelMap(instrs) < 0) {
790
0
        return NULL;
791
0
    }
792
52.7k
    if (resolve_unconditional_jumps(instrs) < 0) {
793
0
        return NULL;
794
0
    }
795
52.7k
    if (resolve_jump_offsets(instrs) < 0) {
796
0
        return NULL;
797
0
    }
798
52.7k
    PyCodeObject *co = NULL;
799
800
52.7k
    struct assembler a;
801
52.7k
    int res = assemble_emit(&a, instrs, umd->u_firstlineno, const_cache);
802
52.7k
    if (res == SUCCESS) {
803
52.7k
        co = makecode(umd, &a, const_cache, consts, maxdepth, nlocalsplus,
804
52.7k
                      code_flags, filename);
805
52.7k
    }
806
52.7k
    assemble_free(&a);
807
52.7k
    return co;
808
52.7k
}