GH-126599: Remove the PyOptimizer API (GH-129194)

This commit is contained in:
Brandt Bucher 2025-01-28 16:10:51 -08:00 committed by GitHub
parent 5c930a26fb
commit 828b27680f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 345 additions and 435 deletions

View file

@ -31,7 +31,7 @@ extern "C" {
#include "pycore_list.h" // struct _Py_list_state #include "pycore_list.h" // struct _Py_list_state
#include "pycore_mimalloc.h" // struct _mimalloc_interp_state #include "pycore_mimalloc.h" // struct _mimalloc_interp_state
#include "pycore_object_state.h" // struct _py_object_state #include "pycore_object_state.h" // struct _py_object_state
#include "pycore_optimizer.h" // _PyOptimizerObject #include "pycore_optimizer.h" // _PyExecutorObject
#include "pycore_obmalloc.h" // struct _obmalloc_state #include "pycore_obmalloc.h" // struct _obmalloc_state
#include "pycore_qsbr.h" // struct _qsbr_state #include "pycore_qsbr.h" // struct _qsbr_state
#include "pycore_stackref.h" // Py_STACKREF_DEBUG #include "pycore_stackref.h" // Py_STACKREF_DEBUG
@ -262,7 +262,7 @@ struct _is {
struct ast_state ast; struct ast_state ast;
struct types_state types; struct types_state types;
struct callable_cache callable_cache; struct callable_cache callable_cache;
_PyOptimizerObject *optimizer; bool jit;
_PyExecutorObject *executor_list_head; _PyExecutorObject *executor_list_head;
size_t trace_run_counter; size_t trace_run_counter;
_rare_events rare_events; _rare_events rare_events;

View file

@ -271,8 +271,12 @@ int _PyOpcode_num_popped(int opcode, int oparg) {
return 0; return 0;
case JUMP_BACKWARD: case JUMP_BACKWARD:
return 0; return 0;
case JUMP_BACKWARD_JIT:
return 0;
case JUMP_BACKWARD_NO_INTERRUPT: case JUMP_BACKWARD_NO_INTERRUPT:
return 0; return 0;
case JUMP_BACKWARD_NO_JIT:
return 0;
case JUMP_FORWARD: case JUMP_FORWARD:
return 0; return 0;
case JUMP_IF_FALSE: case JUMP_IF_FALSE:
@ -742,8 +746,12 @@ int _PyOpcode_num_pushed(int opcode, int oparg) {
return 0; return 0;
case JUMP_BACKWARD: case JUMP_BACKWARD:
return 0; return 0;
case JUMP_BACKWARD_JIT:
return 0;
case JUMP_BACKWARD_NO_INTERRUPT: case JUMP_BACKWARD_NO_INTERRUPT:
return 0; return 0;
case JUMP_BACKWARD_NO_JIT:
return 0;
case JUMP_FORWARD: case JUMP_FORWARD:
return 0; return 0;
case JUMP_IF_FALSE: case JUMP_IF_FALSE:
@ -1467,10 +1475,18 @@ int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect) {
*effect = 0; *effect = 0;
return 0; return 0;
} }
case JUMP_BACKWARD_JIT: {
*effect = 0;
return 0;
}
case JUMP_BACKWARD_NO_INTERRUPT: { case JUMP_BACKWARD_NO_INTERRUPT: {
*effect = 0; *effect = 0;
return 0; return 0;
} }
case JUMP_BACKWARD_NO_JIT: {
*effect = 0;
return 0;
}
case JUMP_FORWARD: { case JUMP_FORWARD: {
*effect = 0; *effect = 0;
return 0; return 0;
@ -2110,7 +2126,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
[INTERPRETER_EXIT] = { true, INSTR_FMT_IX, 0 }, [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, 0 },
[IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
[JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[JUMP_BACKWARD_JIT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
[JUMP_BACKWARD_NO_JIT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
[LIST_APPEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [LIST_APPEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG },
[LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
@ -2539,7 +2557,9 @@ const char *_PyOpcode_OpName[266] = {
[IS_OP] = "IS_OP", [IS_OP] = "IS_OP",
[JUMP] = "JUMP", [JUMP] = "JUMP",
[JUMP_BACKWARD] = "JUMP_BACKWARD", [JUMP_BACKWARD] = "JUMP_BACKWARD",
[JUMP_BACKWARD_JIT] = "JUMP_BACKWARD_JIT",
[JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT",
[JUMP_BACKWARD_NO_JIT] = "JUMP_BACKWARD_NO_JIT",
[JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_FORWARD] = "JUMP_FORWARD",
[JUMP_IF_FALSE] = "JUMP_IF_FALSE", [JUMP_IF_FALSE] = "JUMP_IF_FALSE",
[JUMP_IF_TRUE] = "JUMP_IF_TRUE", [JUMP_IF_TRUE] = "JUMP_IF_TRUE",
@ -2800,7 +2820,9 @@ const uint8_t _PyOpcode_Deopt[256] = {
[INTERPRETER_EXIT] = INTERPRETER_EXIT, [INTERPRETER_EXIT] = INTERPRETER_EXIT,
[IS_OP] = IS_OP, [IS_OP] = IS_OP,
[JUMP_BACKWARD] = JUMP_BACKWARD, [JUMP_BACKWARD] = JUMP_BACKWARD,
[JUMP_BACKWARD_JIT] = JUMP_BACKWARD,
[JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT,
[JUMP_BACKWARD_NO_JIT] = JUMP_BACKWARD,
[JUMP_FORWARD] = JUMP_FORWARD, [JUMP_FORWARD] = JUMP_FORWARD,
[LIST_APPEND] = LIST_APPEND, [LIST_APPEND] = LIST_APPEND,
[LIST_EXTEND] = LIST_EXTEND, [LIST_EXTEND] = LIST_EXTEND,
@ -2939,8 +2961,6 @@ const uint8_t _PyOpcode_Deopt[256] = {
case 146: \ case 146: \
case 147: \ case 147: \
case 148: \ case 148: \
case 230: \
case 231: \
case 232: \ case 232: \
case 233: \ case 233: \
case 234: \ case 234: \

View file

@ -83,23 +83,6 @@ typedef struct _PyExecutorObject {
_PyExitData exits[1]; _PyExitData exits[1];
} _PyExecutorObject; } _PyExecutorObject;
typedef struct _PyOptimizerObject _PyOptimizerObject;
/* Should return > 0 if a new executor is created. O if no executor is produced and < 0 if an error occurred. */
typedef int (*_Py_optimize_func)(
_PyOptimizerObject* self, struct _PyInterpreterFrame *frame,
_Py_CODEUNIT *instr, _PyExecutorObject **exec_ptr,
int curr_stackentries, bool progress_needed);
struct _PyOptimizerObject {
PyObject_HEAD
_Py_optimize_func optimize;
/* Data needed by the optimizer goes here, but is opaque to the VM */
};
/** Test support **/
_PyOptimizerObject *_Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject* optimizer);
// Export for '_opcode' shared extension (JIT compiler). // Export for '_opcode' shared extension (JIT compiler).
PyAPI_FUNC(_PyExecutorObject*) _Py_GetExecutor(PyCodeObject *code, int offset); PyAPI_FUNC(_PyExecutorObject*) _Py_GetExecutor(PyCodeObject *code, int offset);
@ -110,12 +93,6 @@ void _Py_BloomFilter_Init(_PyBloomFilter *);
void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj); void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj);
PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
// For testing
// Export for '_testinternalcapi' shared extension.
PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void);
PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer);
PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void);
#define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3 #define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3
#define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6 #define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6
@ -144,9 +121,7 @@ int _Py_uop_analyze_and_optimize(struct _PyInterpreterFrame *frame,
_PyUOpInstruction *trace, int trace_len, int curr_stackentries, _PyUOpInstruction *trace, int trace_len, int curr_stackentries,
_PyBloomFilter *dependencies); _PyBloomFilter *dependencies);
extern PyTypeObject _PyDefaultOptimizer_Type;
extern PyTypeObject _PyUOpExecutor_Type; extern PyTypeObject _PyUOpExecutor_Type;
extern PyTypeObject _PyUOpOptimizer_Type;
#define UOP_FORMAT_TARGET 0 #define UOP_FORMAT_TARGET 0

72
Include/opcode_ids.h generated
View file

@ -174,41 +174,43 @@ extern "C" {
#define FOR_ITER_LIST 192 #define FOR_ITER_LIST 192
#define FOR_ITER_RANGE 193 #define FOR_ITER_RANGE 193
#define FOR_ITER_TUPLE 194 #define FOR_ITER_TUPLE 194
#define LOAD_ATTR_CLASS 195 #define JUMP_BACKWARD_JIT 195
#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 196 #define JUMP_BACKWARD_NO_JIT 196
#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 197 #define LOAD_ATTR_CLASS 197
#define LOAD_ATTR_INSTANCE_VALUE 198 #define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 198
#define LOAD_ATTR_METHOD_LAZY_DICT 199 #define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 199
#define LOAD_ATTR_METHOD_NO_DICT 200 #define LOAD_ATTR_INSTANCE_VALUE 200
#define LOAD_ATTR_METHOD_WITH_VALUES 201 #define LOAD_ATTR_METHOD_LAZY_DICT 201
#define LOAD_ATTR_MODULE 202 #define LOAD_ATTR_METHOD_NO_DICT 202
#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 203 #define LOAD_ATTR_METHOD_WITH_VALUES 203
#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 204 #define LOAD_ATTR_MODULE 204
#define LOAD_ATTR_PROPERTY 205 #define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 205
#define LOAD_ATTR_SLOT 206 #define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 206
#define LOAD_ATTR_WITH_HINT 207 #define LOAD_ATTR_PROPERTY 207
#define LOAD_CONST_IMMORTAL 208 #define LOAD_ATTR_SLOT 208
#define LOAD_CONST_MORTAL 209 #define LOAD_ATTR_WITH_HINT 209
#define LOAD_GLOBAL_BUILTIN 210 #define LOAD_CONST_IMMORTAL 210
#define LOAD_GLOBAL_MODULE 211 #define LOAD_CONST_MORTAL 211
#define LOAD_SUPER_ATTR_ATTR 212 #define LOAD_GLOBAL_BUILTIN 212
#define LOAD_SUPER_ATTR_METHOD 213 #define LOAD_GLOBAL_MODULE 213
#define RESUME_CHECK 214 #define LOAD_SUPER_ATTR_ATTR 214
#define SEND_GEN 215 #define LOAD_SUPER_ATTR_METHOD 215
#define STORE_ATTR_INSTANCE_VALUE 216 #define RESUME_CHECK 216
#define STORE_ATTR_SLOT 217 #define SEND_GEN 217
#define STORE_ATTR_WITH_HINT 218 #define STORE_ATTR_INSTANCE_VALUE 218
#define STORE_SUBSCR_DICT 219 #define STORE_ATTR_SLOT 219
#define STORE_SUBSCR_LIST_INT 220 #define STORE_ATTR_WITH_HINT 220
#define TO_BOOL_ALWAYS_TRUE 221 #define STORE_SUBSCR_DICT 221
#define TO_BOOL_BOOL 222 #define STORE_SUBSCR_LIST_INT 222
#define TO_BOOL_INT 223 #define TO_BOOL_ALWAYS_TRUE 223
#define TO_BOOL_LIST 224 #define TO_BOOL_BOOL 224
#define TO_BOOL_NONE 225 #define TO_BOOL_INT 225
#define TO_BOOL_STR 226 #define TO_BOOL_LIST 226
#define UNPACK_SEQUENCE_LIST 227 #define TO_BOOL_NONE 227
#define UNPACK_SEQUENCE_TUPLE 228 #define TO_BOOL_STR 228
#define UNPACK_SEQUENCE_TWO_TUPLE 229 #define UNPACK_SEQUENCE_LIST 229
#define UNPACK_SEQUENCE_TUPLE 230
#define UNPACK_SEQUENCE_TWO_TUPLE 231
#define INSTRUMENTED_END_FOR 235 #define INSTRUMENTED_END_FOR 235
#define INSTRUMENTED_POP_ITER 236 #define INSTRUMENTED_POP_ITER 236
#define INSTRUMENTED_END_SEND 237 #define INSTRUMENTED_END_SEND 237

View file

@ -38,12 +38,8 @@ executor in `co_executors`.
## The micro-op optimizer ## The micro-op optimizer
The optimizer that `_PyOptimizer_Optimize()` runs is configurable via the
`_Py_SetTier2Optimizer()` function (this is used in test via
`_testinternalcapi.set_optimizer()`.)
The micro-op (abbreviated `uop` to approximate `μop`) optimizer is defined in The micro-op (abbreviated `uop` to approximate `μop`) optimizer is defined in
[`Python/optimizer.c`](../Python/optimizer.c) as the type `_PyUOpOptimizer_Type`. [`Python/optimizer.c`](../Python/optimizer.c) as `_PyOptimizer_Optimize`.
It translates an instruction trace into a sequence of micro-ops by replacing It translates an instruction trace into a sequence of micro-ops by replacing
each bytecode by an equivalent sequence of micro-ops (see each bytecode by an equivalent sequence of micro-ops (see
`_PyOpcode_macro_expansion` in `_PyOpcode_macro_expansion` in

View file

@ -85,6 +85,10 @@ _specializations = {
"CONTAINS_OP_SET", "CONTAINS_OP_SET",
"CONTAINS_OP_DICT", "CONTAINS_OP_DICT",
], ],
"JUMP_BACKWARD": [
"JUMP_BACKWARD_NO_JIT",
"JUMP_BACKWARD_JIT",
],
"FOR_ITER": [ "FOR_ITER": [
"FOR_ITER_LIST", "FOR_ITER_LIST",
"FOR_ITER_TUPLE", "FOR_ITER_TUPLE",
@ -167,41 +171,43 @@ _specialized_opmap = {
'FOR_ITER_LIST': 192, 'FOR_ITER_LIST': 192,
'FOR_ITER_RANGE': 193, 'FOR_ITER_RANGE': 193,
'FOR_ITER_TUPLE': 194, 'FOR_ITER_TUPLE': 194,
'LOAD_ATTR_CLASS': 195, 'JUMP_BACKWARD_JIT': 195,
'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 196, 'JUMP_BACKWARD_NO_JIT': 196,
'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 197, 'LOAD_ATTR_CLASS': 197,
'LOAD_ATTR_INSTANCE_VALUE': 198, 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 198,
'LOAD_ATTR_METHOD_LAZY_DICT': 199, 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 199,
'LOAD_ATTR_METHOD_NO_DICT': 200, 'LOAD_ATTR_INSTANCE_VALUE': 200,
'LOAD_ATTR_METHOD_WITH_VALUES': 201, 'LOAD_ATTR_METHOD_LAZY_DICT': 201,
'LOAD_ATTR_MODULE': 202, 'LOAD_ATTR_METHOD_NO_DICT': 202,
'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 203, 'LOAD_ATTR_METHOD_WITH_VALUES': 203,
'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 204, 'LOAD_ATTR_MODULE': 204,
'LOAD_ATTR_PROPERTY': 205, 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 205,
'LOAD_ATTR_SLOT': 206, 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 206,
'LOAD_ATTR_WITH_HINT': 207, 'LOAD_ATTR_PROPERTY': 207,
'LOAD_CONST_IMMORTAL': 208, 'LOAD_ATTR_SLOT': 208,
'LOAD_CONST_MORTAL': 209, 'LOAD_ATTR_WITH_HINT': 209,
'LOAD_GLOBAL_BUILTIN': 210, 'LOAD_CONST_IMMORTAL': 210,
'LOAD_GLOBAL_MODULE': 211, 'LOAD_CONST_MORTAL': 211,
'LOAD_SUPER_ATTR_ATTR': 212, 'LOAD_GLOBAL_BUILTIN': 212,
'LOAD_SUPER_ATTR_METHOD': 213, 'LOAD_GLOBAL_MODULE': 213,
'RESUME_CHECK': 214, 'LOAD_SUPER_ATTR_ATTR': 214,
'SEND_GEN': 215, 'LOAD_SUPER_ATTR_METHOD': 215,
'STORE_ATTR_INSTANCE_VALUE': 216, 'RESUME_CHECK': 216,
'STORE_ATTR_SLOT': 217, 'SEND_GEN': 217,
'STORE_ATTR_WITH_HINT': 218, 'STORE_ATTR_INSTANCE_VALUE': 218,
'STORE_SUBSCR_DICT': 219, 'STORE_ATTR_SLOT': 219,
'STORE_SUBSCR_LIST_INT': 220, 'STORE_ATTR_WITH_HINT': 220,
'TO_BOOL_ALWAYS_TRUE': 221, 'STORE_SUBSCR_DICT': 221,
'TO_BOOL_BOOL': 222, 'STORE_SUBSCR_LIST_INT': 222,
'TO_BOOL_INT': 223, 'TO_BOOL_ALWAYS_TRUE': 223,
'TO_BOOL_LIST': 224, 'TO_BOOL_BOOL': 224,
'TO_BOOL_NONE': 225, 'TO_BOOL_INT': 225,
'TO_BOOL_STR': 226, 'TO_BOOL_LIST': 226,
'UNPACK_SEQUENCE_LIST': 227, 'TO_BOOL_NONE': 227,
'UNPACK_SEQUENCE_TUPLE': 228, 'TO_BOOL_STR': 228,
'UNPACK_SEQUENCE_TWO_TUPLE': 229, 'UNPACK_SEQUENCE_LIST': 229,
'UNPACK_SEQUENCE_TUPLE': 230,
'UNPACK_SEQUENCE_TWO_TUPLE': 231,
} }
opmap = { opmap = {

View file

@ -58,7 +58,8 @@ __all__ = [
"LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT", "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT",
"Py_DEBUG", "exceeds_recursion_limit", "get_c_recursion_limit", "Py_DEBUG", "exceeds_recursion_limit", "get_c_recursion_limit",
"skip_on_s390x", "skip_on_s390x",
"without_optimizer", "requires_jit_enabled",
"requires_jit_disabled",
"force_not_colorized", "force_not_colorized",
"force_not_colorized_test_class", "force_not_colorized_test_class",
"make_clean_env", "make_clean_env",
@ -2620,21 +2621,13 @@ skip_on_s390x = unittest.skipIf(is_s390x, 'skipped on s390x')
Py_TRACE_REFS = hasattr(sys, 'getobjects') Py_TRACE_REFS = hasattr(sys, 'getobjects')
# Decorator to disable optimizer while a function run try:
def without_optimizer(func): from _testinternalcapi import jit_enabled
try: except ImportError:
from _testinternalcapi import get_optimizer, set_optimizer requires_jit_enabled = requires_jit_disabled = unittest.skip("requires _testinternalcapi")
except ImportError: else:
return func requires_jit_enabled = unittest.skipUnless(jit_enabled(), "requires JIT enabled")
@functools.wraps(func) requires_jit_disabled = unittest.skipIf(jit_enabled(), "requires JIT disabled")
def wrapper(*args, **kwargs):
save_opt = get_optimizer()
try:
set_optimizer(None)
return func(*args, **kwargs)
finally:
set_optimizer(save_opt)
return wrapper
_BASE_COPY_SRC_DIR_IGNORED_NAMES = frozenset({ _BASE_COPY_SRC_DIR_IGNORED_NAMES = frozenset({

View file

@ -306,7 +306,7 @@ class CAPITest(unittest.TestCase):
CURRENT_THREAD_REGEX + CURRENT_THREAD_REGEX +
r' File .*, line 6 in <module>\n' r' File .*, line 6 in <module>\n'
r'\n' r'\n'
r'Extension modules: _testcapi \(total: 1\)\n') r'Extension modules: _testcapi, _testinternalcapi \(total: 2\)\n')
else: else:
# Python built with NDEBUG macro defined: # Python built with NDEBUG macro defined:
# test _Py_CheckFunctionResult() instead. # test _Py_CheckFunctionResult() instead.

View file

@ -9,21 +9,12 @@ import os
import _opcode import _opcode
from test.support import (script_helper, requires_specialization, from test.support import (script_helper, requires_specialization,
import_helper, Py_GIL_DISABLED) import_helper, Py_GIL_DISABLED, requires_jit_enabled)
_testinternalcapi = import_helper.import_module("_testinternalcapi") _testinternalcapi = import_helper.import_module("_testinternalcapi")
from _testinternalcapi import TIER2_THRESHOLD from _testinternalcapi import TIER2_THRESHOLD
@contextlib.contextmanager
def temporary_optimizer(opt):
old_opt = _testinternalcapi.get_optimizer()
_testinternalcapi.set_optimizer(opt)
try:
yield
finally:
_testinternalcapi.set_optimizer(old_opt)
@contextlib.contextmanager @contextlib.contextmanager
def clear_executors(func): def clear_executors(func):
@ -57,8 +48,7 @@ def get_opnames(ex):
@requires_specialization @requires_specialization
@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds")
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), @requires_jit_enabled
"Requires optimizer infrastructure")
class TestExecutorInvalidation(unittest.TestCase): class TestExecutorInvalidation(unittest.TestCase):
def test_invalidate_object(self): def test_invalidate_object(self):
@ -75,8 +65,6 @@ class TestExecutorInvalidation(unittest.TestCase):
funcs = [ ns[f'f{n}'] for n in range(5)] funcs = [ ns[f'f{n}'] for n in range(5)]
objects = [object() for _ in range(5)] objects = [object() for _ in range(5)]
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
for f in funcs: for f in funcs:
f() f()
executors = [get_first_executor(f) for f in funcs] executors = [get_first_executor(f) for f in funcs]
@ -106,8 +94,6 @@ class TestExecutorInvalidation(unittest.TestCase):
pass pass
"""), ns, ns) """), ns, ns)
f = ns['f'] f = ns['f']
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
f() f()
exe = get_first_executor(f) exe = get_first_executor(f)
self.assertIsNotNone(exe) self.assertIsNotNone(exe)
@ -119,8 +105,6 @@ class TestExecutorInvalidation(unittest.TestCase):
def f(): def f():
for _ in range(TIER2_THRESHOLD): for _ in range(TIER2_THRESHOLD):
pass pass
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
f() f()
exe = get_first_executor(f) exe = get_first_executor(f)
self.assertIsNotNone(exe) self.assertIsNotNone(exe)
@ -133,8 +117,7 @@ class TestExecutorInvalidation(unittest.TestCase):
@requires_specialization @requires_specialization
@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds")
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), @requires_jit_enabled
"Requires optimizer infrastructure")
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
class TestUops(unittest.TestCase): class TestUops(unittest.TestCase):
@ -144,8 +127,6 @@ class TestUops(unittest.TestCase):
while i < x: while i < x:
i += 1 i += 1
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -192,8 +173,6 @@ class TestUops(unittest.TestCase):
"""), ns, ns) """), ns, ns)
many_vars = ns["many_vars"] many_vars = ns["many_vars"]
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
ex = get_first_executor(many_vars) ex = get_first_executor(many_vars)
self.assertIsNone(ex) self.assertIsNone(ex)
many_vars() many_vars()
@ -215,9 +194,6 @@ class TestUops(unittest.TestCase):
while i < x: while i < x:
i += 1 i += 1
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -231,8 +207,6 @@ class TestUops(unittest.TestCase):
while i < n: while i < n:
i += 1 i += 1
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -246,8 +220,6 @@ class TestUops(unittest.TestCase):
if x is None: if x is None:
x = 0 x = 0
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(range(TIER2_THRESHOLD)) testfunc(range(TIER2_THRESHOLD))
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -263,8 +235,6 @@ class TestUops(unittest.TestCase):
if x is not None: if x is not None:
x = 0 x = 0
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(range(TIER2_THRESHOLD)) testfunc(range(TIER2_THRESHOLD))
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -279,8 +249,6 @@ class TestUops(unittest.TestCase):
while not i >= n: while not i >= n:
i += 1 i += 1
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -294,8 +262,6 @@ class TestUops(unittest.TestCase):
while i < n: while i < n:
i += 1 i += 1
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -314,8 +280,6 @@ class TestUops(unittest.TestCase):
a += 1 a += 1
return a return a
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -332,8 +296,6 @@ class TestUops(unittest.TestCase):
total += i total += i
return total return total
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
total = testfunc(TIER2_THRESHOLD) total = testfunc(TIER2_THRESHOLD)
self.assertEqual(total, sum(range(TIER2_THRESHOLD))) self.assertEqual(total, sum(range(TIER2_THRESHOLD)))
@ -353,8 +315,6 @@ class TestUops(unittest.TestCase):
total += i total += i
return total return total
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
a = list(range(TIER2_THRESHOLD)) a = list(range(TIER2_THRESHOLD))
total = testfunc(a) total = testfunc(a)
self.assertEqual(total, sum(a)) self.assertEqual(total, sum(a))
@ -375,8 +335,6 @@ class TestUops(unittest.TestCase):
total += i total += i
return total return total
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
a = tuple(range(TIER2_THRESHOLD)) a = tuple(range(TIER2_THRESHOLD))
total = testfunc(a) total = testfunc(a)
self.assertEqual(total, sum(a)) self.assertEqual(total, sum(a))
@ -395,8 +353,6 @@ class TestUops(unittest.TestCase):
for x in it: for x in it:
pass pass
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
a = [1, 2, 3] a = [1, 2, 3]
it = iter(a) it = iter(a)
testfunc(it) testfunc(it)
@ -411,8 +367,6 @@ class TestUops(unittest.TestCase):
for i in range(n): for i in range(n):
dummy(i) dummy(i)
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -429,8 +383,6 @@ class TestUops(unittest.TestCase):
else: else:
i = 1 i = 1
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -457,8 +409,6 @@ class TestUops(unittest.TestCase):
x += 1000*i + j x += 1000*i + j
return x return x
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
x = testfunc(TIER2_THRESHOLD, TIER2_THRESHOLD) x = testfunc(TIER2_THRESHOLD, TIER2_THRESHOLD)
self.assertEqual(x, sum(range(TIER2_THRESHOLD)) * TIER2_THRESHOLD * 1001) self.assertEqual(x, sum(range(TIER2_THRESHOLD)) * TIER2_THRESHOLD * 1001)
@ -484,8 +434,6 @@ class TestUops(unittest.TestCase):
bits += 1 bits += 1
return bits return bits
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
x = testfunc(TIER2_THRESHOLD * 2) x = testfunc(TIER2_THRESHOLD * 2)
self.assertEqual(x, TIER2_THRESHOLD * 5) self.assertEqual(x, TIER2_THRESHOLD * 5)
@ -499,15 +447,11 @@ class TestUops(unittest.TestCase):
@requires_specialization @requires_specialization
@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds")
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), @requires_jit_enabled
"Requires optimizer infrastructure")
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
class TestUopsOptimization(unittest.TestCase): class TestUopsOptimization(unittest.TestCase):
def _run_with_optimizer(self, testfunc, arg): def _run_with_optimizer(self, testfunc, arg):
res = None
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
res = testfunc(arg) res = testfunc(arg)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -542,9 +486,6 @@ class TestUopsOptimization(unittest.TestCase):
num += 1 num += 1
return a return a
opt = _testinternalcapi.new_uop_optimizer()
res = None
with temporary_optimizer(opt):
res = testfunc(TIER2_THRESHOLD) res = testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -566,9 +507,6 @@ class TestUopsOptimization(unittest.TestCase):
num += 1 num += 1
return x return x
opt = _testinternalcapi.new_uop_optimizer()
res = None
with temporary_optimizer(opt):
res = testfunc(TIER2_THRESHOLD) res = testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -661,10 +599,8 @@ class TestUopsOptimization(unittest.TestCase):
for i in range(n): for i in range(n):
dummy(i) dummy(i)
opt = _testinternalcapi.new_uop_optimizer()
# Trigger specialization # Trigger specialization
testfunc(8) testfunc(8)
with temporary_optimizer(opt):
del dummy del dummy
gc.collect() gc.collect()
@ -703,8 +639,6 @@ class TestUopsOptimization(unittest.TestCase):
x = range(i) x = range(i)
return x return x
opt = _testinternalcapi.new_uop_optimizer()
_testinternalcapi.set_optimizer(opt)
testfunc(_testinternalcapi.TIER2_THRESHOLD) testfunc(_testinternalcapi.TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -712,7 +646,7 @@ class TestUopsOptimization(unittest.TestCase):
uops = get_opnames(ex) uops = get_opnames(ex)
assert "_LOAD_GLOBAL_BUILTINS" not in uops assert "_LOAD_GLOBAL_BUILTINS" not in uops
assert "_LOAD_CONST_INLINE_BORROW" in uops assert "_LOAD_CONST_INLINE_BORROW" in uops
""")) """), PYTHON_JIT="1")
self.assertEqual(result[0].rc, 0, result) self.assertEqual(result[0].rc, 0, result)
def test_float_add_constant_propagation(self): def test_float_add_constant_propagation(self):
@ -1399,8 +1333,6 @@ class TestUopsOptimization(unittest.TestCase):
# Only works on functions promoted to constants # Only works on functions promoted to constants
global_identity(i) global_identity(i)
opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
testfunc(TIER2_THRESHOLD) testfunc(TIER2_THRESHOLD)
ex = get_first_executor(testfunc) ex = get_first_executor(testfunc)
@ -1488,12 +1420,12 @@ class TestUopsOptimization(unittest.TestCase):
class Convert9999ToNone: class Convert9999ToNone:
def __del__(self): def __del__(self):
ns = sys._getframe(1).f_locals ns = sys._getframe(1).f_locals
if ns["i"] == 9999: if ns["i"] == _testinternalcapi.TIER2_THRESHOLD:
ns["i"] = None ns["i"] = None
def crash_addition(): def crash_addition():
try: try:
for i in range(10000): for i in range(_testinternalcapi.TIER2_THRESHOLD + 1):
n = Convert9999ToNone() n = Convert9999ToNone()
i + i # Remove guards for i. i + i # Remove guards for i.
n = None # Change i. n = None # Change i.

View file

@ -15,7 +15,7 @@ import types
import unittest import unittest
from test.support import (captured_stdout, requires_debug_ranges, from test.support import (captured_stdout, requires_debug_ranges,
requires_specialization, cpython_only, requires_specialization, cpython_only,
os_helper) os_helper, import_helper)
from test.support.bytecode_helper import BytecodeTestCase from test.support.bytecode_helper import BytecodeTestCase
@ -904,7 +904,7 @@ dis_loop_test_quickened_code = """\
LOAD_FAST 0 (i) LOAD_FAST 0 (i)
CALL_PY_GENERAL 1 CALL_PY_GENERAL 1
POP_TOP POP_TOP
JUMP_BACKWARD 16 (to L1) JUMP_BACKWARD_{: <6} 16 (to L1)
%3d L2: END_FOR %3d L2: END_FOR
POP_ITER POP_ITER
@ -1308,7 +1308,8 @@ class DisTests(DisTestBase):
# Loop can trigger a quicken where the loop is located # Loop can trigger a quicken where the loop is located
self.code_quicken(loop_test, 4) self.code_quicken(loop_test, 4)
got = self.get_disassembly(loop_test, adaptive=True) got = self.get_disassembly(loop_test, adaptive=True)
expected = dis_loop_test_quickened_code jit = import_helper.import_module("_testinternalcapi").jit_enabled()
expected = dis_loop_test_quickened_code.format("JIT" if jit else "NO_JIT")
self.do_disassembly_compare(got, expected) self.do_disassembly_compare(got, expected)
@cpython_only @cpython_only

View file

@ -6,7 +6,7 @@ import types
import unittest import unittest
from test.support import (threading_helper, check_impl_detail, from test.support import (threading_helper, check_impl_detail,
requires_specialization, requires_specialization_ft, requires_specialization, requires_specialization_ft,
cpython_only) cpython_only, requires_jit_disabled)
from test.support.import_helper import import_module from test.support.import_helper import import_module
# Skip this module on other interpreters, it is cpython specific: # Skip this module on other interpreters, it is cpython specific:
@ -16,20 +16,6 @@ if check_impl_detail(cpython=False):
_testinternalcapi = import_module("_testinternalcapi") _testinternalcapi = import_module("_testinternalcapi")
def disabling_optimizer(func):
def wrapper(*args, **kwargs):
if not hasattr(_testinternalcapi, "get_optimizer"):
return func(*args, **kwargs)
old_opt = _testinternalcapi.get_optimizer()
_testinternalcapi.set_optimizer(None)
try:
return func(*args, **kwargs)
finally:
_testinternalcapi.set_optimizer(old_opt)
return wrapper
class TestBase(unittest.TestCase): class TestBase(unittest.TestCase):
def assert_specialized(self, f, opname): def assert_specialized(self, f, opname):
instructions = dis.get_instructions(f, adaptive=True) instructions = dis.get_instructions(f, adaptive=True)
@ -526,7 +512,7 @@ class TestCallCache(TestBase):
f(None) f(None)
f() f()
@disabling_optimizer @requires_jit_disabled
@requires_specialization_ft @requires_specialization_ft
def test_assign_init_code(self): def test_assign_init_code(self):
class MyClass: class MyClass:
@ -549,7 +535,7 @@ class TestCallCache(TestBase):
MyClass.__init__.__code__ = count_args.__code__ MyClass.__init__.__code__ = count_args.__code__
instantiate() instantiate()
@disabling_optimizer @requires_jit_disabled
@requires_specialization_ft @requires_specialization_ft
def test_push_init_frame_fails(self): def test_push_init_frame_fails(self):
def instantiate(): def instantiate():
@ -583,7 +569,7 @@ class TestRacesDoNotCrash(TestBase):
WARMUPS = 2 WARMUPS = 2
WRITERS = 2 WRITERS = 2
@disabling_optimizer @requires_jit_disabled
def assert_races_do_not_crash( def assert_races_do_not_crash(
self, opname, get_items, read, write, *, check_items=False self, opname, get_items, read, write, *, check_items=False
): ):

View file

@ -1185,7 +1185,7 @@ class ArgsTestCase(BaseTestCase):
stats=TestStats(4, 1), stats=TestStats(4, 1),
forever=True) forever=True)
@support.without_optimizer @support.requires_jit_disabled
def check_leak(self, code, what, *, run_workers=False): def check_leak(self, code, what, *, run_workers=False):
test = self.create_test('huntrleaks', code=code) test = self.create_test('huntrleaks', code=code)

View file

@ -950,39 +950,14 @@ get_co_framesize(PyObject *self, PyObject *arg)
return PyLong_FromLong(code->co_framesize); return PyLong_FromLong(code->co_framesize);
} }
static PyObject *
jit_enabled(PyObject *self, PyObject *arg)
{
return PyBool_FromLong(_PyInterpreterState_GET()->jit);
}
#ifdef _Py_TIER2 #ifdef _Py_TIER2
static PyObject *
new_uop_optimizer(PyObject *self, PyObject *arg)
{
return _PyOptimizer_NewUOpOptimizer();
}
static PyObject *
set_optimizer(PyObject *self, PyObject *opt)
{
if (opt == Py_None) {
opt = NULL;
}
if (_Py_SetTier2Optimizer((_PyOptimizerObject*)opt) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored))
{
PyObject *opt = NULL;
#ifdef _Py_TIER2
opt = (PyObject *)_Py_GetOptimizer();
#endif
if (opt == NULL) {
Py_RETURN_NONE;
}
return opt;
}
static PyObject * static PyObject *
add_executor_dependency(PyObject *self, PyObject *args) add_executor_dependency(PyObject *self, PyObject *args)
{ {
@ -2047,10 +2022,8 @@ static PyMethodDef module_functions[] = {
{"iframe_getline", iframe_getline, METH_O, NULL}, {"iframe_getline", iframe_getline, METH_O, NULL},
{"iframe_getlasti", iframe_getlasti, METH_O, NULL}, {"iframe_getlasti", iframe_getlasti, METH_O, NULL},
{"get_co_framesize", get_co_framesize, METH_O, NULL}, {"get_co_framesize", get_co_framesize, METH_O, NULL},
{"jit_enabled", jit_enabled, METH_NOARGS, NULL},
#ifdef _Py_TIER2 #ifdef _Py_TIER2
{"get_optimizer", get_optimizer, METH_NOARGS, NULL},
{"set_optimizer", set_optimizer, METH_O, NULL},
{"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL},
{"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL},
{"invalidate_executors", invalidate_executors, METH_O, NULL}, {"invalidate_executors", invalidate_executors, METH_O, NULL},
#endif #endif

View file

@ -19,7 +19,7 @@
#include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition #include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition
#include "pycore_object_state.h" // struct _reftracer_runtime_state #include "pycore_object_state.h" // struct _reftracer_runtime_state
#include "pycore_long.h" // _PyLong_GetZero() #include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_optimizer.h" // _PyUOpExecutor_Type, _PyUOpOptimizer_Type, ... #include "pycore_optimizer.h" // _PyUOpExecutor_Type, ...
#include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pymem.h" // _PyMem_IsPtrFreed()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
@ -2379,9 +2379,6 @@ static PyTypeObject* static_types[] = {
&_PyBufferWrapper_Type, &_PyBufferWrapper_Type,
&_PyContextTokenMissing_Type, &_PyContextTokenMissing_Type,
&_PyCoroWrapper_Type, &_PyCoroWrapper_Type,
#ifdef _Py_TIER2
&_PyDefaultOptimizer_Type,
#endif
&_Py_GenericAliasIterType, &_Py_GenericAliasIterType,
&_PyHamtItems_Type, &_PyHamtItems_Type,
&_PyHamtKeys_Type, &_PyHamtKeys_Type,
@ -2404,7 +2401,6 @@ static PyTypeObject* static_types[] = {
&_PyUnion_Type, &_PyUnion_Type,
#ifdef _Py_TIER2 #ifdef _Py_TIER2
&_PyUOpExecutor_Type, &_PyUOpExecutor_Type,
&_PyUOpOptimizer_Type,
#endif #endif
&_PyWeakref_CallableProxyType, &_PyWeakref_CallableProxyType,
&_PyWeakref_ProxyType, &_PyWeakref_ProxyType,

View file

@ -2782,13 +2782,26 @@ dummy_func(
JUMPBY(oparg); JUMPBY(oparg);
} }
tier1 op(_JUMP_BACKWARD, (the_counter/1 --)) { family(JUMP_BACKWARD, 1) = {
assert(oparg <= INSTR_OFFSET()); JUMP_BACKWARD_NO_JIT,
JUMPBY(-oparg); JUMP_BACKWARD_JIT,
#ifdef _Py_TIER2 };
tier1 op(_SPECIALIZE_JUMP_BACKWARD, (--)) {
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION
if (this_instr->op.code == JUMP_BACKWARD) {
this_instr->op.code = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT;
// Need to re-dispatch so the warmup counter isn't off by one:
next_instr = this_instr;
DISPATCH_SAME_OPARG();
}
#endif
}
tier1 op(_JIT, (--)) {
#ifdef _Py_TIER2
_Py_BackoffCounter counter = this_instr[1].counter; _Py_BackoffCounter counter = this_instr[1].counter;
if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD_JIT) {
_Py_CODEUNIT *start = this_instr; _Py_CODEUNIT *start = this_instr;
/* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */
while (oparg > 255) { while (oparg > 255) {
@ -2811,13 +2824,25 @@ dummy_func(
else { else {
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
} }
#endif /* ENABLE_SPECIALIZATION */ #endif
#endif /* _Py_TIER2 */
} }
macro(JUMP_BACKWARD) = macro(JUMP_BACKWARD) =
unused/1 +
_SPECIALIZE_JUMP_BACKWARD +
_CHECK_PERIODIC + _CHECK_PERIODIC +
_JUMP_BACKWARD; JUMP_BACKWARD_NO_INTERRUPT;
macro(JUMP_BACKWARD_NO_JIT) =
unused/1 +
_CHECK_PERIODIC +
JUMP_BACKWARD_NO_INTERRUPT;
macro(JUMP_BACKWARD_JIT) =
unused/1 +
_CHECK_PERIODIC +
JUMP_BACKWARD_NO_INTERRUPT +
_JIT;
pseudo(JUMP, (--)) = { pseudo(JUMP, (--)) = {
JUMP_FORWARD, JUMP_FORWARD,
@ -2906,6 +2931,7 @@ dummy_func(
* generator or coroutine, so we deliberately do not check it here. * generator or coroutine, so we deliberately do not check it here.
* (see bpo-30039). * (see bpo-30039).
*/ */
assert(oparg <= INSTR_OFFSET());
JUMPBY(-oparg); JUMPBY(-oparg);
} }

View file

@ -180,6 +180,7 @@
TARGET(BINARY_OP_EXTEND) { TARGET(BINARY_OP_EXTEND) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 6; next_instr += 6;
INSTRUCTION_STATS(BINARY_OP_EXTEND); INSTRUCTION_STATS(BINARY_OP_EXTEND);
static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size");
@ -1087,6 +1088,7 @@
TARGET(CALL_ALLOC_AND_ENTER_INIT) { TARGET(CALL_ALLOC_AND_ENTER_INIT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 4; next_instr += 4;
INSTRUCTION_STATS(CALL_ALLOC_AND_ENTER_INIT); INSTRUCTION_STATS(CALL_ALLOC_AND_ENTER_INIT);
static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size");
@ -1185,6 +1187,7 @@
TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { TARGET(CALL_BOUND_METHOD_EXACT_ARGS) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 4; next_instr += 4;
INSTRUCTION_STATS(CALL_BOUND_METHOD_EXACT_ARGS); INSTRUCTION_STATS(CALL_BOUND_METHOD_EXACT_ARGS);
static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size");
@ -1288,6 +1291,7 @@
TARGET(CALL_BOUND_METHOD_GENERAL) { TARGET(CALL_BOUND_METHOD_GENERAL) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 4; next_instr += 4;
INSTRUCTION_STATS(CALL_BOUND_METHOD_GENERAL); INSTRUCTION_STATS(CALL_BOUND_METHOD_GENERAL);
static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size");
@ -2113,6 +2117,7 @@
TARGET(CALL_KW_BOUND_METHOD) { TARGET(CALL_KW_BOUND_METHOD) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 4; next_instr += 4;
INSTRUCTION_STATS(CALL_KW_BOUND_METHOD); INSTRUCTION_STATS(CALL_KW_BOUND_METHOD);
static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size");
@ -2313,6 +2318,7 @@
TARGET(CALL_KW_PY) { TARGET(CALL_KW_PY) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 4; next_instr += 4;
INSTRUCTION_STATS(CALL_KW_PY); INSTRUCTION_STATS(CALL_KW_PY);
static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size");
@ -2890,6 +2896,7 @@
TARGET(CALL_PY_EXACT_ARGS) { TARGET(CALL_PY_EXACT_ARGS) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 4; next_instr += 4;
INSTRUCTION_STATS(CALL_PY_EXACT_ARGS); INSTRUCTION_STATS(CALL_PY_EXACT_ARGS);
static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size");
@ -2971,6 +2978,7 @@
TARGET(CALL_PY_GENERAL) { TARGET(CALL_PY_GENERAL) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 4; next_instr += 4;
INSTRUCTION_STATS(CALL_PY_GENERAL); INSTRUCTION_STATS(CALL_PY_GENERAL);
static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size");
@ -5160,10 +5168,24 @@
} }
TARGET(JUMP_BACKWARD) { TARGET(JUMP_BACKWARD) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 2; next_instr += 2;
INSTRUCTION_STATS(JUMP_BACKWARD); INSTRUCTION_STATS(JUMP_BACKWARD);
PREDICTED_JUMP_BACKWARD:;
_Py_CODEUNIT* const this_instr = next_instr - 2;
(void)this_instr;
/* Skip 1 cache entry */
// _SPECIALIZE_JUMP_BACKWARD
{
#if ENABLE_SPECIALIZATION
if (this_instr->op.code == JUMP_BACKWARD) {
this_instr->op.code = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT;
// Need to re-dispatch so the warmup counter isn't off by one:
next_instr = this_instr;
DISPATCH_SAME_OPARG();
}
#endif
}
// _CHECK_PERIODIC // _CHECK_PERIODIC
{ {
_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY();
@ -5175,16 +5197,52 @@
if (err != 0) goto error; if (err != 0) goto error;
} }
} }
// _JUMP_BACKWARD // _JUMP_BACKWARD_NO_INTERRUPT
{ {
uint16_t the_counter = read_u16(&this_instr[1].cache); /* This bytecode is used in the `yield from` or `await` loop.
(void)the_counter; * If there is an interrupt, we want it handled in the innermost
* generator or coroutine, so we deliberately do not check it here.
* (see bpo-30039).
*/
assert(oparg <= INSTR_OFFSET()); assert(oparg <= INSTR_OFFSET());
JUMPBY(-oparg); JUMPBY(-oparg);
}
DISPATCH();
}
TARGET(JUMP_BACKWARD_JIT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 2;
INSTRUCTION_STATS(JUMP_BACKWARD_JIT);
static_assert(1 == 1, "incorrect cache size");
/* Skip 1 cache entry */
// _CHECK_PERIODIC
{
_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY();
QSBR_QUIESCENT_STATE(tstate);
if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _Py_HandlePending(tstate);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err != 0) goto error;
}
}
// _JUMP_BACKWARD_NO_INTERRUPT
{
/* This bytecode is used in the `yield from` or `await` loop.
* If there is an interrupt, we want it handled in the innermost
* generator or coroutine, so we deliberately do not check it here.
* (see bpo-30039).
*/
assert(oparg <= INSTR_OFFSET());
JUMPBY(-oparg);
}
// _JIT
{
#ifdef _Py_TIER2 #ifdef _Py_TIER2
#if ENABLE_SPECIALIZATION
_Py_BackoffCounter counter = this_instr[1].counter; _Py_BackoffCounter counter = this_instr[1].counter;
if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD_JIT) {
_Py_CODEUNIT *start = this_instr; _Py_CODEUNIT *start = this_instr;
/* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */
while (oparg > 255) { while (oparg > 255) {
@ -5211,8 +5269,7 @@
else { else {
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
} }
#endif /* ENABLE_SPECIALIZATION */ #endif
#endif /* _Py_TIER2 */
} }
DISPATCH(); DISPATCH();
} }
@ -5226,10 +5283,41 @@
* generator or coroutine, so we deliberately do not check it here. * generator or coroutine, so we deliberately do not check it here.
* (see bpo-30039). * (see bpo-30039).
*/ */
assert(oparg <= INSTR_OFFSET());
JUMPBY(-oparg); JUMPBY(-oparg);
DISPATCH(); DISPATCH();
} }
TARGET(JUMP_BACKWARD_NO_JIT) {
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(JUMP_BACKWARD_NO_JIT);
static_assert(1 == 1, "incorrect cache size");
/* Skip 1 cache entry */
// _CHECK_PERIODIC
{
_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY();
QSBR_QUIESCENT_STATE(tstate);
if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _Py_HandlePending(tstate);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err != 0) goto error;
}
}
// _JUMP_BACKWARD_NO_INTERRUPT
{
/* This bytecode is used in the `yield from` or `await` loop.
* If there is an interrupt, we want it handled in the innermost
* generator or coroutine, so we deliberately do not check it here.
* (see bpo-30039).
*/
assert(oparg <= INSTR_OFFSET());
JUMPBY(-oparg);
}
DISPATCH();
}
TARGET(JUMP_FORWARD) { TARGET(JUMP_FORWARD) {
frame->instr_ptr = next_instr; frame->instr_ptr = next_instr;
next_instr += 1; next_instr += 1;
@ -5369,6 +5457,7 @@
TARGET(LOAD_ATTR_CLASS) { TARGET(LOAD_ATTR_CLASS) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_CLASS); INSTRUCTION_STATS(LOAD_ATTR_CLASS);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5407,6 +5496,7 @@
TARGET(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) { TARGET(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK); INSTRUCTION_STATS(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5451,6 +5541,7 @@
TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); INSTRUCTION_STATS(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5487,6 +5578,7 @@
TARGET(LOAD_ATTR_INSTANCE_VALUE) { TARGET(LOAD_ATTR_INSTANCE_VALUE) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_INSTANCE_VALUE); INSTRUCTION_STATS(LOAD_ATTR_INSTANCE_VALUE);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5540,6 +5632,7 @@
TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { TARGET(LOAD_ATTR_METHOD_LAZY_DICT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_METHOD_LAZY_DICT); INSTRUCTION_STATS(LOAD_ATTR_METHOD_LAZY_DICT);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5583,6 +5676,7 @@
TARGET(LOAD_ATTR_METHOD_NO_DICT) { TARGET(LOAD_ATTR_METHOD_NO_DICT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_METHOD_NO_DICT); INSTRUCTION_STATS(LOAD_ATTR_METHOD_NO_DICT);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5619,6 +5713,7 @@
TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { TARGET(LOAD_ATTR_METHOD_WITH_VALUES) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_METHOD_WITH_VALUES); INSTRUCTION_STATS(LOAD_ATTR_METHOD_WITH_VALUES);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5669,6 +5764,7 @@
TARGET(LOAD_ATTR_MODULE) { TARGET(LOAD_ATTR_MODULE) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_MODULE); INSTRUCTION_STATS(LOAD_ATTR_MODULE);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5724,6 +5820,7 @@
TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) { TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_NO_DICT); INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_NO_DICT);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5755,6 +5852,7 @@
TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) { TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES); INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5799,6 +5897,7 @@
TARGET(LOAD_ATTR_PROPERTY) { TARGET(LOAD_ATTR_PROPERTY) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_PROPERTY); INSTRUCTION_STATS(LOAD_ATTR_PROPERTY);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5864,6 +5963,7 @@
TARGET(LOAD_ATTR_SLOT) { TARGET(LOAD_ATTR_SLOT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_SLOT); INSTRUCTION_STATS(LOAD_ATTR_SLOT);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -5909,6 +6009,7 @@
TARGET(LOAD_ATTR_WITH_HINT) { TARGET(LOAD_ATTR_WITH_HINT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 10; next_instr += 10;
INSTRUCTION_STATS(LOAD_ATTR_WITH_HINT); INSTRUCTION_STATS(LOAD_ATTR_WITH_HINT);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
@ -6326,6 +6427,7 @@
TARGET(LOAD_GLOBAL_BUILTIN) { TARGET(LOAD_GLOBAL_BUILTIN) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 5; next_instr += 5;
INSTRUCTION_STATS(LOAD_GLOBAL_BUILTIN); INSTRUCTION_STATS(LOAD_GLOBAL_BUILTIN);
static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size");
@ -6380,6 +6482,7 @@
TARGET(LOAD_GLOBAL_MODULE) { TARGET(LOAD_GLOBAL_MODULE) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 5; next_instr += 5;
INSTRUCTION_STATS(LOAD_GLOBAL_MODULE); INSTRUCTION_STATS(LOAD_GLOBAL_MODULE);
static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size");
@ -7557,6 +7660,7 @@
TARGET(STORE_ATTR_INSTANCE_VALUE) { TARGET(STORE_ATTR_INSTANCE_VALUE) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 5; next_instr += 5;
INSTRUCTION_STATS(STORE_ATTR_INSTANCE_VALUE); INSTRUCTION_STATS(STORE_ATTR_INSTANCE_VALUE);
static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size");
@ -7615,6 +7719,7 @@
TARGET(STORE_ATTR_SLOT) { TARGET(STORE_ATTR_SLOT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 5; next_instr += 5;
INSTRUCTION_STATS(STORE_ATTR_SLOT); INSTRUCTION_STATS(STORE_ATTR_SLOT);
static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size");
@ -7652,6 +7757,7 @@
TARGET(STORE_ATTR_WITH_HINT) { TARGET(STORE_ATTR_WITH_HINT) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 5; next_instr += 5;
INSTRUCTION_STATS(STORE_ATTR_WITH_HINT); INSTRUCTION_STATS(STORE_ATTR_WITH_HINT);
static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size");
@ -8046,6 +8152,7 @@
TARGET(TO_BOOL_ALWAYS_TRUE) { TARGET(TO_BOOL_ALWAYS_TRUE) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
(void)this_instr;
next_instr += 4; next_instr += 4;
INSTRUCTION_STATS(TO_BOOL_ALWAYS_TRUE); INSTRUCTION_STATS(TO_BOOL_ALWAYS_TRUE);
static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size");

View file

@ -194,6 +194,8 @@ static void *opcode_targets[256] = {
&&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_LIST,
&&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_RANGE,
&&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_TUPLE,
&&TARGET_JUMP_BACKWARD_JIT,
&&TARGET_JUMP_BACKWARD_NO_JIT,
&&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_CLASS,
&&TARGET_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK, &&TARGET_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK,
&&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
@ -232,8 +234,6 @@ static void *opcode_targets[256] = {
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_END_FOR,
&&TARGET_INSTRUMENTED_POP_ITER, &&TARGET_INSTRUMENTED_POP_ITER,
&&TARGET_INSTRUMENTED_END_SEND, &&TARGET_INSTRUMENTED_END_SEND,

View file

@ -91,70 +91,13 @@ insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorO
instr->op.arg = index; instr->op.arg = index;
} }
static int
never_optimize(
_PyOptimizerObject* self,
_PyInterpreterFrame *frame,
_Py_CODEUNIT *instr,
_PyExecutorObject **exec,
int Py_UNUSED(stack_entries),
bool Py_UNUSED(progress_needed))
{
// This may be called if the optimizer is reset
return 0;
}
PyTypeObject _PyDefaultOptimizer_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
.tp_name = "noop_optimizer",
.tp_basicsize = sizeof(_PyOptimizerObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
};
static _PyOptimizerObject _PyOptimizer_Default = {
PyObject_HEAD_INIT(&_PyDefaultOptimizer_Type)
.optimize = never_optimize,
};
_PyOptimizerObject *
_Py_GetOptimizer(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
if (interp->optimizer == &_PyOptimizer_Default) {
return NULL;
}
Py_INCREF(interp->optimizer);
return interp->optimizer;
}
static _PyExecutorObject * static _PyExecutorObject *
make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies); make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies);
_PyOptimizerObject * static int
_Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject *optimizer) uop_optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *instr,
{ _PyExecutorObject **exec_ptr, int curr_stackentries,
if (optimizer == NULL) { bool progress_needed);
optimizer = &_PyOptimizer_Default;
}
_PyOptimizerObject *old = interp->optimizer;
if (old == NULL) {
old = &_PyOptimizer_Default;
}
Py_INCREF(optimizer);
interp->optimizer = optimizer;
return old;
}
int
_Py_SetTier2Optimizer(_PyOptimizerObject *optimizer)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
_PyOptimizerObject *old = _Py_SetOptimizer(interp, optimizer);
Py_XDECREF(old);
return old == NULL ? -1 : 0;
}
/* Returns 1 if optimized, 0 if not optimized, and -1 for an error. /* Returns 1 if optimized, 0 if not optimized, and -1 for an error.
* If optimized, *executor_ptr contains a new reference to the executor * If optimized, *executor_ptr contains a new reference to the executor
@ -164,6 +107,7 @@ _PyOptimizer_Optimize(
_PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyInterpreterFrame *frame, _Py_CODEUNIT *start,
_PyStackRef *stack_pointer, _PyExecutorObject **executor_ptr, int chain_depth) _PyStackRef *stack_pointer, _PyExecutorObject **executor_ptr, int chain_depth)
{ {
assert(_PyInterpreterState_GET()->jit);
// The first executor in a chain and the MAX_CHAIN_DEPTH'th executor *must* // The first executor in a chain and the MAX_CHAIN_DEPTH'th executor *must*
// make progress in order to avoid infinite loops or excessively-long // make progress in order to avoid infinite loops or excessively-long
// side-exit chains. We can only insert the executor into the bytecode if // side-exit chains. We can only insert the executor into the bytecode if
@ -172,12 +116,10 @@ _PyOptimizer_Optimize(
bool progress_needed = chain_depth == 0; bool progress_needed = chain_depth == 0;
PyCodeObject *code = _PyFrame_GetCode(frame); PyCodeObject *code = _PyFrame_GetCode(frame);
assert(PyCode_Check(code)); assert(PyCode_Check(code));
PyInterpreterState *interp = _PyInterpreterState_GET();
if (progress_needed && !has_space_for_executor(code, start)) { if (progress_needed && !has_space_for_executor(code, start)) {
return 0; return 0;
} }
_PyOptimizerObject *opt = interp->optimizer; int err = uop_optimize(frame, start, executor_ptr, (int)(stack_pointer - _PyFrame_Stackbase(frame)), progress_needed);
int err = opt->optimize(opt, frame, start, executor_ptr, (int)(stack_pointer - _PyFrame_Stackbase(frame)), progress_needed);
if (err <= 0) { if (err <= 0) {
return err; return err;
} }
@ -684,6 +626,7 @@ translate_bytecode_to_trace(
} }
case JUMP_BACKWARD: case JUMP_BACKWARD:
case JUMP_BACKWARD_JIT:
ADD_TO_TRACE(_CHECK_PERIODIC, 0, 0, target); ADD_TO_TRACE(_CHECK_PERIODIC, 0, 0, target);
_Py_FALLTHROUGH; _Py_FALLTHROUGH;
case JUMP_BACKWARD_NO_INTERRUPT: case JUMP_BACKWARD_NO_INTERRUPT:
@ -1241,7 +1184,6 @@ int effective_trace_length(_PyUOpInstruction *buffer, int length)
static int static int
uop_optimize( uop_optimize(
_PyOptimizerObject *self,
_PyInterpreterFrame *frame, _PyInterpreterFrame *frame,
_Py_CODEUNIT *instr, _Py_CODEUNIT *instr,
_PyExecutorObject **exec_ptr, _PyExecutorObject **exec_ptr,
@ -1299,31 +1241,6 @@ uop_optimize(
return 1; return 1;
} }
static void
uop_opt_dealloc(PyObject *self) {
PyObject_Free(self);
}
PyTypeObject _PyUOpOptimizer_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
.tp_name = "uop_optimizer",
.tp_basicsize = sizeof(_PyOptimizerObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
.tp_dealloc = uop_opt_dealloc,
};
PyObject *
_PyOptimizer_NewUOpOptimizer(void)
{
_PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type);
if (opt == NULL) {
return NULL;
}
opt->optimize = uop_optimize;
return (PyObject *)opt;
}
/***************************************** /*****************************************
* Executor management * Executor management

View file

@ -1306,14 +1306,7 @@ init_interp_main(PyThreadState *tstate)
} else } else
#endif #endif
{ {
PyObject *opt = _PyOptimizer_NewUOpOptimizer(); interp->jit = true;
if (opt == NULL) {
return _PyStatus_ERR("can't initialize optimizer");
}
if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) {
return _PyStatus_ERR("can't install optimizer");
}
Py_DECREF(opt);
} }
} }
} }
@ -1665,11 +1658,10 @@ finalize_modules(PyThreadState *tstate)
{ {
PyInterpreterState *interp = tstate->interp; PyInterpreterState *interp = tstate->interp;
// Invalidate all executors and turn off JIT:
interp->jit = false;
#ifdef _Py_TIER2 #ifdef _Py_TIER2
// Invalidate all executors and turn off tier 2 optimizer
_Py_Executors_InvalidateAll(interp, 0); _Py_Executors_InvalidateAll(interp, 0);
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
Py_XDECREF(old);
#endif #endif
// Stop watching __builtin__ modifications // Stop watching __builtin__ modifications

View file

@ -655,11 +655,9 @@ init_interpreter(PyInterpreterState *interp,
} }
interp->sys_profile_initialized = false; interp->sys_profile_initialized = false;
interp->sys_trace_initialized = false; interp->sys_trace_initialized = false;
#ifdef _Py_TIER2 interp->jit = false;
(void)_Py_SetOptimizer(interp, NULL);
interp->executor_list_head = NULL; interp->executor_list_head = NULL;
interp->trace_run_counter = JIT_CLEANUP_THRESHOLD; interp->trace_run_counter = JIT_CLEANUP_THRESHOLD;
#endif
if (interp != &runtime->_main_interpreter) { if (interp != &runtime->_main_interpreter) {
/* Fix the self-referential, statically initialized fields. */ /* Fix the self-referential, statically initialized fields. */
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
@ -829,12 +827,6 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
tstate->_status.cleared = 0; tstate->_status.cleared = 0;
} }
#ifdef _Py_TIER2
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
assert(old != NULL);
Py_DECREF(old);
#endif
/* It is possible that any of the objects below have a finalizer /* It is possible that any of the objects below have a finalizer
that runs Python code or otherwise relies on a thread state that runs Python code or otherwise relies on a thread state
or even the interpreter state. For now we trust that isn't or even the interpreter state. For now we trust that isn't

View file

@ -2265,9 +2265,7 @@ sys_activate_stack_trampoline_impl(PyObject *module, const char *backend)
{ {
#ifdef PY_HAVE_PERF_TRAMPOLINE #ifdef PY_HAVE_PERF_TRAMPOLINE
#ifdef _Py_JIT #ifdef _Py_JIT
_PyOptimizerObject* optimizer = _Py_GetOptimizer(); if (_PyInterpreterState_GET()->jit) {
if (optimizer != NULL) {
Py_DECREF(optimizer);
PyErr_SetString(PyExc_ValueError, "Cannot activate the perf trampoline if the JIT is active"); PyErr_SetString(PyExc_ValueError, "Cannot activate the perf trampoline if the JIT is active");
return NULL; return NULL;
} }

View file

@ -388,9 +388,7 @@ Python/sysmodule.c - perf_map_state -
Python/sysmodule.c - _PySys_ImplCacheTag - Python/sysmodule.c - _PySys_ImplCacheTag -
Python/sysmodule.c - _PySys_ImplName - Python/sysmodule.c - _PySys_ImplName -
Python/sysmodule.c - whatstrings - Python/sysmodule.c - whatstrings -
Python/optimizer.c - _PyDefaultOptimizer_Type -
Python/optimizer.c - _PyUOpExecutor_Type - Python/optimizer.c - _PyUOpExecutor_Type -
Python/optimizer.c - _PyUOpOptimizer_Type -
Python/optimizer.c - _PyOptimizer_Default - Python/optimizer.c - _PyOptimizer_Default -
Python/optimizer.c - _ColdExit_Type - Python/optimizer.c - _ColdExit_Type -
Python/optimizer.c - Py_FatalErrorExecutor - Python/optimizer.c - Py_FatalErrorExecutor -

Can't render this file because it has a wrong number of fields in line 4.

View file

@ -202,7 +202,7 @@ def generate_tier1_cases(
needs_this = uses_this(inst) needs_this = uses_this(inst)
out.emit("\n") out.emit("\n")
out.emit(f"TARGET({name}) {{\n") out.emit(f"TARGET({name}) {{\n")
unused_guard = "(void)this_instr;\n" if inst.family is None else "" unused_guard = "(void)this_instr;\n"
if inst.properties.needs_prev: if inst.properties.needs_prev:
out.emit(f"_Py_CODEUNIT* const prev_instr = frame->instr_ptr;\n") out.emit(f"_Py_CODEUNIT* const prev_instr = frame->instr_ptr;\n")
if needs_this and not inst.is_target: if needs_this and not inst.is_target: