Coverage Report

Created: 2026-05-16 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Python/optimizer.c
Line
Count
Source
1
#include "Python.h"
2
3
#ifdef _Py_TIER2
4
5
#include "opcode.h"
6
#include "pycore_interp.h"
7
#include "pycore_backoff.h"
8
#include "pycore_bitutils.h"        // _Py_popcount32()
9
#include "pycore_ceval.h"       // _Py_set_eval_breaker_bit
10
#include "pycore_code.h"            // _Py_GetBaseCodeUnit
11
#include "pycore_interpframe.h"
12
#include "pycore_object.h"          // _PyObject_GC_UNTRACK()
13
#include "pycore_opcode_metadata.h" // _PyOpcode_OpName[]
14
#include "pycore_opcode_utils.h"  // MAX_REAL_OPCODE
15
#include "pycore_optimizer.h"     // _Py_uop_analyze_and_optimize()
16
#include "pycore_pystate.h"       // _PyInterpreterState_GET()
17
#include "pycore_tuple.h"         // _PyTuple_FromArraySteal
18
#include "pycore_unicodeobject.h" // _PyUnicode_FromASCII
19
#include "pycore_uop_ids.h"
20
#include "pycore_jit.h"
21
#include <stdbool.h>
22
#include <stdint.h>
23
#include <stddef.h>
24
25
#define NEED_OPCODE_METADATA
26
#include "pycore_uop_metadata.h" // Uop tables
27
#undef NEED_OPCODE_METADATA
28
29
#define MAX_EXECUTORS_SIZE 256
30
31
// Trace too short, no progress:
32
// _START_EXECUTOR
33
// _MAKE_WARM
34
// _CHECK_VALIDITY
35
// _SET_IP
36
// is 4-5 instructions.
37
#define CODE_SIZE_NO_PROGRESS 5
38
// We start with _START_EXECUTOR, _MAKE_WARM
39
#define CODE_SIZE_EMPTY 2
40
41
#define _PyExecutorObject_CAST(op)  ((_PyExecutorObject *)(op))
42
43
#ifndef Py_GIL_DISABLED
44
static bool
45
has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr)
46
{
47
    if (code == (PyCodeObject *)&_Py_InitCleanup) {
48
        return false;
49
    }
50
    if (instr->op.code == ENTER_EXECUTOR) {
51
        return true;
52
    }
53
    if (code->co_executors == NULL) {
54
        return true;
55
    }
56
    return code->co_executors->size < MAX_EXECUTORS_SIZE;
57
}
58
59
static int32_t
60
get_index_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr)
61
{
62
    if (instr->op.code == ENTER_EXECUTOR) {
63
        return instr->op.arg;
64
    }
65
    _PyExecutorArray *old = code->co_executors;
66
    int size = 0;
67
    int capacity = 0;
68
    if (old != NULL) {
69
        size = old->size;
70
        capacity = old->capacity;
71
        assert(size < MAX_EXECUTORS_SIZE);
72
    }
73
    assert(size <= capacity);
74
    if (size == capacity) {
75
        /* Array is full. Grow array */
76
        int new_capacity = capacity ? capacity * 2 : 4;
77
        _PyExecutorArray *new = PyMem_Realloc(
78
            old,
79
            offsetof(_PyExecutorArray, executors) +
80
            new_capacity * sizeof(_PyExecutorObject *));
81
        if (new == NULL) {
82
            return -1;
83
        }
84
        new->capacity = new_capacity;
85
        new->size = size;
86
        code->co_executors = new;
87
    }
88
    assert(size < code->co_executors->capacity);
89
    return size;
90
}
91
92
static void
93
insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorObject *executor)
94
{
95
    Py_INCREF(executor);
96
    if (instr->op.code == ENTER_EXECUTOR) {
97
        assert(index == instr->op.arg);
98
        _Py_ExecutorDetach(code->co_executors->executors[index]);
99
    }
100
    else {
101
        assert(code->co_executors->size == index);
102
        assert(code->co_executors->capacity > index);
103
        code->co_executors->size++;
104
    }
105
    executor->vm_data.opcode = instr->op.code;
106
    executor->vm_data.oparg = instr->op.arg;
107
    executor->vm_data.code = code;
108
    executor->vm_data.index = (int)(instr - _PyCode_CODE(code));
109
    code->co_executors->executors[index] = executor;
110
    assert(index < MAX_EXECUTORS_SIZE);
111
    instr->op.code = ENTER_EXECUTOR;
112
    instr->op.arg = index;
113
}
114
#endif // Py_GIL_DISABLED
115
116
static _PyExecutorObject *
117
make_executor_from_uops(_PyThreadStateImpl *tstate, _PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies);
118
119
static int
120
uop_optimize(_PyInterpreterFrame *frame, PyThreadState *tstate,
121
             _PyExecutorObject **exec_ptr,
122
             bool progress_needed);
123
124
/* Returns 1 if optimized, 0 if not optimized, and -1 for an error.
125
 * If optimized, *executor_ptr contains a new reference to the executor
126
 */
127
// gh-137573: inlining this function causes stack overflows
128
Py_NO_INLINE int
129
_PyOptimizer_Optimize(
130
    _PyInterpreterFrame *frame, PyThreadState *tstate)
131
{
132
    _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
133
    PyInterpreterState *interp = _PyInterpreterState_GET();
134
    if (!interp->jit) {
135
        // gh-140936: It is possible that interp->jit will become false during
136
        // interpreter finalization. However, the specialized JUMP_BACKWARD_JIT
137
        // instruction may still be present. In this case, we should
138
        // return immediately without optimization.
139
        return 0;
140
    }
141
    _PyExecutorObject *prev_executor = _tstate->jit_tracer_state->initial_state.executor;
142
    if (prev_executor != NULL && !prev_executor->vm_data.valid) {
143
        // gh-143604: If we are a side exit executor and the original executor is no
144
        // longer valid, don't compile to prevent a reference leak.
145
        return 0;
146
    }
147
    assert(!interp->compiling);
148
    assert(_tstate->jit_tracer_state->initial_state.stack_depth >= 0);
149
#ifndef Py_GIL_DISABLED
150
    assert(_tstate->jit_tracer_state->initial_state.func != NULL);
151
    interp->compiling = true;
152
    // The first executor in a chain and the MAX_CHAIN_DEPTH'th executor *must*
153
    // make progress in order to avoid infinite loops or excessively-long
154
    // side-exit chains. We can only insert the executor into the bytecode if
155
    // this is true, since a deopt won't infinitely re-enter the executor:
156
    int chain_depth = _tstate->jit_tracer_state->initial_state.chain_depth;
157
    chain_depth %= MAX_CHAIN_DEPTH;
158
    bool progress_needed = chain_depth == 0;
159
    PyCodeObject *code = (PyCodeObject *)_tstate->jit_tracer_state->initial_state.code;
160
    _Py_CODEUNIT *start = _tstate->jit_tracer_state->initial_state.start_instr;
161
    if (progress_needed && !has_space_for_executor(code, start)) {
162
        interp->compiling = false;
163
        return 0;
164
    }
165
    _PyExecutorObject *executor;
166
    int err = uop_optimize(frame, tstate, &executor, progress_needed);
167
    if (err <= 0) {
168
        interp->compiling = false;
169
        return err;
170
    }
171
    assert(executor != NULL);
172
    if (progress_needed) {
173
        int index = get_index_for_executor(code, start);
174
        if (index < 0) {
175
            /* Out of memory. Don't raise and assume that the
176
             * error will show up elsewhere.
177
             *
178
             * If an optimizer has already produced an executor,
179
             * it might get confused by the executor disappearing,
180
             * but there is not much we can do about that here. */
181
            Py_DECREF(executor);
182
            interp->compiling = false;
183
            return 0;
184
        }
185
        insert_executor(code, start, index, executor);
186
    }
187
    executor->vm_data.chain_depth = chain_depth;
188
    assert(executor->vm_data.valid);
189
    _PyExitData *exit = _tstate->jit_tracer_state->initial_state.exit;
190
    if (exit != NULL && !progress_needed) {
191
        exit->executor = executor;
192
    }
193
    else {
194
        // An executor inserted into the code object now has a strong reference
195
        // to it from the code object. Thus, we don't need this reference anymore.
196
        Py_DECREF(executor);
197
    }
198
    interp->compiling = false;
199
    return 1;
200
#else
201
    return 0;
202
#endif
203
}
204
205
static _PyExecutorObject *
206
get_executor_lock_held(PyCodeObject *code, int offset)
207
{
208
    int code_len = (int)Py_SIZE(code);
209
    for (int i = 0 ; i < code_len;) {
210
        if (_PyCode_CODE(code)[i].op.code == ENTER_EXECUTOR && i*2 == offset) {
211
            int oparg = _PyCode_CODE(code)[i].op.arg;
212
            _PyExecutorObject *res = code->co_executors->executors[oparg];
213
            Py_INCREF(res);
214
            return res;
215
        }
216
        i += _PyInstruction_GetLength(code, i);
217
    }
218
    PyErr_SetString(PyExc_ValueError, "no executor at given byte offset");
219
    return NULL;
220
}
221
222
_PyExecutorObject *
223
_Py_GetExecutor(PyCodeObject *code, int offset)
224
{
225
    _PyExecutorObject *executor;
226
    Py_BEGIN_CRITICAL_SECTION(code);
227
    executor = get_executor_lock_held(code, offset);
228
    Py_END_CRITICAL_SECTION();
229
    return executor;
230
}
231
232
static PyObject *
233
is_valid(PyObject *self, PyObject *Py_UNUSED(ignored))
234
{
235
    return PyBool_FromLong(((_PyExecutorObject *)self)->vm_data.valid);
236
}
237
238
static PyObject *
239
get_opcode(PyObject *self, PyObject *Py_UNUSED(ignored))
240
{
241
    return PyLong_FromUnsignedLong(((_PyExecutorObject *)self)->vm_data.opcode);
242
}
243
244
static PyObject *
245
get_oparg(PyObject *self, PyObject *Py_UNUSED(ignored))
246
{
247
    return PyLong_FromUnsignedLong(((_PyExecutorObject *)self)->vm_data.oparg);
248
}
249
250
///////////////////// Experimental UOp Optimizer /////////////////////
251
252
static int executor_clear(PyObject *executor);
253
254
void
255
_PyExecutor_Free(_PyExecutorObject *self)
256
{
257
#ifdef _Py_JIT
258
    _PyJIT_Free(self);
259
#endif
260
    PyObject_GC_Del(self);
261
}
262
263
static void executor_invalidate(PyObject *op);
264
265
static void
266
executor_clear_exits(_PyExecutorObject *executor)
267
{
268
    _PyExecutorObject *cold = _PyExecutor_GetColdExecutor();
269
    _PyExecutorObject *cold_dynamic = _PyExecutor_GetColdDynamicExecutor();
270
    for (uint32_t i = 0; i < executor->exit_count; i++) {
271
        _PyExitData *exit = &executor->exits[i];
272
        exit->temperature = initial_unreachable_backoff_counter();
273
        _PyExecutorObject *old = executor->exits[i].executor;
274
        exit->executor = exit->is_dynamic ? cold_dynamic : cold;
275
        Py_DECREF(old);
276
    }
277
}
278
279
280
void
281
_Py_ClearExecutorDeletionList(PyInterpreterState *interp)
282
{
283
    if (interp->executor_deletion_list_head == NULL) {
284
        return;
285
    }
286
    _PyRuntimeState *runtime = &_PyRuntime;
287
    HEAD_LOCK(runtime);
288
    PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
289
    while (ts) {
290
        _PyExecutorObject *current = (_PyExecutorObject *)ts->current_executor;
291
        Py_XINCREF(current);
292
        ts = ts->next;
293
    }
294
    HEAD_UNLOCK(runtime);
295
    _PyExecutorObject *keep_list = NULL;
296
    do {
297
        _PyExecutorObject *exec = interp->executor_deletion_list_head;
298
        interp->executor_deletion_list_head = exec->vm_data.links.next;
299
        if (Py_REFCNT(exec) == 0) {
300
            _PyExecutor_Free(exec);
301
        } else {
302
            exec->vm_data.links.next = keep_list;
303
            keep_list = exec;
304
        }
305
    } while (interp->executor_deletion_list_head != NULL);
306
    interp->executor_deletion_list_head = keep_list;
307
    HEAD_LOCK(runtime);
308
    ts = PyInterpreterState_ThreadHead(interp);
309
    while (ts) {
310
        _PyExecutorObject *current = (_PyExecutorObject *)ts->current_executor;
311
        if (current != NULL) {
312
            Py_DECREF((PyObject *)current);
313
        }
314
        ts = ts->next;
315
    }
316
    HEAD_UNLOCK(runtime);
317
}
318
319
static void
320
add_to_pending_deletion_list(_PyExecutorObject *self)
321
{
322
    if (self->vm_data.pending_deletion) {
323
        return;
324
    }
325
    self->vm_data.pending_deletion = 1;
326
    PyInterpreterState *interp = PyInterpreterState_Get();
327
    self->vm_data.links.previous = NULL;
328
    self->vm_data.links.next = interp->executor_deletion_list_head;
329
    interp->executor_deletion_list_head = self;
330
}
331
332
static void
333
uop_dealloc(PyObject *op) {
334
    _PyExecutorObject *self = _PyExecutorObject_CAST(op);
335
    executor_invalidate(op);
336
    assert(self->vm_data.code == NULL);
337
    add_to_pending_deletion_list(self);
338
}
339
340
const char *
341
_PyUOpName(int index)
342
{
343
    if (index < 0 || index > MAX_UOP_REGS_ID) {
344
        return NULL;
345
    }
346
    return _PyOpcode_uop_name[index];
347
}
348
349
#ifdef Py_DEBUG
350
void
351
_PyUOpPrint(const _PyUOpInstruction *uop)
352
{
353
    const char *name = _PyUOpName(uop->opcode);
354
    if (name == NULL) {
355
        printf("<uop %d>", uop->opcode);
356
    }
357
    else {
358
        printf("%s", name);
359
    }
360
    switch(uop->format) {
361
        case UOP_FORMAT_TARGET:
362
            printf(" (%d, target=%d, operand0=%#" PRIx64 ", operand1=%#" PRIx64,
363
                uop->oparg,
364
                uop->target,
365
                (uint64_t)uop->operand0,
366
                (uint64_t)uop->operand1);
367
            break;
368
        case UOP_FORMAT_JUMP:
369
            printf(" (%d, jump_target=%d, operand0=%#" PRIx64 ", operand1=%#" PRIx64,
370
                uop->oparg,
371
                uop->jump_target,
372
                (uint64_t)uop->operand0,
373
                (uint64_t)uop->operand1);
374
            break;
375
        default:
376
            printf(" (%d, Unknown format)", uop->oparg);
377
    }
378
    if (_PyUop_Flags[_PyUop_Uncached[uop->opcode]] & HAS_ERROR_FLAG) {
379
        printf(", error_target=%d", uop->error_target);
380
    }
381
382
    printf(")");
383
}
384
#endif
385
386
static Py_ssize_t
387
uop_len(PyObject *op)
388
{
389
    _PyExecutorObject *self = _PyExecutorObject_CAST(op);
390
    return self->code_size;
391
}
392
393
static PyObject *
394
uop_item(PyObject *op, Py_ssize_t index)
395
{
396
    _PyExecutorObject *self = _PyExecutorObject_CAST(op);
397
    Py_ssize_t len = uop_len(op);
398
    if (index < 0 || index >= len) {
399
        PyErr_SetNone(PyExc_IndexError);
400
        return NULL;
401
    }
402
    int opcode = self->trace[index].opcode;
403
    int base_opcode = _PyUop_Uncached[opcode];
404
    const char *name = _PyUOpName(base_opcode);
405
    if (name == NULL) {
406
        name = "<nil>";
407
    }
408
    PyObject *oname = _PyUnicode_FromASCII(name, strlen(name));
409
    if (oname == NULL) {
410
        return NULL;
411
    }
412
    PyObject *oparg = PyLong_FromUnsignedLong(self->trace[index].oparg);
413
    if (oparg == NULL) {
414
        Py_DECREF(oname);
415
        return NULL;
416
    }
417
    PyObject *target = PyLong_FromUnsignedLong(self->trace[index].target);
418
    if (target == NULL) {
419
        Py_DECREF(oparg);
420
        Py_DECREF(oname);
421
        return NULL;
422
    }
423
    PyObject *operand = PyLong_FromUnsignedLongLong(self->trace[index].operand0);
424
    if (operand == NULL) {
425
        Py_DECREF(target);
426
        Py_DECREF(oparg);
427
        Py_DECREF(oname);
428
        return NULL;
429
    }
430
    PyObject *args[4] = { oname, oparg, target, operand };
431
    return _PyTuple_FromArraySteal(args, 4);
432
}
433
434
PySequenceMethods uop_as_sequence = {
435
    .sq_length = uop_len,
436
    .sq_item = uop_item,
437
};
438
439
static int
440
executor_traverse(PyObject *o, visitproc visit, void *arg)
441
{
442
    _PyExecutorObject *executor = _PyExecutorObject_CAST(o);
443
    for (uint32_t i = 0; i < executor->exit_count; i++) {
444
        Py_VISIT(executor->exits[i].executor);
445
    }
446
    return 0;
447
}
448
449
static PyObject *
450
get_jit_code(PyObject *self, PyObject *Py_UNUSED(ignored))
451
{
452
#ifndef _Py_JIT
453
    PyErr_SetString(PyExc_RuntimeError, "JIT support not enabled.");
454
    return NULL;
455
#else
456
    _PyExecutorObject *executor = _PyExecutorObject_CAST(self);
457
    if (executor->jit_code == NULL || executor->jit_size == 0) {
458
        Py_RETURN_NONE;
459
    }
460
    return PyBytes_FromStringAndSize(executor->jit_code, executor->jit_size);
461
#endif
462
}
463
464
static PyMethodDef uop_executor_methods[] = {
465
    { "is_valid", is_valid, METH_NOARGS, NULL },
466
    { "get_jit_code", get_jit_code, METH_NOARGS, NULL},
467
    { "get_opcode", get_opcode, METH_NOARGS, NULL },
468
    { "get_oparg", get_oparg, METH_NOARGS, NULL },
469
    { NULL, NULL },
470
};
471
472
static int
473
executor_is_gc(PyObject *o)
474
{
475
    return !_Py_IsImmortal(o);
476
}
477
478
PyTypeObject _PyUOpExecutor_Type = {
479
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
480
    .tp_name = "uop_executor",
481
    .tp_basicsize = offsetof(_PyExecutorObject, exits),
482
    .tp_itemsize = 1,
483
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_HAVE_GC,
484
    .tp_dealloc = uop_dealloc,
485
    .tp_as_sequence = &uop_as_sequence,
486
    .tp_methods = uop_executor_methods,
487
    .tp_traverse = executor_traverse,
488
    .tp_clear = executor_clear,
489
    .tp_is_gc = executor_is_gc,
490
};
491
492
/* TO DO -- Generate these tables */
493
static const uint16_t
494
_PyUOp_Replacements[MAX_UOP_ID + 1] = {
495
    [_ITER_JUMP_RANGE] = _GUARD_NOT_EXHAUSTED_RANGE,
496
    [_ITER_JUMP_LIST] = _GUARD_NOT_EXHAUSTED_LIST,
497
    [_ITER_JUMP_TUPLE] = _GUARD_NOT_EXHAUSTED_TUPLE,
498
    [_FOR_ITER] = _FOR_ITER_TIER_TWO,
499
    [_FOR_ITER_VIRTUAL] = _FOR_ITER_VIRTUAL_TIER_TWO,
500
    [_ITER_NEXT_LIST] = _ITER_NEXT_LIST_TIER_TWO,
501
    [_CHECK_PERIODIC_AT_END] = _TIER2_RESUME_CHECK,
502
    [_LOAD_BYTECODE] = _NOP,
503
    [_SEND_VIRTUAL] = _SEND_VIRTUAL_TIER_TWO,
504
    [_SEND_ASYNC_GEN] = _SEND_ASYNC_GEN_TIER_TWO,
505
};
506
507
static const uint8_t
508
is_for_iter_test[MAX_UOP_ID + 1] = {
509
    [_GUARD_NOT_EXHAUSTED_RANGE] = 1,
510
    [_GUARD_NOT_EXHAUSTED_LIST] = 1,
511
    [_GUARD_NOT_EXHAUSTED_TUPLE] = 1,
512
    [_FOR_ITER_TIER_TWO] = 1,
513
    [_ITER_NEXT_INLINE] = 1,
514
};
515
516
static const uint16_t
517
BRANCH_TO_GUARD[4][2] = {
518
    [POP_JUMP_IF_FALSE - POP_JUMP_IF_FALSE][0] = _GUARD_IS_TRUE_POP,
519
    [POP_JUMP_IF_FALSE - POP_JUMP_IF_FALSE][1] = _GUARD_IS_FALSE_POP,
520
    [POP_JUMP_IF_TRUE - POP_JUMP_IF_FALSE][0] = _GUARD_IS_FALSE_POP,
521
    [POP_JUMP_IF_TRUE - POP_JUMP_IF_FALSE][1] = _GUARD_IS_TRUE_POP,
522
    [POP_JUMP_IF_NONE - POP_JUMP_IF_FALSE][0] = _GUARD_IS_NOT_NONE_POP,
523
    [POP_JUMP_IF_NONE - POP_JUMP_IF_FALSE][1] = _GUARD_IS_NONE_POP,
524
    [POP_JUMP_IF_NOT_NONE - POP_JUMP_IF_FALSE][0] = _GUARD_IS_NONE_POP,
525
    [POP_JUMP_IF_NOT_NONE - POP_JUMP_IF_FALSE][1] = _GUARD_IS_NOT_NONE_POP,
526
};
527
528
static const uint16_t
529
guard_ip_uop[MAX_UOP_ID + 1] = {
530
    [_PUSH_FRAME] = _GUARD_IP__PUSH_FRAME,
531
    [_RETURN_GENERATOR] = _GUARD_IP_RETURN_GENERATOR,
532
    [_RETURN_VALUE] = _GUARD_IP_RETURN_VALUE,
533
    [_YIELD_VALUE] = _GUARD_IP_YIELD_VALUE,
534
};
535
536
static const uint16_t
537
guard_code_version_uop[MAX_UOP_ID + 1] = {
538
    [_PUSH_FRAME] = _GUARD_CODE_VERSION__PUSH_FRAME,
539
    [_RETURN_GENERATOR] = _GUARD_CODE_VERSION_RETURN_GENERATOR,
540
    [_RETURN_VALUE] = _GUARD_CODE_VERSION_RETURN_VALUE,
541
    [_YIELD_VALUE] = _GUARD_CODE_VERSION_YIELD_VALUE,
542
};
543
544
static const uint16_t
545
dynamic_exit_uop[MAX_UOP_ID + 1] = {
546
    [_GUARD_IP__PUSH_FRAME] = 1,
547
    [_GUARD_IP_RETURN_GENERATOR] = 1,
548
    [_GUARD_IP_RETURN_VALUE] = 1,
549
    [_GUARD_IP_YIELD_VALUE] = 1,
550
    [_GUARD_CODE_VERSION__PUSH_FRAME] = 1,
551
    [_GUARD_CODE_VERSION_RETURN_GENERATOR] = 1,
552
    [_GUARD_CODE_VERSION_RETURN_VALUE] = 1,
553
    [_GUARD_CODE_VERSION_YIELD_VALUE] = 1,
554
};
555
556
557
558
#ifdef Py_DEBUG
559
#define DPRINTF(level, ...) \
560
    if (lltrace >= (level)) { printf(__VA_ARGS__); }
561
#else
562
#define DPRINTF(level, ...)
563
#endif
564
565
566
static inline void
567
add_to_trace(
568
    _PyJitTracerState *tracer,
569
    uint16_t opcode,
570
    uint16_t oparg,
571
    uint64_t operand,
572
    uint32_t target)
573
{
574
    _PyJitUopBuffer *trace = &tracer->code_buffer;
575
    _PyUOpInstruction *inst = trace->next;
576
    inst->opcode = opcode;
577
    inst->format = UOP_FORMAT_TARGET;
578
    inst->target = target;
579
    inst->oparg = oparg;
580
    inst->operand0 = operand;
581
#ifdef Py_STATS
582
    inst->execution_count = 0;
583
    inst->fitness = tracer->translator_state.fitness;
584
#endif
585
    trace->next++;
586
}
587
588
589
#ifdef Py_DEBUG
590
#define ADD_TO_TRACE(OPCODE, OPARG, OPERAND, TARGET) \
591
    add_to_trace(tracer, (OPCODE), (OPARG), (OPERAND), (TARGET)); \
592
    if (lltrace >= 2) { \
593
        printf("%4d ADD_TO_TRACE: ", uop_buffer_length(trace)); \
594
        _PyUOpPrint(uop_buffer_last(trace)); \
595
        printf("\n"); \
596
    }
597
#else
598
#define ADD_TO_TRACE(OPCODE, OPARG, OPERAND, TARGET) \
599
    add_to_trace(tracer, (OPCODE), (OPARG), (OPERAND), (TARGET))
600
#endif
601
602
#define INSTR_IP(INSTR, CODE) \
603
    ((uint32_t)((INSTR) - ((_Py_CODEUNIT *)(CODE)->co_code_adaptive)))
604
605
606
/* Branch penalty: 0 for a fully biased branch and FITNESS_BRANCH_BALANCED for
607
 * a balanced or fully off-trace branch. This keeps any single branch from
608
 * consuming more than one balanced-branch cost.
609
 */
610
static inline int
611
compute_branch_penalty(uint16_t history)
612
{
613
    bool branch_taken = history & 1;
614
    int taken_count = _Py_popcount32((uint32_t)history);
615
    int on_trace_count = branch_taken ? taken_count : 16 - taken_count;
616
    int off_trace = 16 - on_trace_count;
617
    int penalty = off_trace * FITNESS_BRANCH_BALANCED / 8;
618
    if (penalty > FITNESS_BRANCH_BALANCED) {
619
        penalty = FITNESS_BRANCH_BALANCED;
620
    }
621
    return penalty;
622
}
623
624
/* Compute exit quality for the current trace position.
625
 * Higher values mean better places to stop the trace. */
626
static inline int32_t
627
compute_exit_quality(_Py_CODEUNIT *target_instr, int opcode,
628
                     const _PyJitTracerState *tracer)
629
{
630
    if (target_instr == tracer->initial_state.close_loop_instr) {
631
        return EXIT_QUALITY_CLOSE_LOOP;
632
    }
633
    else if (target_instr->op.code == ENTER_EXECUTOR) {
634
        return EXIT_QUALITY_ENTER_EXECUTOR;
635
    }
636
    else if (opcode == JUMP_BACKWARD_JIT ||
637
        opcode == JUMP_BACKWARD ||
638
        opcode == JUMP_BACKWARD_NO_INTERRUPT) {
639
        return EXIT_QUALITY_BACKWARD_EDGE;
640
    }
641
    else if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]] > 0) {
642
        return EXIT_QUALITY_SPECIALIZABLE;
643
    }
644
    return EXIT_QUALITY_DEFAULT;
645
}
646
647
/* Frame penalty: (MAX_ABSTRACT_FRAME_DEPTH-1) pushes exhaust fitness. */
648
static inline int32_t
649
compute_frame_penalty(uint16_t fitness_initial)
650
{
651
    return (int32_t)fitness_initial / (MAX_ABSTRACT_FRAME_DEPTH - 1) + 1;
652
}
653
654
static int
655
is_terminator(const _PyUOpInstruction *uop)
656
{
657
    int opcode = _PyUop_Uncached[uop->opcode];
658
    return (
659
        opcode == _EXIT_TRACE ||
660
        opcode == _DEOPT ||
661
        opcode == _JUMP_TO_TOP ||
662
        opcode == _DYNAMIC_EXIT
663
    );
664
}
665
666
static PyObject *
667
record_trace_transform_to_type(PyObject *value)
668
{
669
    PyObject *tp = Py_NewRef((PyObject *)Py_TYPE(value));
670
    Py_DECREF(value);
671
    return tp;
672
}
673
674
/* _RECORD_NOS_GEN_FUNC and _RECORD_3OS_GEN_FUNC record the raw receiver.
675
 * If it is a generator, return its function object; otherwise return NULL.
676
 */
677
static PyObject *
678
record_trace_transform_gen_func(PyObject *value)
679
{
680
    PyObject *func = NULL;
681
    if (PyGen_Check(value)) {
682
        _PyStackRef f = ((PyGenObject *)value)->gi_iframe.f_funcobj;
683
        if (!PyStackRef_IsNull(f)) {
684
            func = Py_NewRef(PyStackRef_AsPyObjectBorrow(f));
685
        }
686
    }
687
    Py_DECREF(value);
688
    return func;
689
}
690
691
/* _RECORD_BOUND_METHOD records the raw callable.
692
 * Keep it only for bound methods; otherwise return NULL.
693
 */
694
static PyObject *
695
record_trace_transform_bound_method(PyObject *value)
696
{
697
    if (Py_TYPE(value) == &PyMethod_Type) {
698
        return value;
699
    }
700
    Py_DECREF(value);
701
    return NULL;
702
}
703
704
/* Returns 1 on success (added to trace), 0 on trace end.
705
 */
706
// gh-142543: inlining this function causes stack overflows
707
Py_NO_INLINE int
708
_PyJit_translate_single_bytecode_to_trace(
709
    PyThreadState *tstate,
710
    _PyInterpreterFrame *frame,
711
    _Py_CODEUNIT *next_instr,
712
    int stop_tracing_opcode)
713
{
714
715
#ifdef Py_DEBUG
716
    char *python_lltrace = Py_GETENV("PYTHON_LLTRACE");
717
    int lltrace = 0;
718
    if (python_lltrace != NULL && *python_lltrace >= '0') {
719
        lltrace = *python_lltrace - '0';  // TODO: Parse an int and all that
720
    }
721
#endif
722
    _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
723
    _PyJitTracerState *tracer = _tstate->jit_tracer_state;
724
    PyCodeObject *old_code = tracer->prev_state.instr_code;
725
    bool progress_needed = (tracer->initial_state.chain_depth % MAX_CHAIN_DEPTH) == 0;
726
    _PyJitUopBuffer *trace = &tracer->code_buffer;
727
728
    _Py_CODEUNIT *this_instr =  tracer->prev_state.instr;
729
    _Py_CODEUNIT *target_instr = this_instr;
730
    uint32_t target = 0;
731
732
    target = Py_IsNone((PyObject *)old_code)
733
        ? (uint32_t)(target_instr - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR)
734
        : INSTR_IP(target_instr, old_code);
735
736
    // Rewind EXTENDED_ARG so that we see the whole thing.
737
    // We must point to the first EXTENDED_ARG when deopting.
738
    int oparg = tracer->prev_state.instr_oparg;
739
    int opcode = this_instr->op.code;
740
    int rewind_oparg = oparg;
741
    while (rewind_oparg > 255) {
742
        rewind_oparg >>= 8;
743
        target--;
744
    }
745
746
    if (opcode == ENTER_EXECUTOR) {
747
        _PyExecutorObject *executor = old_code->co_executors->executors[oparg & 255];
748
        opcode = executor->vm_data.opcode;
749
        oparg = (oparg & ~255) | executor->vm_data.oparg;
750
    }
751
752
    if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]] > 0) {
753
        uint16_t backoff = (this_instr + 1)->counter.value_and_backoff;
754
        // adaptive_counter_cooldown is a fresh specialization.
755
        // trigger_backoff_counter is what we set during tracing.
756
        // All tracing backoffs should be freshly specialized or untouched.
757
        // If not, that indicates a deopt during tracing, and
758
        // thus the "actual" instruction executed is not the one that is
759
        // in the instruction stream, but rather the deopt.
760
        // It's important we check for this, as some specializations might make
761
        // no progress (they can immediately deopt after specializing).
762
        // We do this to improve performance, as otherwise a compiled trace
763
        // will just deopt immediately.
764
        if (backoff != adaptive_counter_cooldown().value_and_backoff &&
765
            backoff != trigger_backoff_counter().value_and_backoff) {
766
            OPT_STAT_INC(trace_immediately_deopts);
767
            opcode = _PyOpcode_Deopt[opcode];
768
        }
769
    }
770
771
    // Strange control-flow
772
    bool has_dynamic_jump_taken = OPCODE_HAS_UNPREDICTABLE_JUMP(opcode) &&
773
        (next_instr != this_instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]);
774
775
    /* Special case the first instruction,
776
    * so that we can guarantee forward progress */
777
    if (progress_needed && uop_buffer_length(&tracer->code_buffer) < CODE_SIZE_NO_PROGRESS) {
778
        if (OPCODE_HAS_EXIT(opcode) || OPCODE_HAS_DEOPT(opcode)) {
779
            opcode = _PyOpcode_Deopt[opcode];
780
        }
781
        assert(!OPCODE_HAS_EXIT(opcode));
782
        assert(!OPCODE_HAS_DEOPT(opcode));
783
    }
784
785
    bool needs_guard_ip = OPCODE_HAS_NEEDS_GUARD_IP(opcode);
786
    if (has_dynamic_jump_taken && !needs_guard_ip) {
787
        DPRINTF(2, "Unsupported: dynamic jump taken %s\n", _PyOpcode_OpName[opcode]);
788
        goto unsupported;
789
    }
790
791
    int is_sys_tracing = (tstate->c_tracefunc != NULL) || (tstate->c_profilefunc != NULL);
792
    if (is_sys_tracing) {
793
        goto done;
794
    }
795
796
    if (stop_tracing_opcode == _DEOPT) {
797
        // gh-143183: It's important we rewind to the last known proper target.
798
        // The current target might be garbage as stop tracing usually indicates
799
        // we are in something that we can't trace.
800
        DPRINTF(2, "Told to stop tracing\n");
801
        goto unsupported;
802
    }
803
    else if (stop_tracing_opcode != 0) {
804
        assert(stop_tracing_opcode == _EXIT_TRACE);
805
        ADD_TO_TRACE(stop_tracing_opcode, 0, 0, target);
806
        goto done;
807
    }
808
809
    DPRINTF(2, "%p %d: %s(%d) %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip);
810
811
#ifdef Py_DEBUG
812
    if (oparg > 255) {
813
        assert(_Py_GetBaseCodeUnit(old_code, target).op.code == EXTENDED_ARG);
814
    }
815
#endif
816
817
    // This happens when a recursive call happens that we can't trace. Such as Python -> C -> Python calls
818
    // If we haven't guarded the IP, then it's untraceable.
819
    if (frame != tracer->prev_state.instr_frame && !needs_guard_ip) {
820
        DPRINTF(2, "Unsupported: unguardable jump taken\n");
821
        goto unsupported;
822
    }
823
824
    if (oparg > 0xFFFF) {
825
        DPRINTF(2, "Unsupported: oparg too large\n");
826
        unsupported:
827
        {
828
            _PyUOpInstruction *curr = uop_buffer_last(trace);
829
            while (curr->opcode != _SET_IP && uop_buffer_length(trace) > 2) {
830
                trace->next--;
831
                curr = uop_buffer_last(trace);
832
            }
833
            if (curr->opcode == _SET_IP) {
834
                int32_t old_target = (int32_t)uop_get_target(curr);
835
                curr->opcode = _DEOPT;
836
                curr->format = UOP_FORMAT_TARGET;
837
                curr->target = old_target;
838
            }
839
            goto done;
840
        }
841
    }
842
843
    if (opcode == NOP) {
844
        return 1;
845
    }
846
847
    if (opcode == JUMP_FORWARD) {
848
        return 1;
849
    }
850
851
    if (opcode == EXTENDED_ARG) {
852
        return 1;
853
    }
854
855
    // Stop the trace if fitness has dropped below the exit quality threshold.
856
    _PyJitTracerTranslatorState *ts = &tracer->translator_state;
857
    int32_t eq = compute_exit_quality(target_instr, opcode, tracer);
858
    DPRINTF(3, "Fitness check: %s(%d) fitness=%d, exit_quality=%d, depth=%d\n",
859
            _PyOpcode_OpName[opcode], oparg, ts->fitness, eq, ts->frame_depth);
860
861
    if (ts->fitness < eq) {
862
        // Heuristic exit: leave operand1=0 so the side exit increments chain_depth.
863
        ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target);
864
        OPT_STAT_INC(fitness_terminated_traces);
865
        DPRINTF(2, "Fitness terminated: %s(%d) fitness=%d < exit_quality=%d\n",
866
                _PyOpcode_OpName[opcode], oparg, ts->fitness, eq);
867
        goto done;
868
    }
869
870
    // Snapshot remaining space so the later fitness charge reflects all buffer
871
    // space this bytecode consumed, including reserved tail slots.
872
    int32_t remaining_before = uop_buffer_remaining_space(trace);
873
874
    // One for possible _DEOPT, one because _CHECK_VALIDITY itself might _DEOPT
875
    trace->end -= 2;
876
877
    const _PyOpcodeRecordSlotMap *record_slot_map = &_PyOpcode_RecordSlotMaps[opcode];
878
879
    assert(opcode != ENTER_EXECUTOR && opcode != EXTENDED_ARG);
880
    assert(!_PyErr_Occurred(tstate));
881
882
883
    if (OPCODE_HAS_EXIT(opcode)) {
884
        // Make space for side exit
885
        trace->end--;
886
    }
887
    if (OPCODE_HAS_ERROR(opcode)) {
888
        // Make space for error stub
889
        trace->end--;
890
    }
891
    if (OPCODE_HAS_DEOPT(opcode)) {
892
        // Make space for side exit
893
        trace->end--;
894
    }
895
896
    // _GUARD_IP leads to an exit.
897
    trace->end -= needs_guard_ip;
898
899
#if Py_DEBUG
900
    const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode];
901
    int space_needed = expansion->nuops + needs_guard_ip + 2 + (!OPCODE_HAS_NO_SAVE_IP(opcode));
902
    assert(uop_buffer_remaining_space(trace) > space_needed);
903
#endif
904
905
    ADD_TO_TRACE(_CHECK_VALIDITY, 0, 0, target);
906
907
    if (!OPCODE_HAS_NO_SAVE_IP(opcode)) {
908
        ADD_TO_TRACE(_SET_IP, 0, (uintptr_t)target_instr, target);
909
    }
910
911
    switch (opcode) {
912
        case POP_JUMP_IF_NONE:
913
        case POP_JUMP_IF_NOT_NONE:
914
        case POP_JUMP_IF_FALSE:
915
        case POP_JUMP_IF_TRUE:
916
        {
917
            _Py_CODEUNIT *computed_next_instr_without_modifiers = target_instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]];
918
            _Py_CODEUNIT *computed_next_instr = computed_next_instr_without_modifiers + (computed_next_instr_without_modifiers->op.code == NOT_TAKEN);
919
            _Py_CODEUNIT *computed_jump_instr = computed_next_instr_without_modifiers + oparg;
920
            assert(next_instr == computed_next_instr || next_instr == computed_jump_instr);
921
            int jump_happened = target_instr[1].cache & 1;
922
            assert(jump_happened ? (next_instr == computed_jump_instr) : (next_instr == computed_next_instr));
923
            uint32_t uopcode = BRANCH_TO_GUARD[opcode - POP_JUMP_IF_FALSE][jump_happened];
924
            ADD_TO_TRACE(uopcode, 0, 0, INSTR_IP(jump_happened ? computed_next_instr : computed_jump_instr, old_code));
925
            int bp = compute_branch_penalty(target_instr[1].cache);
926
            tracer->translator_state.fitness -= bp;
927
            DPRINTF(3, "  branch penalty: -%d (history=0x%04x, taken=%d) -> fitness=%d\n",
928
                    bp, target_instr[1].cache, jump_happened,
929
                    tracer->translator_state.fitness);
930
931
            break;
932
        }
933
        case JUMP_BACKWARD_JIT:
934
            // This is possible as the JIT might have re-activated after it was disabled
935
        case JUMP_BACKWARD_NO_JIT:
936
        case JUMP_BACKWARD:
937
            ADD_TO_TRACE(_CHECK_PERIODIC, 0, 0, target);
938
            break;
939
        case JUMP_BACKWARD_NO_INTERRUPT:
940
            break;
941
942
        case RESUME:
943
        case RESUME_CHECK:
944
        case RESUME_CHECK_JIT:
945
            /* Use a special tier 2 version of RESUME_CHECK to allow traces to
946
             *  start with RESUME_CHECK */
947
            ADD_TO_TRACE(_TIER2_RESUME_CHECK, 0, 0, target);
948
            break;
949
        default:
950
        {
951
            const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode];
952
            // Reserve space for nuops (+ _SET_IP + _EXIT_TRACE)
953
            int nuops = expansion->nuops;
954
            if (nuops == 0) {
955
                DPRINTF(2, "Unsupported opcode %s\n", _PyOpcode_OpName[opcode]);
956
                goto unsupported;
957
            }
958
            assert(nuops > 0);
959
            uint32_t orig_oparg = oparg;  // For OPARG_TOP/BOTTOM
960
            uint32_t orig_target = target;
961
            int record_idx = 0;
962
            for (int i = 0; i < nuops; i++) {
963
                oparg = orig_oparg;
964
                target = orig_target;
965
                uint32_t uop = expansion->uops[i].uop;
966
                uint64_t operand = 0;
967
                // Add one to account for the actual opcode/oparg pair:
968
                int offset = expansion->uops[i].offset + 1;
969
                switch (expansion->uops[i].size) {
970
                    case OPARG_SIMPLE:
971
                        assert(opcode != _JUMP_BACKWARD_NO_INTERRUPT && opcode != JUMP_BACKWARD);
972
                        break;
973
                    case OPARG_CACHE_1:
974
                        operand = read_u16(&this_instr[offset].cache);
975
                        break;
976
                    case OPARG_CACHE_2:
977
                        operand = read_u32(&this_instr[offset].cache);
978
                        break;
979
                    case OPARG_CACHE_4:
980
                        operand = read_u64(&this_instr[offset].cache);
981
                        break;
982
                    case OPARG_TOP:  // First half of super-instr
983
                        assert(orig_oparg <= 255);
984
                        oparg = orig_oparg >> 4;
985
                        break;
986
                    case OPARG_BOTTOM:  // Second half of super-instr
987
                        assert(orig_oparg <= 255);
988
                        oparg = orig_oparg & 0xF;
989
                        break;
990
                    case OPARG_SAVE_RETURN_OFFSET:  // op=_SAVE_RETURN_OFFSET; oparg=return_offset
991
                        oparg = offset;
992
                        assert(uop == _SAVE_RETURN_OFFSET);
993
                        break;
994
                    case OPARG_REPLACED:
995
                        uop = _PyUOp_Replacements[uop];
996
                        assert(uop != 0);
997
998
                        uint32_t next_inst = target + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]];
999
                        if (uop == _TIER2_RESUME_CHECK) {
1000
                            target = next_inst;
1001
                        }
1002
                        else {
1003
                            int extended_arg = orig_oparg > 255;
1004
                            uint32_t jump_target = next_inst + orig_oparg + extended_arg;
1005
                            /* Jump must be to an "END" either END_FOR or END_SEND */
1006
                            assert((
1007
                                    _Py_GetBaseCodeUnit(old_code, jump_target).op.code == END_FOR &&
1008
                                    _Py_GetBaseCodeUnit(old_code, jump_target+1).op.code == POP_ITER
1009
                                )
1010
                                ||
1011
                                _Py_GetBaseCodeUnit(old_code, jump_target).op.code == END_SEND
1012
                            );
1013
                            if (is_for_iter_test[uop]) {
1014
                                target = jump_target + 1;
1015
                            }
1016
                        }
1017
                        break;
1018
                    case OPERAND1_1:
1019
                        assert(uop_buffer_last(trace)->opcode == uop);
1020
                        operand = read_u16(&this_instr[offset].cache);
1021
                        uop_buffer_last(trace)->operand1 = operand;
1022
                        continue;
1023
                    case OPERAND1_2:
1024
                        assert(uop_buffer_last(trace)->opcode == uop);
1025
                        operand = read_u32(&this_instr[offset].cache);
1026
                        uop_buffer_last(trace)->operand1 = operand;
1027
                        continue;
1028
                    case OPERAND1_4:
1029
                        assert(uop_buffer_last(trace)->opcode == uop);
1030
                        operand = read_u64(&this_instr[offset].cache);
1031
                        uop_buffer_last(trace)->operand1 = operand;
1032
                        continue;
1033
                    default:
1034
                        fprintf(stderr,
1035
                                "opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n",
1036
                                opcode, oparg, nuops, i,
1037
                                expansion->uops[i].size,
1038
                                expansion->uops[i].offset);
1039
                        Py_FatalError("garbled expansion");
1040
                }
1041
                if (uop == _BINARY_OP_INPLACE_ADD_UNICODE) {
1042
                    assert(i + 1 == nuops);
1043
                    _Py_CODEUNIT *next = target_instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]];
1044
                    assert(next->op.code == STORE_FAST);
1045
                    operand = next->op.arg;
1046
                }
1047
                else if (uop == _PUSH_FRAME) {
1048
                    _PyJitTracerTranslatorState *ts_depth = &tracer->translator_state;
1049
                    ts_depth->frame_depth++;
1050
                    assert(ts_depth->frame_depth < MAX_ABSTRACT_FRAME_DEPTH);
1051
                    int32_t frame_penalty = compute_frame_penalty(tstate->interp->opt_config.fitness_initial);
1052
                    ts_depth->fitness -= frame_penalty;
1053
                    DPRINTF(3, "  _PUSH_FRAME: depth=%d, penalty=-%d -> fitness=%d\n",
1054
                            ts_depth->frame_depth, frame_penalty,
1055
                            ts_depth->fitness);
1056
                }
1057
                else if (uop == _RETURN_VALUE || uop == _RETURN_GENERATOR || uop == _YIELD_VALUE) {
1058
                    _PyJitTracerTranslatorState *ts_depth = &tracer->translator_state;
1059
                    int32_t frame_penalty = compute_frame_penalty(tstate->interp->opt_config.fitness_initial);
1060
                    if (ts_depth->frame_depth <= 0) {
1061
                        // Returning past the traced root is normal for guarded
1062
                        // caller continuation. Charge a small penalty so these
1063
                        // paths still terminate.
1064
                        int32_t underflow_penalty = frame_penalty / 4;
1065
                        ts_depth->fitness -= underflow_penalty;
1066
                        DPRINTF(3, "  %s: underflow penalty=-%d -> fitness=%d\n",
1067
                                _PyOpcode_uop_name[uop], underflow_penalty,
1068
                                ts_depth->fitness);
1069
                    }
1070
                    else {
1071
                        // Symmetric with push: net-zero frame impact.
1072
                        ts_depth->fitness += frame_penalty;
1073
                        ts_depth->frame_depth--;
1074
                        DPRINTF(3, "  %s: return reward=+%d, depth=%d -> fitness=%d\n",
1075
                                _PyOpcode_uop_name[uop], frame_penalty,
1076
                                ts_depth->frame_depth,
1077
                                ts_depth->fitness);
1078
                    }
1079
                }
1080
                else if (_PyUop_Flags[uop] & HAS_RECORDS_VALUE_FLAG) {
1081
                    assert(record_idx < record_slot_map->count);
1082
                    uint8_t record_slot = record_slot_map->slots[record_idx];
1083
                    assert(record_slot < tracer->prev_state.recorded_count);
1084
                    PyObject *recorded_value = tracer->prev_state.recorded_values[record_slot];
1085
                    tracer->prev_state.recorded_values[record_slot] = NULL;
1086
                    if ((record_slot_map->transform_mask & (1u << record_idx)) &&
1087
                        recorded_value != NULL) {
1088
                        recorded_value = _PyOpcode_RecordTransformValue(uop, recorded_value);
1089
                    }
1090
                    record_idx++;
1091
                    operand = (uintptr_t)recorded_value;
1092
                }
1093
                // All other instructions
1094
                ADD_TO_TRACE(uop, oparg, operand, target);
1095
            }
1096
            break;
1097
        }  // End default
1098
1099
    }  // End switch (opcode)
1100
1101
    if (needs_guard_ip) {
1102
        int last_opcode = uop_buffer_last(trace)->opcode;
1103
        uint16_t guard_ip = guard_ip_uop[last_opcode];
1104
        if (guard_ip == 0) {
1105
            DPRINTF(1, "Unknown uop needing guard ip %s\n", _PyOpcode_uop_name[last_opcode]);
1106
            Py_UNREACHABLE();
1107
        }
1108
        PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable);
1109
        Py_INCREF(code);
1110
        ADD_TO_TRACE(_RECORD_CODE, 0, (uintptr_t)code, 0);
1111
        ADD_TO_TRACE(guard_ip, 0, (uintptr_t)next_instr, 0);
1112
        if (PyCode_Check(code)) {
1113
            /* Record stack depth, in operand1 */
1114
            int stack_depth = (int)(frame->stackpointer - _PyFrame_Stackbase(frame));
1115
            uop_buffer_last(trace)->operand1 = stack_depth;
1116
            ADD_TO_TRACE(guard_code_version_uop[last_opcode], 0, ((PyCodeObject *)code)->co_version, 0);
1117
        }
1118
    }
1119
    // Loop back to the start
1120
    int is_first_instr = tracer->initial_state.close_loop_instr == next_instr ||
1121
        tracer->initial_state.start_instr == next_instr;
1122
    if (is_first_instr && uop_buffer_length(trace) > CODE_SIZE_NO_PROGRESS) {
1123
        if (needs_guard_ip) {
1124
            ADD_TO_TRACE(_SET_IP, 0, (uintptr_t)next_instr, 0);
1125
        }
1126
        ADD_TO_TRACE(_JUMP_TO_TOP, 0, 0, 0);
1127
        goto done;
1128
    }
1129
    // Charge fitness by trace-buffer capacity consumed for this bytecode,
1130
    // including both emitted uops and tail reservations.
1131
    {
1132
        int32_t slots_used = remaining_before - uop_buffer_remaining_space(trace);
1133
        tracer->translator_state.fitness -= slots_used;
1134
        DPRINTF(3, "  per-insn cost: -%d -> fitness=%d\n", slots_used,
1135
                tracer->translator_state.fitness);
1136
    }
1137
    DPRINTF(2, "Trace continuing (fitness=%d)\n", tracer->translator_state.fitness);
1138
    return 1;
1139
done:
1140
    DPRINTF(2, "Trace done\n");
1141
    if (!is_terminator(uop_buffer_last(trace))) {
1142
        ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target);
1143
    }
1144
    return 0;
1145
}
1146
1147
// Returns 0 for do not enter tracing, 1 on enter tracing.
1148
// gh-142543: inlining this function causes stack overflows
1149
Py_NO_INLINE int
1150
_PyJit_TryInitializeTracing(
1151
    PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *curr_instr,
1152
    _Py_CODEUNIT *start_instr, _Py_CODEUNIT *close_loop_instr, _PyStackRef *stack_pointer, int chain_depth,
1153
    _PyExitData *exit, int oparg, _PyExecutorObject *current_executor)
1154
{
1155
    _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
1156
    if (_tstate->jit_tracer_state == NULL) {
1157
        _tstate->jit_tracer_state = (_PyJitTracerState *)_PyObject_VirtualAlloc(sizeof(_PyJitTracerState));
1158
        if (_tstate->jit_tracer_state == NULL) {
1159
            // Don't error, just go to next instruction.
1160
            return 0;
1161
        }
1162
        _tstate->jit_tracer_state->is_tracing = false;
1163
    }
1164
    _PyJitTracerState *tracer = _tstate->jit_tracer_state;
1165
    // A recursive trace.
1166
    if (tracer->is_tracing) {
1167
        return 0;
1168
    }
1169
    if (oparg > 0xFFFF) {
1170
        return 0;
1171
    }
1172
    PyObject *func = PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
1173
    if (func == NULL || !PyFunction_Check(func)) {
1174
        return 0;
1175
    }
1176
    PyCodeObject *code = _PyFrame_GetCode(frame);
1177
#ifdef Py_DEBUG
1178
    char *python_lltrace = Py_GETENV("PYTHON_LLTRACE");
1179
    int lltrace = 0;
1180
    if (python_lltrace != NULL && *python_lltrace >= '0') {
1181
        lltrace = *python_lltrace - '0';  // TODO: Parse an int and all that
1182
    }
1183
    DPRINTF(2,
1184
        "Tracing %s (%s:%d) at byte offset %d at chain depth %d\n",
1185
        PyUnicode_AsUTF8(code->co_qualname),
1186
        PyUnicode_AsUTF8(code->co_filename),
1187
        code->co_firstlineno,
1188
        2 * INSTR_IP(close_loop_instr, code),
1189
        chain_depth);
1190
#endif
1191
    /* Set up tracing buffer*/
1192
    _PyJitUopBuffer *trace = &tracer->code_buffer;
1193
    uop_buffer_init(trace, &tracer->uop_array[0], UOP_MAX_TRACE_LENGTH);
1194
    _PyJitTracerTranslatorState *ts = &tracer->translator_state;
1195
    ts->fitness = tstate->interp->opt_config.fitness_initial;
1196
    ts->frame_depth = 0;
1197
    ADD_TO_TRACE(_START_EXECUTOR, 0, (uintptr_t)start_instr, INSTR_IP(start_instr, code));
1198
    ADD_TO_TRACE(_MAKE_WARM, 0, 0, 0);
1199
1200
    tracer->initial_state.start_instr = start_instr;
1201
    tracer->initial_state.close_loop_instr = close_loop_instr;
1202
    tracer->initial_state.code = (PyCodeObject *)Py_NewRef(code);
1203
    tracer->initial_state.func = (PyFunctionObject *)Py_NewRef(func);
1204
    tracer->initial_state.executor = (_PyExecutorObject *)Py_XNewRef(current_executor);
1205
    tracer->initial_state.exit = exit;
1206
    tracer->initial_state.stack_depth = (int)(stack_pointer - _PyFrame_Stackbase(frame));
1207
    tracer->initial_state.chain_depth = chain_depth;
1208
    tracer->prev_state.instr_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame));
1209
    tracer->prev_state.instr = curr_instr;
1210
    tracer->prev_state.instr_frame = frame;
1211
    tracer->prev_state.instr_oparg = oparg;
1212
    tracer->prev_state.instr_stacklevel = tracer->initial_state.stack_depth;
1213
    tracer->prev_state.recorded_count = 0;
1214
    for (int i = 0; i < MAX_RECORDED_VALUES; i++) {
1215
        tracer->prev_state.recorded_values[i] = NULL;
1216
    }
1217
    const _PyOpcodeRecordEntry *record_entry = &_PyOpcode_RecordEntries[curr_instr->op.code];
1218
    for (int i = 0; i < record_entry->count; i++) {
1219
        _Py_RecordFuncPtr record_func = _PyOpcode_RecordFunctions[record_entry->indices[i]];
1220
        record_func(frame, stack_pointer, oparg, &tracer->prev_state.recorded_values[i]);
1221
    }
1222
    tracer->prev_state.recorded_count = record_entry->count;
1223
    assert(curr_instr->op.code == JUMP_BACKWARD_JIT || curr_instr->op.code == RESUME_CHECK_JIT || (exit != NULL));
1224
    tracer->initial_state.jump_backward_instr = curr_instr;
1225
1226
    DPRINTF(3, "Fitness init: chain_depth=%d, fitness=%d\n",
1227
            chain_depth, ts->fitness);
1228
1229
    tracer->is_tracing = true;
1230
    return 1;
1231
}
1232
1233
Py_NO_INLINE void
1234
_PyJit_FinalizeTracing(PyThreadState *tstate, int err)
1235
{
1236
    _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
1237
    _PyJitTracerState *tracer = _tstate->jit_tracer_state;
1238
    // Deal with backoffs
1239
    assert(tracer != NULL);
1240
    _PyExitData *exit = tracer->initial_state.exit;
1241
    if (exit == NULL) {
1242
        // We hold a strong reference to the code object, so the instruction won't be freed.
1243
        if (err <= 0) {
1244
            _Py_BackoffCounter counter = tracer->initial_state.jump_backward_instr[1].counter;
1245
            tracer->initial_state.jump_backward_instr[1].counter = restart_backoff_counter(counter);
1246
        }
1247
        else {
1248
            if (tracer->initial_state.jump_backward_instr[0].op.code == JUMP_BACKWARD_JIT) {
1249
                tracer->initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(&tstate->interp->opt_config);
1250
            }
1251
            else {
1252
                tracer->initial_state.jump_backward_instr[1].counter = initial_resume_backoff_counter(&tstate->interp->opt_config);
1253
            }
1254
        }
1255
    }
1256
    else if (tracer->initial_state.executor->vm_data.valid) {
1257
        // Likewise, we hold a strong reference to the executor containing this exit, so the exit is guaranteed
1258
        // to be valid to access.
1259
        if (err <= 0) {
1260
            exit->temperature = restart_backoff_counter(exit->temperature);
1261
        }
1262
        else {
1263
            exit->temperature = initial_temperature_backoff_counter(&tstate->interp->opt_config);
1264
        }
1265
    }
1266
    // Clear all recorded values
1267
    _PyJitUopBuffer *buffer = &tracer->code_buffer;
1268
    for (_PyUOpInstruction *inst = buffer->start; inst < buffer->next; inst++) {
1269
        if (_PyUop_Flags[inst->opcode] & HAS_RECORDS_VALUE_FLAG) {
1270
            Py_XDECREF((PyObject *)(uintptr_t)inst->operand0);
1271
        }
1272
    }
1273
    Py_CLEAR(tracer->initial_state.code);
1274
    Py_CLEAR(tracer->initial_state.func);
1275
    Py_CLEAR(tracer->initial_state.executor);
1276
    Py_CLEAR(tracer->prev_state.instr_code);
1277
    for (int i = 0; i < MAX_RECORDED_VALUES; i++) {
1278
        Py_CLEAR(tracer->prev_state.recorded_values[i]);
1279
    }
1280
    tracer->prev_state.recorded_count = 0;
1281
    uop_buffer_init(buffer, &tracer->uop_array[0], UOP_MAX_TRACE_LENGTH);
1282
    tracer->is_tracing = false;
1283
}
1284
1285
bool
1286
_PyJit_EnterExecutorShouldStopTracing(int og_opcode)
1287
{
1288
    // Continue tracing (skip over the executor). If it's a RESUME
1289
    // trace to form longer, more optimizeable traces.
1290
    // We want to trace over RESUME traces. Otherwise, functions with lots of RESUME
1291
    // end up with many fragmented traces which perform badly.
1292
    // See for example, the richards benchmark in pyperformance.
1293
    // For consideration: We may want to consider tracing over side traces
1294
    // inserted into bytecode as well in the future.
1295
    return og_opcode == RESUME_CHECK_JIT;
1296
}
1297
1298
void
1299
_PyJit_TracerFree(_PyThreadStateImpl *_tstate)
1300
{
1301
    if (_tstate->jit_tracer_state != NULL) {
1302
        _PyObject_VirtualFree(_tstate->jit_tracer_state, sizeof(_PyJitTracerState));
1303
        _tstate->jit_tracer_state = NULL;
1304
    }
1305
}
1306
1307
#undef RESERVE
1308
#undef INSTR_IP
1309
#undef ADD_TO_TRACE
1310
#undef DPRINTF
1311
1312
#define UNSET_BIT(array, bit) (array[(bit)>>5] &= ~(1<<((bit)&31)))
1313
#define SET_BIT(array, bit) (array[(bit)>>5] |= (1<<((bit)&31)))
1314
#define BIT_IS_SET(array, bit) (array[(bit)>>5] & (1<<((bit)&31)))
1315
1316
/* Count the number of unused uops and exits
1317
*/
1318
static int
1319
count_exits(_PyUOpInstruction *buffer, int length)
1320
{
1321
    int exit_count = 0;
1322
    for (int i = 0; i < length; i++) {
1323
        uint16_t base_opcode = _PyUop_Uncached[buffer[i].opcode];
1324
        if (base_opcode == _EXIT_TRACE || base_opcode == _DYNAMIC_EXIT) {
1325
            exit_count++;
1326
        }
1327
    }
1328
    return exit_count;
1329
}
1330
1331
/* The number of cached registers at any exit (`EXIT_IF` or `DEOPT_IF`)
1332
 * This is the number of cached at entries at start, unless the uop is
1333
 * marked as `exit_depth_is_output` in which case it is the number of
1334
 * cached entries at the end */
1335
static int
1336
get_cached_entries_for_side_exit(_PyUOpInstruction *inst)
1337
{
1338
    // Maybe add another generated table for this?
1339
    int base_opcode = _PyUop_Uncached[inst->opcode];
1340
    assert(base_opcode != 0);
1341
    for (int i = 0; i <= MAX_CACHED_REGISTER; i++) {
1342
        const _PyUopTOSentry *entry = &_PyUop_Caching[base_opcode].entries[i];
1343
        if (entry->opcode == inst->opcode) {
1344
            return entry->exit;
1345
        }
1346
    }
1347
    Py_UNREACHABLE();
1348
}
1349
1350
static void make_exit(_PyUOpInstruction *inst, int opcode, int target, bool is_control_flow)
1351
{
1352
    assert(opcode > MAX_UOP_ID && opcode <= MAX_UOP_REGS_ID);
1353
    inst->opcode = opcode;
1354
    inst->oparg = 0;
1355
    inst->operand0 = 0;
1356
    inst->format = UOP_FORMAT_TARGET;
1357
    inst->target = target;
1358
    inst->operand1 = is_control_flow;
1359
#ifdef Py_STATS
1360
    inst->fitness = 0;
1361
    inst->execution_count = 0;
1362
#endif
1363
}
1364
1365
/* Convert implicit exits, errors and deopts
1366
 * into explicit ones. */
1367
static int
1368
prepare_for_execution(_PyUOpInstruction *buffer, int length)
1369
{
1370
    int32_t current_jump = -1;
1371
    int32_t current_jump_target = -1;
1372
    int32_t current_error = -1;
1373
    int32_t current_error_target = -1;
1374
    int32_t current_popped = -1;
1375
    int32_t current_exit_op = -1;
1376
    /* Leaving in NOPs slows down the interpreter and messes up the stats */
1377
    _PyUOpInstruction *copy_to = &buffer[0];
1378
    for (int i = 0; i < length; i++) {
1379
        _PyUOpInstruction *inst = &buffer[i];
1380
        if (inst->opcode != _NOP) {
1381
            if (copy_to != inst) {
1382
                *copy_to = *inst;
1383
            }
1384
            copy_to++;
1385
        }
1386
    }
1387
    length = (int)(copy_to - buffer);
1388
    int next_spare = length;
1389
    for (int i = 0; i < length; i++) {
1390
        _PyUOpInstruction *inst = &buffer[i];
1391
        int base_opcode = _PyUop_Uncached[inst->opcode];
1392
        assert(inst->opcode != _NOP);
1393
        int32_t target = (int32_t)uop_get_target(inst);
1394
        uint16_t exit_flags = _PyUop_Flags[base_opcode] & (HAS_EXIT_FLAG | HAS_DEOPT_FLAG | HAS_PERIODIC_FLAG);
1395
        if (exit_flags) {
1396
            uint16_t base_exit_op = _EXIT_TRACE;
1397
            if (exit_flags & HAS_DEOPT_FLAG) {
1398
                base_exit_op = _DEOPT;
1399
            }
1400
            else if (exit_flags & HAS_PERIODIC_FLAG) {
1401
                base_exit_op = _HANDLE_PENDING_AND_DEOPT;
1402
            }
1403
            int32_t jump_target = target;
1404
            if (dynamic_exit_uop[base_opcode]) {
1405
                base_exit_op = _DYNAMIC_EXIT;
1406
            }
1407
            int exit_depth = get_cached_entries_for_side_exit(inst);
1408
            assert(_PyUop_Caching[base_exit_op].entries[exit_depth].opcode > 0);
1409
            int16_t exit_op = _PyUop_Caching[base_exit_op].entries[exit_depth].opcode;
1410
            bool is_control_flow = (base_opcode == _GUARD_IS_FALSE_POP || base_opcode == _GUARD_IS_TRUE_POP || is_for_iter_test[base_opcode]);
1411
            if (jump_target != current_jump_target || current_exit_op != exit_op) {
1412
                make_exit(&buffer[next_spare], exit_op, jump_target, is_control_flow);
1413
                current_exit_op = exit_op;
1414
                current_jump_target = jump_target;
1415
                current_jump = next_spare;
1416
                next_spare++;
1417
            }
1418
            buffer[i].jump_target = current_jump;
1419
            buffer[i].format = UOP_FORMAT_JUMP;
1420
        }
1421
        if (_PyUop_Flags[base_opcode] & HAS_ERROR_FLAG) {
1422
            int popped = (_PyUop_Flags[base_opcode] & HAS_ERROR_NO_POP_FLAG) ?
1423
                0 : _PyUop_num_popped(base_opcode, inst->oparg);
1424
            if (target != current_error_target || popped != current_popped) {
1425
                current_popped = popped;
1426
                current_error = next_spare;
1427
                current_error_target = target;
1428
                make_exit(&buffer[next_spare], _ERROR_POP_N_r00, 0, false);
1429
                buffer[next_spare].operand0 = target;
1430
                next_spare++;
1431
            }
1432
            buffer[i].error_target = current_error;
1433
            if (buffer[i].format == UOP_FORMAT_TARGET) {
1434
                buffer[i].format = UOP_FORMAT_JUMP;
1435
                buffer[i].jump_target = 0;
1436
            }
1437
        }
1438
        if (base_opcode == _JUMP_TO_TOP) {
1439
            assert(_PyUop_Uncached[buffer[0].opcode] == _START_EXECUTOR);
1440
            buffer[i].format = UOP_FORMAT_JUMP;
1441
            buffer[i].jump_target = 1;
1442
        }
1443
    }
1444
    return next_spare;
1445
}
1446
1447
/* Executor side exits */
1448
1449
static _PyExecutorObject *
1450
allocate_executor(int exit_count, int length)
1451
{
1452
    int size = exit_count*sizeof(_PyExitData) + length*sizeof(_PyUOpInstruction);
1453
    _PyExecutorObject *res = PyObject_GC_NewVar(_PyExecutorObject, &_PyUOpExecutor_Type, size);
1454
    if (res == NULL) {
1455
        return NULL;
1456
    }
1457
    res->trace = (_PyUOpInstruction *)(res->exits + exit_count);
1458
    res->code_size = length;
1459
    res->exit_count = exit_count;
1460
    res->jit_registration = NULL;
1461
    return res;
1462
}
1463
1464
#ifdef Py_DEBUG
1465
1466
#define CHECK(PRED) \
1467
if (!(PRED)) { \
1468
    printf(#PRED " at %d\n", i); \
1469
    assert(0); \
1470
}
1471
1472
static int
1473
target_unused(int opcode)
1474
{
1475
    return (_PyUop_Flags[opcode] & (HAS_ERROR_FLAG | HAS_EXIT_FLAG | HAS_DEOPT_FLAG)) == 0;
1476
}
1477
1478
static void
1479
sanity_check(_PyExecutorObject *executor)
1480
{
1481
    for (uint32_t i = 0; i < executor->exit_count; i++) {
1482
        _PyExitData *exit = &executor->exits[i];
1483
        CHECK(exit->target < (1 << 25));
1484
    }
1485
    bool ended = false;
1486
    uint32_t i = 0;
1487
    CHECK(_PyUop_Uncached[executor->trace[0].opcode] == _START_EXECUTOR ||
1488
        _PyUop_Uncached[executor->trace[0].opcode] == _COLD_EXIT ||
1489
        _PyUop_Uncached[executor->trace[0].opcode] == _COLD_DYNAMIC_EXIT);
1490
    for (; i < executor->code_size; i++) {
1491
        const _PyUOpInstruction *inst = &executor->trace[i];
1492
        uint16_t opcode = inst->opcode;
1493
        uint16_t base_opcode = _PyUop_Uncached[opcode];
1494
        CHECK(opcode > MAX_UOP_ID);
1495
        CHECK(opcode <= MAX_UOP_REGS_ID);
1496
        CHECK(base_opcode <= MAX_UOP_ID);
1497
        CHECK(base_opcode != 0);
1498
        switch(inst->format) {
1499
            case UOP_FORMAT_TARGET:
1500
                CHECK(target_unused(base_opcode));
1501
                break;
1502
            case UOP_FORMAT_JUMP:
1503
                CHECK(inst->jump_target < executor->code_size);
1504
                break;
1505
        }
1506
        if (_PyUop_Flags[base_opcode] & HAS_ERROR_FLAG) {
1507
            CHECK(inst->format == UOP_FORMAT_JUMP);
1508
            CHECK(inst->error_target < executor->code_size);
1509
        }
1510
        if (is_terminator(inst)) {
1511
            ended = true;
1512
            i++;
1513
            break;
1514
        }
1515
    }
1516
    CHECK(ended);
1517
    for (; i < executor->code_size; i++) {
1518
        const _PyUOpInstruction *inst = &executor->trace[i];
1519
        uint16_t base_opcode = _PyUop_Uncached[inst->opcode];
1520
        CHECK(
1521
            base_opcode == _DEOPT ||
1522
            base_opcode == _HANDLE_PENDING_AND_DEOPT ||
1523
            base_opcode == _EXIT_TRACE ||
1524
            base_opcode == _ERROR_POP_N ||
1525
            base_opcode == _DYNAMIC_EXIT);
1526
    }
1527
}
1528
1529
#undef CHECK
1530
#endif
1531
1532
/* Makes an executor from a buffer of uops.
1533
 * Account for the buffer having gaps and NOPs by computing a "used"
1534
 * bit vector and only copying the used uops. Here "used" means reachable
1535
 * and not a NOP.
1536
 */
1537
static _PyExecutorObject *
1538
make_executor_from_uops(_PyThreadStateImpl *tstate, _PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies)
1539
{
1540
    int exit_count = count_exits(buffer, length);
1541
    _PyExecutorObject *executor = allocate_executor(exit_count, length);
1542
    if (executor == NULL) {
1543
        return NULL;
1544
    }
1545
1546
    /* Initialize exits */
1547
    int chain_depth = tstate->jit_tracer_state->initial_state.chain_depth;
1548
    _PyExecutorObject *cold = _PyExecutor_GetColdExecutor();
1549
    _PyExecutorObject *cold_dynamic = _PyExecutor_GetColdDynamicExecutor();
1550
    cold->vm_data.chain_depth = chain_depth;
1551
    PyInterpreterState *interp = tstate->base.interp;
1552
    for (int i = 0; i < exit_count; i++) {
1553
        executor->exits[i].index = i;
1554
        executor->exits[i].temperature = initial_temperature_backoff_counter(&interp->opt_config);
1555
    }
1556
    int next_exit = exit_count-1;
1557
    _PyUOpInstruction *dest = (_PyUOpInstruction *)&executor->trace[length];
1558
    assert(_PyUop_Uncached[buffer[0].opcode] == _START_EXECUTOR);
1559
    buffer[0].operand0 = (uint64_t)executor;
1560
    for (int i = length-1; i >= 0; i--) {
1561
        uint16_t base_opcode = _PyUop_Uncached[buffer[i].opcode];
1562
        dest--;
1563
        *dest = buffer[i];
1564
        if (base_opcode == _EXIT_TRACE || base_opcode == _DYNAMIC_EXIT) {
1565
            _PyExitData *exit = &executor->exits[next_exit];
1566
            exit->target = buffer[i].target;
1567
            dest->operand0 = (uint64_t)exit;
1568
            exit->executor = base_opcode == _EXIT_TRACE ? cold : cold_dynamic;
1569
            exit->is_dynamic = (char)(base_opcode == _DYNAMIC_EXIT);
1570
            exit->is_control_flow = (char)buffer[i].operand1;
1571
            next_exit--;
1572
        }
1573
    }
1574
    assert(next_exit == -1);
1575
    assert(dest == executor->trace);
1576
    assert(_PyUop_Uncached[dest->opcode] == _START_EXECUTOR);
1577
    // Note: we MUST track it here before any Py_DECREF(executor) or
1578
    // linking of executor. Otherwise, the GC tries to untrack a
1579
    // still untracked object during dealloc.
1580
    _PyObject_GC_TRACK(executor);
1581
    if (_Py_ExecutorInit(executor, dependencies) < 0) {
1582
        Py_DECREF(executor);
1583
        return NULL;
1584
    }
1585
#ifdef Py_DEBUG
1586
    char *python_lltrace = Py_GETENV("PYTHON_LLTRACE");
1587
    int lltrace = 0;
1588
    if (python_lltrace != NULL && *python_lltrace >= '0') {
1589
        lltrace = *python_lltrace - '0';  // TODO: Parse an int and all that
1590
    }
1591
    if (lltrace >= 2) {
1592
        printf("Optimized trace (length %d):\n", length);
1593
        for (int i = 0; i < length; i++) {
1594
            printf("%4d OPTIMIZED: ", i);
1595
            _PyUOpPrint(&executor->trace[i]);
1596
            printf("\n");
1597
        }
1598
    }
1599
    sanity_check(executor);
1600
#endif
1601
#ifdef _Py_JIT
1602
    executor->jit_code = NULL;
1603
    executor->jit_size = 0;
1604
    // This is initialized to false so we can prevent the executor
1605
    // from being immediately detected as cold and invalidated.
1606
    executor->vm_data.cold = false;
1607
    if (_PyJIT_Compile(executor, executor->trace, length)) {
1608
        Py_DECREF(executor);
1609
        return NULL;
1610
    }
1611
#endif
1612
    return executor;
1613
}
1614
1615
#ifdef Py_STATS
1616
/* Returns the effective trace length.
1617
 * Ignores NOPs and trailing exit and error handling.*/
1618
int effective_trace_length(_PyUOpInstruction *buffer, int length)
1619
{
1620
    int nop_count = 0;
1621
    for (int i = 0; i < length; i++) {
1622
        int opcode = buffer[i].opcode;
1623
        if (opcode == _NOP) {
1624
            nop_count++;
1625
        }
1626
        if (is_terminator(&buffer[i])) {
1627
            return i+1-nop_count;
1628
        }
1629
    }
1630
    Py_FatalError("No terminating instruction");
1631
    Py_UNREACHABLE();
1632
}
1633
#endif
1634
1635
1636
static int
1637
stack_allocate(_PyUOpInstruction *buffer, _PyUOpInstruction *output, int length)
1638
{
1639
    assert(buffer[0].opcode == _START_EXECUTOR);
1640
    /* The input buffer and output buffers will overlap.
1641
       Make sure that we can move instructions to the output
1642
       without overwriting the input. */
1643
    if (buffer == output) {
1644
        // This can only happen if optimizer has not been run
1645
        for (int i = 0; i < length; i++) {
1646
            buffer[i + UOP_MAX_TRACE_LENGTH] = buffer[i];
1647
        }
1648
        buffer += UOP_MAX_TRACE_LENGTH;
1649
    }
1650
    else {
1651
        assert(output + UOP_MAX_TRACE_LENGTH == buffer);
1652
    }
1653
    int depth = 0;
1654
    _PyUOpInstruction *write = output;
1655
    for (int i = 0; i < length; i++) {
1656
        int uop = buffer[i].opcode;
1657
        if (uop == _NOP) {
1658
            continue;
1659
        }
1660
        int new_depth = _PyUop_Caching[uop].best[depth];
1661
        if (new_depth != depth) {
1662
            write->opcode = _PyUop_SpillsAndReloads[depth][new_depth];
1663
            assert(write->opcode != 0);
1664
            write->format = UOP_FORMAT_TARGET;
1665
            write->oparg = 0;
1666
            write->target = 0;
1667
            write++;
1668
            depth = new_depth;
1669
        }
1670
        *write = buffer[i];
1671
        uint16_t new_opcode = _PyUop_Caching[uop].entries[depth].opcode;
1672
        assert(new_opcode != 0);
1673
        write->opcode = new_opcode;
1674
        write++;
1675
        depth = _PyUop_Caching[uop].entries[depth].output;
1676
    }
1677
    return (int)(write - output);
1678
}
1679
1680
static int
1681
uop_optimize(
1682
    _PyInterpreterFrame *frame,
1683
    PyThreadState *tstate,
1684
    _PyExecutorObject **exec_ptr,
1685
    bool progress_needed)
1686
{
1687
    _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
1688
    assert(_tstate->jit_tracer_state != NULL);
1689
    _PyUOpInstruction *buffer = _tstate->jit_tracer_state->code_buffer.start;
1690
    OPT_STAT_INC(attempts);
1691
    bool is_noopt = !tstate->interp->opt_config.uops_optimize_enabled;
1692
    int curr_stackentries = _tstate->jit_tracer_state->initial_state.stack_depth;
1693
    int length = uop_buffer_length(&_tstate->jit_tracer_state->code_buffer);
1694
    if (length <= CODE_SIZE_NO_PROGRESS) {
1695
        return 0;
1696
    }
1697
    assert(length > 0);
1698
    assert(length < UOP_MAX_TRACE_LENGTH);
1699
    OPT_STAT_INC(traces_created);
1700
1701
    _PyBloomFilter dependencies;
1702
    _Py_BloomFilter_Init(&dependencies);
1703
    if (!is_noopt) {
1704
        _PyUOpInstruction *output = &_tstate->jit_tracer_state->uop_array[UOP_MAX_TRACE_LENGTH];
1705
        length = _Py_uop_analyze_and_optimize(
1706
            _tstate, buffer, length, curr_stackentries,
1707
            output, &dependencies);
1708
1709
        if (length <= 0) {
1710
            return length;
1711
        }
1712
        buffer = output;
1713
    }
1714
    assert(length < UOP_MAX_TRACE_LENGTH);
1715
    assert(length >= 1);
1716
    /* Fix up */
1717
    for (int pc = 0; pc < length; pc++) {
1718
        int opcode = buffer[pc].opcode;
1719
        int oparg = buffer[pc].oparg;
1720
        if (oparg < _PyUop_Replication[opcode].stop && oparg >= _PyUop_Replication[opcode].start) {
1721
            buffer[pc].opcode = opcode + oparg + 1 - _PyUop_Replication[opcode].start;
1722
            assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0);
1723
        }
1724
        else if (_PyUop_Flags[opcode] & HAS_RECORDS_VALUE_FLAG) {
1725
            Py_XDECREF((PyObject *)(uintptr_t)buffer[pc].operand0);
1726
            buffer[pc].opcode = _NOP;
1727
        }
1728
        else if (is_terminator(&buffer[pc])) {
1729
            break;
1730
        }
1731
        assert(_PyOpcode_uop_name[buffer[pc].opcode]);
1732
    }
1733
    // We've cleaned up the references in the buffer, so discard the code buffer
1734
    // to avoid doing it again during tracer cleanup
1735
    _PyJitUopBuffer *code_buffer = &_tstate->jit_tracer_state->code_buffer;
1736
    code_buffer->next = code_buffer->start;
1737
1738
    OPT_HIST(effective_trace_length(buffer, length), optimized_trace_length_hist);
1739
    _PyUOpInstruction *output = &_tstate->jit_tracer_state->uop_array[0];
1740
    length = stack_allocate(buffer, output, length);
1741
    buffer = output;
1742
    length = prepare_for_execution(buffer, length);
1743
    assert(length <= UOP_MAX_TRACE_LENGTH);
1744
    _PyExecutorObject *executor = make_executor_from_uops(
1745
        _tstate, buffer, length, &dependencies);
1746
    if (executor == NULL) {
1747
        return -1;
1748
    }
1749
    assert(length <= UOP_MAX_TRACE_LENGTH);
1750
1751
    // Check executor coldness
1752
    // It's okay if this ends up going negative.
1753
    if (--tstate->interp->executor_creation_counter == 0) {
1754
        _Py_set_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT);
1755
    }
1756
1757
    *exec_ptr = executor;
1758
    return 1;
1759
}
1760
1761
1762
/*****************************************
1763
 *        Executor management
1764
 ****************************************/
1765
1766
static int
1767
link_executor(_PyExecutorObject *executor, const _PyBloomFilter *bloom)
1768
{
1769
    PyInterpreterState *interp = _PyInterpreterState_GET();
1770
    if (interp->executor_count == interp->executor_capacity) {
1771
        size_t new_cap = interp->executor_capacity ? interp->executor_capacity * 2 : 64;
1772
        _PyBloomFilter *new_blooms = PyMem_Realloc(
1773
            interp->executor_blooms, new_cap * sizeof(_PyBloomFilter));
1774
        if (new_blooms == NULL) {
1775
            return -1;
1776
        }
1777
        _PyExecutorObject **new_ptrs = PyMem_Realloc(
1778
            interp->executor_ptrs, new_cap * sizeof(_PyExecutorObject *));
1779
        if (new_ptrs == NULL) {
1780
            /* Revert blooms realloc — the old pointer may have been freed by
1781
             * a successful realloc, but new_blooms is the valid pointer. */
1782
            interp->executor_blooms = new_blooms;
1783
            return -1;
1784
        }
1785
        interp->executor_blooms = new_blooms;
1786
        interp->executor_ptrs = new_ptrs;
1787
        interp->executor_capacity = new_cap;
1788
    }
1789
    size_t idx = interp->executor_count++;
1790
    interp->executor_blooms[idx] = *bloom;
1791
    interp->executor_ptrs[idx] = executor;
1792
    executor->vm_data.bloom_array_idx = (int32_t)idx;
1793
    return 0;
1794
}
1795
1796
static void
1797
unlink_executor(_PyExecutorObject *executor)
1798
{
1799
    PyInterpreterState *interp = PyInterpreterState_Get();
1800
    int32_t idx = executor->vm_data.bloom_array_idx;
1801
    assert(idx >= 0 && (size_t)idx < interp->executor_count);
1802
    size_t last = --interp->executor_count;
1803
    if ((size_t)idx != last) {
1804
        /* Swap-remove: move the last element into the vacated slot */
1805
        interp->executor_blooms[idx] = interp->executor_blooms[last];
1806
        interp->executor_ptrs[idx] = interp->executor_ptrs[last];
1807
        interp->executor_ptrs[idx]->vm_data.bloom_array_idx = idx;
1808
    }
1809
    executor->vm_data.bloom_array_idx = -1;
1810
}
1811
1812
/* This must be called by optimizers before using the executor */
1813
int
1814
_Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_set)
1815
{
1816
    executor->vm_data.valid = true;
1817
    executor->vm_data.pending_deletion = 0;
1818
    executor->vm_data.code = NULL;
1819
    if (link_executor(executor, dependency_set) < 0) {
1820
        return -1;
1821
    }
1822
    return 0;
1823
}
1824
1825
static _PyExecutorObject *
1826
make_cold_executor(uint16_t opcode)
1827
{
1828
    _PyExecutorObject *cold = allocate_executor(0, 1);
1829
    if (cold == NULL) {
1830
        Py_FatalError("Cannot allocate core JIT code");
1831
    }
1832
    ((_PyUOpInstruction *)cold->trace)->opcode = opcode;
1833
    // This is initialized to false so we can prevent the executor
1834
    // from being immediately detected as cold and invalidated.
1835
    cold->vm_data.cold = false;
1836
#ifdef _Py_JIT
1837
    cold->jit_code = NULL;
1838
    cold->jit_size = 0;
1839
    if (_PyJIT_Compile(cold, cold->trace, 1)) {
1840
        Py_DECREF(cold);
1841
        Py_FatalError("Cannot allocate core JIT code");
1842
    }
1843
#endif
1844
    _Py_SetImmortal((PyObject *)cold);
1845
    return cold;
1846
}
1847
1848
_PyExecutorObject *
1849
_PyExecutor_GetColdExecutor(void)
1850
{
1851
    PyInterpreterState *interp = _PyInterpreterState_GET();
1852
    if (interp->cold_executor == NULL) {
1853
        return interp->cold_executor = make_cold_executor(_COLD_EXIT_r00);;
1854
    }
1855
    return interp->cold_executor;
1856
}
1857
1858
_PyExecutorObject *
1859
_PyExecutor_GetColdDynamicExecutor(void)
1860
{
1861
    PyInterpreterState *interp = _PyInterpreterState_GET();
1862
    if (interp->cold_dynamic_executor == NULL) {
1863
        interp->cold_dynamic_executor = make_cold_executor(_COLD_DYNAMIC_EXIT_r00);
1864
    }
1865
    return interp->cold_dynamic_executor;
1866
}
1867
1868
void
1869
_PyExecutor_ClearExit(_PyExitData *exit)
1870
{
1871
    if (exit == NULL) {
1872
        return;
1873
    }
1874
    _PyExecutorObject *old = exit->executor;
1875
    if (exit->is_dynamic) {
1876
        exit->executor = _PyExecutor_GetColdDynamicExecutor();
1877
    }
1878
    else {
1879
        exit->executor = _PyExecutor_GetColdExecutor();
1880
    }
1881
    Py_DECREF(old);
1882
}
1883
1884
/* Detaches the executor from the code object (if any) that
1885
 * holds a reference to it */
1886
void
1887
_Py_ExecutorDetach(_PyExecutorObject *executor)
1888
{
1889
    PyCodeObject *code = executor->vm_data.code;
1890
    if (code == NULL) {
1891
        return;
1892
    }
1893
    _Py_CODEUNIT *instruction = &_PyCode_CODE(code)[executor->vm_data.index];
1894
    assert(instruction->op.code == ENTER_EXECUTOR);
1895
    int index = instruction->op.arg;
1896
    assert(code->co_executors->executors[index] == executor);
1897
    instruction->op.code = _PyOpcode_Deopt[executor->vm_data.opcode];
1898
    instruction->op.arg = executor->vm_data.oparg;
1899
    executor->vm_data.code = NULL;
1900
    code->co_executors->executors[index] = NULL;
1901
    Py_DECREF(executor);
1902
}
1903
1904
/* Executors can be invalidated at any time,
1905
   even with a stop-the-world lock held.
1906
   Consequently it must not run arbitrary code,
1907
   including Py_DECREF with a non-executor. */
1908
static void
1909
executor_invalidate(PyObject *op)
1910
{
1911
    _PyExecutorObject *executor = _PyExecutorObject_CAST(op);
1912
    if (!executor->vm_data.valid) {
1913
        return;
1914
    }
1915
    executor->vm_data.valid = 0;
1916
    unlink_executor(executor);
1917
    executor_clear_exits(executor);
1918
    _Py_ExecutorDetach(executor);
1919
    _PyObject_GC_UNTRACK(op);
1920
}
1921
1922
static int
1923
executor_clear(PyObject *op)
1924
{
1925
    executor_invalidate(op);
1926
    return 0;
1927
}
1928
1929
void
1930
_Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj)
1931
{
1932
    assert(executor->vm_data.valid);
1933
    PyInterpreterState *interp = _PyInterpreterState_GET();
1934
    int32_t idx = executor->vm_data.bloom_array_idx;
1935
    assert(idx >= 0 && (size_t)idx < interp->executor_count);
1936
    _Py_BloomFilter_Add(&interp->executor_blooms[idx], obj);
1937
}
1938
1939
/* Invalidate all executors that depend on `obj`
1940
 * May cause other executors to be invalidated as well.
1941
 * Uses contiguous bloom filter array for cache-friendly scanning.
1942
 */
1943
void
1944
_Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation)
1945
{
1946
    _PyBloomFilter obj_filter;
1947
    _Py_BloomFilter_Init(&obj_filter);
1948
    _Py_BloomFilter_Add(&obj_filter, obj);
1949
    /* Scan contiguous bloom filter array */
1950
    PyObject *invalidate = PyList_New(0);
1951
    if (invalidate == NULL) {
1952
        goto error;
1953
    }
1954
    /* Clearing an executor can clear others, so we need to make a list of
1955
     * executors to invalidate first */
1956
    for (size_t i = 0; i < interp->executor_count; i++) {
1957
        assert(interp->executor_ptrs[i]->vm_data.valid);
1958
        if (bloom_filter_may_contain(&interp->executor_blooms[i], &obj_filter) &&
1959
            PyList_Append(invalidate, (PyObject *)interp->executor_ptrs[i]))
1960
        {
1961
            goto error;
1962
        }
1963
    }
1964
    for (Py_ssize_t i = 0; i < PyList_GET_SIZE(invalidate); i++) {
1965
        PyObject *exec = PyList_GET_ITEM(invalidate, i);
1966
        executor_invalidate(exec);
1967
        if (is_invalidation) {
1968
            OPT_STAT_INC(executors_invalidated);
1969
        }
1970
    }
1971
    Py_DECREF(invalidate);
1972
    return;
1973
error:
1974
    PyErr_Clear();
1975
    Py_XDECREF(invalidate);
1976
    // If we're truly out of memory, wiping out everything is a fine fallback:
1977
    _Py_Executors_InvalidateAll(interp, is_invalidation);
1978
}
1979
1980
/* Invalidate all executors */
1981
void
1982
_Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
1983
{
1984
    while (interp->executor_count > 0) {
1985
        /* Invalidate from the end to avoid repeated swap-remove shifts */
1986
        _PyExecutorObject *executor = interp->executor_ptrs[interp->executor_count - 1];
1987
        assert(executor->vm_data.valid);
1988
        if (executor->vm_data.code) {
1989
            // Clear the entire code object so its co_executors array be freed:
1990
            _PyCode_Clear_Executors(executor->vm_data.code);
1991
        }
1992
        else {
1993
            executor_invalidate((PyObject *)executor);
1994
        }
1995
        if (is_invalidation) {
1996
            OPT_STAT_INC(executors_invalidated);
1997
        }
1998
    }
1999
}
2000
2001
void
2002
_Py_Executors_InvalidateCold(PyInterpreterState *interp)
2003
{
2004
    /* Scan contiguous executor array */
2005
    PyObject *invalidate = PyList_New(0);
2006
    if (invalidate == NULL) {
2007
        goto error;
2008
    }
2009
2010
    /* Clearing an executor can deallocate others, so we need to make a list of
2011
     * executors to invalidate first */
2012
    for (size_t i = 0; i < interp->executor_count; i++) {
2013
        _PyExecutorObject *exec = interp->executor_ptrs[i];
2014
        assert(exec->vm_data.valid);
2015
2016
        if (exec->vm_data.cold && PyList_Append(invalidate, (PyObject *)exec) < 0) {
2017
            goto error;
2018
        }
2019
        else {
2020
            exec->vm_data.cold = true;
2021
        }
2022
    }
2023
    for (Py_ssize_t i = 0; i < PyList_GET_SIZE(invalidate); i++) {
2024
        PyObject *exec = PyList_GET_ITEM(invalidate, i);
2025
        executor_invalidate(exec);
2026
    }
2027
    Py_DECREF(invalidate);
2028
    return;
2029
error:
2030
    PyErr_Clear();
2031
    Py_XDECREF(invalidate);
2032
    // If we're truly out of memory, wiping out everything is a fine fallback
2033
    _Py_Executors_InvalidateAll(interp, 0);
2034
}
2035
2036
#include "record_functions.c.h"
2037
2038
static int
2039
escape_angles(const char *input, Py_ssize_t size, char *buffer) {
2040
    int written = 0;
2041
    for (Py_ssize_t i = 0; i < size; i++) {
2042
        char c = input[i];
2043
        if (c == '<' || c == '>') {
2044
            buffer[written++] = '&';
2045
            buffer[written++] = c == '>' ? 'g' : 'l';
2046
            buffer[written++] = 't';
2047
            buffer[written++] = ';';
2048
        }
2049
        else {
2050
            buffer[written++] = c;
2051
        }
2052
    }
2053
    return written;
2054
}
2055
2056
static void
2057
write_str(PyObject *str, FILE *out)
2058
{
2059
    // Encode the Unicode object to the specified encoding
2060
    PyObject *encoded_obj = PyUnicode_AsEncodedString(str, "utf8", "strict");
2061
    if (encoded_obj == NULL) {
2062
        PyErr_Clear();
2063
        return;
2064
    }
2065
    const char *encoded_str = PyBytes_AsString(encoded_obj);
2066
    Py_ssize_t encoded_size = PyBytes_Size(encoded_obj);
2067
    char buffer[120];
2068
    bool truncated = false;
2069
    if (encoded_size > 24) {
2070
        encoded_size = 24;
2071
        truncated = true;
2072
    }
2073
    int size = escape_angles(encoded_str, encoded_size, buffer);
2074
    fwrite(buffer, 1, size, out);
2075
    if (truncated) {
2076
        fwrite("...", 1, 3, out);
2077
    }
2078
    Py_DECREF(encoded_obj);
2079
}
2080
2081
static int
2082
find_line_number(PyCodeObject *code, _PyExecutorObject *executor)
2083
{
2084
    int code_len = (int)Py_SIZE(code);
2085
    for (int i = 0; i < code_len; i++) {
2086
        _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
2087
        int opcode = instr->op.code;
2088
        if (opcode == ENTER_EXECUTOR) {
2089
            _PyExecutorObject *exec = code->co_executors->executors[instr->op.arg];
2090
            if (exec == executor) {
2091
                return PyCode_Addr2Line(code, i*2);
2092
            }
2093
        }
2094
        i += _PyOpcode_Caches[_Py_GetBaseCodeUnit(code, i).op.code];
2095
    }
2096
    return -1;
2097
}
2098
2099
#define RED "#ff0000"
2100
#define WHITE "#ffffff"
2101
#define BLUE "#0000ff"
2102
#define BLACK "#000000"
2103
#define LOOP "#00c000"
2104
2105
#ifdef Py_STATS
2106
2107
static const char *COLORS[10] = {
2108
    "9",
2109
    "8",
2110
    "7",
2111
    "6",
2112
    "5",
2113
    "4",
2114
    "3",
2115
    "2",
2116
    "1",
2117
    WHITE,
2118
};
2119
const char *
2120
get_background_color(_PyUOpInstruction const *inst, uint64_t max_hotness)
2121
{
2122
    uint64_t hotness = inst->execution_count;
2123
    int index = (hotness * 10)/max_hotness;
2124
    if (index > 9) {
2125
        index = 9;
2126
    }
2127
    if (index < 0) {
2128
        index = 0;
2129
    }
2130
    return COLORS[index];
2131
}
2132
2133
const char *
2134
get_foreground_color(_PyUOpInstruction const *inst, uint64_t max_hotness)
2135
{
2136
    if(_PyUop_Uncached[inst->opcode] == _DEOPT) {
2137
        return RED;
2138
    }
2139
    uint64_t hotness = inst->execution_count;
2140
    int index = (hotness * 10)/max_hotness;
2141
    if (index > 3) {
2142
        return BLACK;
2143
    }
2144
    return WHITE;
2145
}
2146
#endif
2147
2148
static void
2149
write_row_for_uop(_PyExecutorObject *executor, uint32_t i, FILE *out)
2150
{
2151
    /* Write row for uop.
2152
        * The `port` is a marker so that outgoing edges can
2153
        * be placed correctly. If a row is marked `port=17`,
2154
        * then the outgoing edge is `{EXEC_NAME}:17 -> {TARGET}`
2155
        * https://graphviz.readthedocs.io/en/stable/manual.html#node-ports-compass
2156
        */
2157
    _PyUOpInstruction const *inst = &executor->trace[i];
2158
    const char *opname = _PyOpcode_uop_name[inst->opcode];
2159
#ifdef Py_STATS
2160
    const char *bg_color = get_background_color(inst, executor->trace[0].execution_count);
2161
    const char *color = get_foreground_color(inst, executor->trace[0].execution_count);
2162
    fprintf(out, "        <tr><td port=\"i%d\" border=\"1\" color=\"%s\" bgcolor=\"%s\" ><font color=\"%s\"> %s [%d]&nbsp;--&nbsp; %" PRIu64 "</font></td></tr>\n",
2163
        i, color, bg_color, color, opname, inst->fitness, inst->execution_count);
2164
#else
2165
    const char *color = (_PyUop_Uncached[inst->opcode] == _DEOPT) ? RED : BLACK;
2166
    fprintf(out, "        <tr><td port=\"i%d\" border=\"1\" color=\"%s\" >%s op0=%" PRIu64 "</td></tr>\n", i, color, opname, inst->operand0);
2167
#endif
2168
}
2169
2170
static bool
2171
is_stop(_PyUOpInstruction const *inst)
2172
{
2173
    uint16_t base_opcode = _PyUop_Uncached[inst->opcode];
2174
    return (base_opcode == _EXIT_TRACE || base_opcode == _DEOPT || base_opcode == _JUMP_TO_TOP);
2175
}
2176
2177
2178
/* Writes the node and outgoing edges for a single tracelet in graphviz format.
2179
 * Each tracelet is presented as a table of the uops it contains.
2180
 * If Py_STATS is enabled, execution counts are included.
2181
 *
2182
 * https://graphviz.readthedocs.io/en/stable/manual.html
2183
 * https://graphviz.org/gallery/
2184
 */
2185
static void
2186
executor_to_gv(_PyExecutorObject *executor, FILE *out)
2187
{
2188
    PyCodeObject *code = executor->vm_data.code;
2189
    fprintf(out, "executor_%p [\n", executor);
2190
    fprintf(out, "    shape = none\n");
2191
2192
    /* Write the HTML table for the uops */
2193
    fprintf(out, "    label = <<table border=\"0\" cellspacing=\"0\">\n");
2194
    fprintf(out, "        <tr><td port=\"start\" border=\"1\" ><b>Executor</b></td></tr>\n");
2195
    if (code == NULL) {
2196
        fprintf(out, "        <tr><td border=\"1\" >No code object</td></tr>\n");
2197
    }
2198
    else {
2199
        fprintf(out, "        <tr><td  border=\"1\" >");
2200
        write_str(code->co_qualname, out);
2201
        int line = find_line_number(code, executor);
2202
        fprintf(out, ": %d</td></tr>\n", line);
2203
    }
2204
    for (uint32_t i = 0; i < executor->code_size; i++) {
2205
        write_row_for_uop(executor, i, out);
2206
        if (is_stop(&executor->trace[i])) {
2207
            break;
2208
        }
2209
    }
2210
    fprintf(out, "    </table>>\n");
2211
    fprintf(out, "]\n\n");
2212
2213
    /* Write all the outgoing edges */
2214
    _PyExecutorObject *cold = _PyExecutor_GetColdExecutor();
2215
    _PyExecutorObject *cold_dynamic = _PyExecutor_GetColdDynamicExecutor();
2216
    for (uint32_t i = 0; i < executor->code_size; i++) {
2217
        _PyUOpInstruction const *inst = &executor->trace[i];
2218
        uint16_t base_opcode = _PyUop_Uncached[inst->opcode];
2219
        uint16_t flags = _PyUop_Flags[base_opcode];
2220
        _PyExitData *exit = NULL;
2221
        if (base_opcode == _JUMP_TO_TOP) {
2222
            fprintf(out, "executor_%p:i%d -> executor_%p:i%d [color = \"" LOOP "\"]\n", executor, i, executor, inst->jump_target);
2223
            break;
2224
        }
2225
        if (base_opcode == _EXIT_TRACE) {
2226
            exit = (_PyExitData *)inst->operand0;
2227
        }
2228
        else if (flags & HAS_EXIT_FLAG) {
2229
            assert(inst->format == UOP_FORMAT_JUMP);
2230
            _PyUOpInstruction const *exit_inst = &executor->trace[inst->jump_target];
2231
            uint16_t base_exit_opcode = _PyUop_Uncached[exit_inst->opcode];
2232
            (void)base_exit_opcode;
2233
            assert(base_exit_opcode == _EXIT_TRACE || base_exit_opcode == _DYNAMIC_EXIT);
2234
            exit = (_PyExitData *)exit_inst->operand0;
2235
        }
2236
        if (exit != NULL) {
2237
            if (exit->executor == cold || exit->executor == cold_dynamic) {
2238
#ifdef Py_STATS
2239
                /* Only mark as have cold exit if it has actually exited */
2240
                uint64_t diff = inst->execution_count - executor->trace[i+1].execution_count;
2241
                if (diff) {
2242
                    fprintf(out, "cold_%p%d [ label = \"%"  PRIu64  "\" shape = ellipse color=\"" BLUE "\" ]\n", executor, i, diff);
2243
                    fprintf(out, "executor_%p:i%d -> cold_%p%d\n", executor, i, executor, i);
2244
                }
2245
#endif
2246
            }
2247
            else {
2248
                fprintf(out, "executor_%p:i%d -> executor_%p:start\n", executor, i, exit->executor);
2249
            }
2250
        }
2251
        if (is_stop(inst)) {
2252
            break;
2253
        }
2254
    }
2255
}
2256
2257
/* Write the graph of all the live tracelets in graphviz format. */
2258
int
2259
_PyDumpExecutors(FILE *out)
2260
{
2261
    fprintf(out, "digraph ideal {\n\n");
2262
    fprintf(out, "    rankdir = \"LR\"\n\n");
2263
    fprintf(out, "    node [colorscheme=greys9]\n");
2264
    PyInterpreterState *interp = PyInterpreterState_Get();
2265
    for (size_t i = 0; i < interp->executor_count; i++) {
2266
        executor_to_gv(interp->executor_ptrs[i], out);
2267
    }
2268
    fprintf(out, "}\n\n");
2269
    return 0;
2270
}
2271
2272
#else
2273
2274
int
2275
_PyDumpExecutors(FILE *out)
2276
0
{
2277
0
    PyErr_SetString(PyExc_NotImplementedError, "No JIT available");
2278
0
    return -1;
2279
0
}
2280
2281
void
2282
_PyExecutor_Free(struct _PyExecutorObject *self)
2283
0
{
2284
    /* This should never be called */
2285
0
    Py_UNREACHABLE();
2286
0
}
2287
2288
#endif /* _Py_TIER2 */