Coverage Report

Created: 2026-10-15 06:54

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