/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 | } |