Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Modules/_opcode.c
Line
Count
Source (jump to first uncovered line)
1
#ifndef Py_BUILD_CORE_BUILTIN
2
#  define Py_BUILD_CORE_MODULE 1
3
#endif
4
5
#include "Python.h"
6
#include "compile.h"
7
#include "opcode.h"
8
#include "pycore_ceval.h"           // SPECIAL_MAX
9
#include "pycore_code.h"
10
#include "pycore_compile.h"
11
#include "pycore_intrinsics.h"
12
#include "pycore_optimizer.h"     // _Py_GetExecutor()
13
#include "pycore_opcode_metadata.h" // IS_VALID_OPCODE, OPCODE_HAS_*, etc
14
#include "pycore_opcode_utils.h"
15
16
/*[clinic input]
17
module _opcode
18
[clinic start generated code]*/
19
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=117442e66eb376e6]*/
20
21
#include "clinic/_opcode.c.h"
22
23
/*[clinic input]
24
25
_opcode.stack_effect -> int
26
27
  opcode: int
28
  oparg: object = None
29
  /
30
  *
31
  jump: object = None
32
33
Compute the stack effect of the opcode.
34
[clinic start generated code]*/
35
36
static int
37
_opcode_stack_effect_impl(PyObject *module, int opcode, PyObject *oparg,
38
                          PyObject *jump)
39
/*[clinic end generated code: output=64a18f2ead954dbb input=461c9d4a44851898]*/
40
0
{
41
0
    int oparg_int = 0;
42
0
    int jump_int;
43
44
0
    if (oparg != Py_None) {
45
0
        oparg_int = (int)PyLong_AsLong(oparg);
46
0
        if ((oparg_int == -1) && PyErr_Occurred()) {
47
0
            return -1;
48
0
        }
49
0
    }
50
51
0
    if (jump == Py_None) {
52
0
        jump_int = -1;
53
0
    }
54
0
    else if (jump == Py_True) {
55
0
        jump_int = 1;
56
0
    }
57
0
    else if (jump == Py_False) {
58
0
        jump_int = 0;
59
0
    }
60
0
    else {
61
0
        PyErr_SetString(PyExc_ValueError,
62
0
                "stack_effect: jump must be False, True or None");
63
0
        return -1;
64
0
    }
65
0
    int effect = PyCompile_OpcodeStackEffectWithJump(opcode, oparg_int, jump_int);
66
0
    if (effect == PY_INVALID_STACK_EFFECT) {
67
0
        PyErr_SetString(PyExc_ValueError, "invalid opcode or oparg");
68
0
        return -1;
69
0
    }
70
0
    return effect;
71
0
}
72
73
/*[clinic input]
74
75
_opcode.is_valid -> bool
76
77
  opcode: int
78
79
Return True if opcode is valid, False otherwise.
80
[clinic start generated code]*/
81
82
static int
83
_opcode_is_valid_impl(PyObject *module, int opcode)
84
/*[clinic end generated code: output=b0d918ea1d073f65 input=fe23e0aa194ddae0]*/
85
0
{
86
0
    return IS_VALID_OPCODE(opcode);
87
0
}
88
89
/*[clinic input]
90
91
_opcode.has_arg -> bool
92
93
  opcode: int
94
95
Return True if the opcode uses its oparg, False otherwise.
96
[clinic start generated code]*/
97
98
static int
99
_opcode_has_arg_impl(PyObject *module, int opcode)
100
/*[clinic end generated code: output=7a062d3b2dcc0815 input=93d878ba6361db5f]*/
101
0
{
102
0
    return IS_VALID_OPCODE(opcode) && OPCODE_HAS_ARG(opcode);
103
0
}
104
105
/*[clinic input]
106
107
_opcode.has_const -> bool
108
109
  opcode: int
110
111
Return True if the opcode accesses a constant, False otherwise.
112
[clinic start generated code]*/
113
114
static int
115
_opcode_has_const_impl(PyObject *module, int opcode)
116
/*[clinic end generated code: output=c646d5027c634120 input=a6999e4cf13f9410]*/
117
0
{
118
0
    return IS_VALID_OPCODE(opcode) && OPCODE_HAS_CONST(opcode);
119
0
}
120
121
/*[clinic input]
122
123
_opcode.has_name -> bool
124
125
  opcode: int
126
127
Return True if the opcode accesses an attribute by name, False otherwise.
128
[clinic start generated code]*/
129
130
static int
131
_opcode_has_name_impl(PyObject *module, int opcode)
132
/*[clinic end generated code: output=b49a83555c2fa517 input=448aa5e4bcc947ba]*/
133
0
{
134
0
    return IS_VALID_OPCODE(opcode) && OPCODE_HAS_NAME(opcode);
135
0
}
136
137
/*[clinic input]
138
139
_opcode.has_jump -> bool
140
141
  opcode: int
142
143
Return True if the opcode has a jump target, False otherwise.
144
[clinic start generated code]*/
145
146
static int
147
_opcode_has_jump_impl(PyObject *module, int opcode)
148
/*[clinic end generated code: output=e9c583c669f1c46a input=35f711274357a0c3]*/
149
0
{
150
0
    return IS_VALID_OPCODE(opcode) && OPCODE_HAS_JUMP(opcode);
151
0
}
152
153
/*[clinic input]
154
155
_opcode.has_free -> bool
156
157
  opcode: int
158
159
Return True if the opcode accesses a free variable, False otherwise.
160
161
Note that 'free' in this context refers to names in the current scope
162
that are referenced by inner scopes or names in outer scopes that are
163
referenced from this scope. It does not include references to global
164
or builtin scopes.
165
[clinic start generated code]*/
166
167
static int
168
_opcode_has_free_impl(PyObject *module, int opcode)
169
/*[clinic end generated code: output=d81ae4d79af0ee26 input=117dcd5c19c1139b]*/
170
0
{
171
0
    return IS_VALID_OPCODE(opcode) && OPCODE_HAS_FREE(opcode);
172
0
}
173
174
/*[clinic input]
175
176
_opcode.has_local -> bool
177
178
  opcode: int
179
180
Return True if the opcode accesses a local variable, False otherwise.
181
[clinic start generated code]*/
182
183
static int
184
_opcode_has_local_impl(PyObject *module, int opcode)
185
/*[clinic end generated code: output=da5a8616b7a5097b input=9a798ee24aaef49d]*/
186
0
{
187
0
    return IS_VALID_OPCODE(opcode) && OPCODE_HAS_LOCAL(opcode);
188
0
}
189
190
/*[clinic input]
191
192
_opcode.has_exc -> bool
193
194
  opcode: int
195
196
Return True if the opcode sets an exception handler, False otherwise.
197
[clinic start generated code]*/
198
199
static int
200
_opcode_has_exc_impl(PyObject *module, int opcode)
201
/*[clinic end generated code: output=41b68dff0ec82a52 input=db0e4bdb9bf13fa5]*/
202
0
{
203
0
    return IS_VALID_OPCODE(opcode) && IS_BLOCK_PUSH_OPCODE(opcode);
204
0
}
205
206
/*[clinic input]
207
208
_opcode.get_specialization_stats
209
210
Return the specialization stats
211
[clinic start generated code]*/
212
213
static PyObject *
214
_opcode_get_specialization_stats_impl(PyObject *module)
215
/*[clinic end generated code: output=fcbc32fdfbec5c17 input=e1f60db68d8ce5f6]*/
216
0
{
217
#ifdef Py_STATS
218
    return _Py_GetSpecializationStats();
219
#else
220
0
    Py_RETURN_NONE;
221
0
#endif
222
0
}
223
224
/*[clinic input]
225
226
_opcode.get_nb_ops
227
228
Return array of symbols of binary ops.
229
230
Indexed by the BINARY_OP oparg value.
231
[clinic start generated code]*/
232
233
static PyObject *
234
_opcode_get_nb_ops_impl(PyObject *module)
235
/*[clinic end generated code: output=d997d306cc15426f input=9462fc544c823176]*/
236
0
{
237
0
    PyObject *list = PyList_New(NB_OPARG_LAST + 1);
238
0
    if (list == NULL) {
239
0
        return NULL;
240
0
    }
241
0
#define ADD_NB_OP(NUM, STR) \
242
0
    do { \
243
0
        PyObject *pair = Py_BuildValue("ss", #NUM, STR); \
244
0
        if (pair == NULL) { \
245
0
            Py_DECREF(list); \
246
0
            return NULL; \
247
0
        } \
248
0
        PyList_SET_ITEM(list, (NUM), pair); \
249
0
    } while(0);
250
251
0
    ADD_NB_OP(NB_ADD, "+");
252
0
    ADD_NB_OP(NB_AND, "&");
253
0
    ADD_NB_OP(NB_FLOOR_DIVIDE, "//");
254
0
    ADD_NB_OP(NB_LSHIFT, "<<");
255
0
    ADD_NB_OP(NB_MATRIX_MULTIPLY, "@");
256
0
    ADD_NB_OP(NB_MULTIPLY, "*");
257
0
    ADD_NB_OP(NB_REMAINDER, "%");
258
0
    ADD_NB_OP(NB_OR, "|");
259
0
    ADD_NB_OP(NB_POWER, "**");
260
0
    ADD_NB_OP(NB_RSHIFT, ">>");
261
0
    ADD_NB_OP(NB_SUBTRACT, "-");
262
0
    ADD_NB_OP(NB_TRUE_DIVIDE, "/");
263
0
    ADD_NB_OP(NB_XOR, "^");
264
0
    ADD_NB_OP(NB_INPLACE_ADD, "+=");
265
0
    ADD_NB_OP(NB_INPLACE_AND, "&=");
266
0
    ADD_NB_OP(NB_INPLACE_FLOOR_DIVIDE, "//=");
267
0
    ADD_NB_OP(NB_INPLACE_LSHIFT, "<<=");
268
0
    ADD_NB_OP(NB_INPLACE_MATRIX_MULTIPLY, "@=");
269
0
    ADD_NB_OP(NB_INPLACE_MULTIPLY, "*=");
270
0
    ADD_NB_OP(NB_INPLACE_REMAINDER, "%=");
271
0
    ADD_NB_OP(NB_INPLACE_OR, "|=");
272
0
    ADD_NB_OP(NB_INPLACE_POWER, "**=");
273
0
    ADD_NB_OP(NB_INPLACE_RSHIFT, ">>=");
274
0
    ADD_NB_OP(NB_INPLACE_SUBTRACT, "-=");
275
0
    ADD_NB_OP(NB_INPLACE_TRUE_DIVIDE, "/=");
276
0
    ADD_NB_OP(NB_INPLACE_XOR, "^=");
277
0
    ADD_NB_OP(NB_SUBSCR, "[]");
278
279
0
#undef ADD_NB_OP
280
281
0
    for(int i = 0; i <= NB_OPARG_LAST; i++) {
282
0
        if (PyList_GET_ITEM(list, i) == NULL) {
283
0
            Py_DECREF(list);
284
0
            PyErr_Format(PyExc_ValueError,
285
0
                         "Missing initialization for NB_OP %d",
286
0
                         i);
287
0
            return NULL;
288
0
        }
289
0
    }
290
0
    return list;
291
0
}
292
293
/*[clinic input]
294
295
_opcode.get_intrinsic1_descs
296
297
Return a list of names of the unary intrinsics.
298
[clinic start generated code]*/
299
300
static PyObject *
301
_opcode_get_intrinsic1_descs_impl(PyObject *module)
302
/*[clinic end generated code: output=bd1ddb6b4447d18b input=13b51c712618459b]*/
303
0
{
304
0
    PyObject *list = PyList_New(MAX_INTRINSIC_1 + 1);
305
0
    if (list == NULL) {
306
0
        return NULL;
307
0
    }
308
0
    for (int i=0; i <= MAX_INTRINSIC_1; i++) {
309
0
        PyObject *name = _PyCompile_GetUnaryIntrinsicName(i);
310
0
        if (name == NULL) {
311
0
            Py_DECREF(list);
312
0
            return NULL;
313
0
        }
314
0
        PyList_SET_ITEM(list, i, name);
315
0
    }
316
0
    return list;
317
0
}
318
319
320
/*[clinic input]
321
322
_opcode.get_intrinsic2_descs
323
324
Return a list of names of the binary intrinsics.
325
[clinic start generated code]*/
326
327
static PyObject *
328
_opcode_get_intrinsic2_descs_impl(PyObject *module)
329
/*[clinic end generated code: output=40e62bc27584c8a0 input=e83068f249f5471b]*/
330
0
{
331
0
    PyObject *list = PyList_New(MAX_INTRINSIC_2 + 1);
332
0
    if (list == NULL) {
333
0
        return NULL;
334
0
    }
335
0
    for (int i=0; i <= MAX_INTRINSIC_2; i++) {
336
0
        PyObject *name = _PyCompile_GetBinaryIntrinsicName(i);
337
0
        if (name == NULL) {
338
0
            Py_DECREF(list);
339
0
            return NULL;
340
0
        }
341
0
        PyList_SET_ITEM(list, i, name);
342
0
    }
343
0
    return list;
344
0
}
345
346
/*[clinic input]
347
348
_opcode.get_special_method_names
349
350
Return a list of special method names.
351
[clinic start generated code]*/
352
353
static PyObject *
354
_opcode_get_special_method_names_impl(PyObject *module)
355
/*[clinic end generated code: output=fce72614cd988d17 input=25f2115560bdf163]*/
356
0
{
357
0
    PyObject *list = PyList_New(SPECIAL_MAX + 1);
358
0
    if (list == NULL) {
359
0
        return NULL;
360
0
    }
361
0
    for (int i=0; i <= SPECIAL_MAX; i++) {
362
0
        PyObject *name = _Py_SpecialMethods[i].name;
363
0
        if (name == NULL) {
364
0
            Py_DECREF(list);
365
0
            return NULL;
366
0
        }
367
0
        PyList_SET_ITEM(list, i, name);
368
0
    }
369
0
    return list;
370
0
}
371
372
/*[clinic input]
373
374
_opcode.get_executor
375
376
  code: object
377
  offset: int
378
379
Return the executor object at offset in code if exists, None otherwise.
380
[clinic start generated code]*/
381
382
static PyObject *
383
_opcode_get_executor_impl(PyObject *module, PyObject *code, int offset)
384
/*[clinic end generated code: output=c035c7a47b16648f input=85eff93ea7aac282]*/
385
0
{
386
0
    if (!PyCode_Check(code)) {
387
0
        PyErr_Format(PyExc_TypeError,
388
0
                     "expected a code object, not '%.100s'",
389
0
                     Py_TYPE(code)->tp_name);
390
0
        return NULL;
391
0
    }
392
#ifdef _Py_TIER2
393
    return (PyObject *)_Py_GetExecutor((PyCodeObject *)code, offset);
394
#else
395
0
    PyErr_Format(PyExc_RuntimeError,
396
0
                 "Executors are not available in this build");
397
0
    return NULL;
398
0
#endif
399
0
}
400
401
static PyMethodDef
402
opcode_functions[] =  {
403
    _OPCODE_STACK_EFFECT_METHODDEF
404
    _OPCODE_IS_VALID_METHODDEF
405
    _OPCODE_HAS_ARG_METHODDEF
406
    _OPCODE_HAS_CONST_METHODDEF
407
    _OPCODE_HAS_NAME_METHODDEF
408
    _OPCODE_HAS_JUMP_METHODDEF
409
    _OPCODE_HAS_FREE_METHODDEF
410
    _OPCODE_HAS_LOCAL_METHODDEF
411
    _OPCODE_HAS_EXC_METHODDEF
412
    _OPCODE_GET_SPECIALIZATION_STATS_METHODDEF
413
    _OPCODE_GET_NB_OPS_METHODDEF
414
    _OPCODE_GET_INTRINSIC1_DESCS_METHODDEF
415
    _OPCODE_GET_INTRINSIC2_DESCS_METHODDEF
416
    _OPCODE_GET_EXECUTOR_METHODDEF
417
    _OPCODE_GET_SPECIAL_METHOD_NAMES_METHODDEF
418
    {NULL, NULL, 0, NULL}
419
};
420
421
static int
422
0
_opcode_exec(PyObject *m) {
423
0
    if (PyModule_AddIntMacro(m, ENABLE_SPECIALIZATION) < 0) {
424
0
        return -1;
425
0
    }
426
0
    if (PyModule_AddIntMacro(m, ENABLE_SPECIALIZATION_FT) < 0) {
427
0
        return -1;
428
0
    }
429
0
    return 0;
430
0
}
431
432
static PyModuleDef_Slot module_slots[] = {
433
    {Py_mod_exec, _opcode_exec},
434
    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
435
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
436
    {0, NULL}
437
};
438
439
static struct PyModuleDef opcodemodule = {
440
    PyModuleDef_HEAD_INIT,
441
    .m_name = "_opcode",
442
    .m_doc = "Opcode support module.",
443
    .m_size = 0,
444
    .m_methods = opcode_functions,
445
    .m_slots = module_slots,
446
};
447
448
PyMODINIT_FUNC
449
PyInit__opcode(void)
450
0
{
451
0
    return PyModuleDef_Init(&opcodemodule);
452
0
}