diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index e4b5b6831fa0b2..c5ea78c1683761 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -210,12 +210,6 @@ Functions :exc:`ModuleNotFoundError` is raised when the module being reloaded lacks a :class:`~importlib.machinery.ModuleSpec`. - .. versionchanged:: 3.15 - If *module* is a lazy module that has not yet been materialized (i.e., - loaded via :class:`importlib.util.LazyLoader` and not yet accessed), - calling :func:`reload` is a no-op and returns the module unchanged. - This prevents the reload from unintentionally triggering the lazy load. - .. warning:: This function is not thread-safe. Calling it from multiple threads can result in unexpected behavior. It's recommended to use the :class:`threading.Lock` diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h index b08c8c52221f4b..a3badb59cb771a 100644 --- a/Include/internal/pycore_genobject.h +++ b/Include/internal/pycore_genobject.h @@ -22,7 +22,7 @@ PyGenObject *_PyGen_GetGeneratorFromFrame(_PyInterpreterFrame *frame) } PyAPI_FUNC(PyObject *)_PyGen_yf(PyGenObject *); -extern void _PyGen_Finalize(PyObject *self); +extern int _PyGen_ClearFrame(PyGenObject *self); // Export for '_asyncio' shared extension PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *); diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 6a0fc1a59e7965..d1d22c77507c6c 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -12,6 +12,7 @@ extern "C" { #include "pycore_uop.h" // _PyUOpInstruction #include "pycore_uop_ids.h" #include "pycore_stackref.h" // _PyStackRef +#include "pycore_optimizer_types.h" #include @@ -84,7 +85,7 @@ PyAPI_FUNC(void) _Py_Executors_InvalidateCold(PyInterpreterState *interp); #define JIT_CLEANUP_THRESHOLD 1000 int _Py_uop_analyze_and_optimize( - PyFunctionObject *func, + _PyThreadStateImpl *tstate, _PyUOpInstruction *trace, int trace_len, int curr_stackentries, _PyBloomFilter *dependencies); @@ -112,86 +113,6 @@ static inline uint16_t uop_get_error_target(const _PyUOpInstruction *inst) return inst->error_target; } -// Holds locals, stack, locals, stack ... co_consts (in that order) -#define MAX_ABSTRACT_INTERP_SIZE 4096 - -#define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5) - -// Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH()) -#define MAX_ABSTRACT_FRAME_DEPTH (16) - -// The maximum number of side exits that we can take before requiring forward -// progress (and inserting a new ENTER_EXECUTOR instruction). In practice, this -// is the "maximum amount of polymorphism" that an isolated trace tree can -// handle before rejoining the rest of the program. -#define MAX_CHAIN_DEPTH 4 - -/* Symbols */ -/* See explanation in optimizer_symbols.c */ - - -typedef enum _JitSymType { - JIT_SYM_UNKNOWN_TAG = 1, - JIT_SYM_NULL_TAG = 2, - JIT_SYM_NON_NULL_TAG = 3, - JIT_SYM_BOTTOM_TAG = 4, - JIT_SYM_TYPE_VERSION_TAG = 5, - JIT_SYM_KNOWN_CLASS_TAG = 6, - JIT_SYM_KNOWN_VALUE_TAG = 7, - JIT_SYM_TUPLE_TAG = 8, - JIT_SYM_TRUTHINESS_TAG = 9, - JIT_SYM_COMPACT_INT = 10, -} JitSymType; - -typedef struct _jit_opt_known_class { - uint8_t tag; - uint32_t version; - PyTypeObject *type; -} JitOptKnownClass; - -typedef struct _jit_opt_known_version { - uint8_t tag; - uint32_t version; -} JitOptKnownVersion; - -typedef struct _jit_opt_known_value { - uint8_t tag; - PyObject *value; -} JitOptKnownValue; - -#define MAX_SYMBOLIC_TUPLE_SIZE 7 - -typedef struct _jit_opt_tuple { - uint8_t tag; - uint8_t length; - uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE]; -} JitOptTuple; - -typedef struct { - uint8_t tag; - bool invert; - uint16_t value; -} JitOptTruthiness; - -typedef struct { - uint8_t tag; -} JitOptCompactInt; - -typedef union _jit_opt_symbol { - uint8_t tag; - JitOptKnownClass cls; - JitOptKnownValue value; - JitOptKnownVersion version; - JitOptTuple tuple; - JitOptTruthiness truthiness; - JitOptCompactInt compact; -} JitOptSymbol; - - -// This mimics the _PyStackRef API -typedef union { - uintptr_t bits; -} JitOptRef; #define REF_IS_BORROWED 1 @@ -238,48 +159,6 @@ PyJitRef_IsBorrowed(JitOptRef ref) return (ref.bits & REF_IS_BORROWED) == REF_IS_BORROWED; } -struct _Py_UOpsAbstractFrame { - bool globals_watched; - // The version number of the globals dicts, once checked. 0 if unchecked. - uint32_t globals_checked_version; - // Max stacklen - int stack_len; - int locals_len; - PyFunctionObject *func; - PyCodeObject *code; - - JitOptRef *stack_pointer; - JitOptRef *stack; - JitOptRef *locals; -}; - -typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; - -typedef struct ty_arena { - int ty_curr_number; - int ty_max_number; - JitOptSymbol arena[TY_ARENA_SIZE]; -} ty_arena; - -typedef struct _JitOptContext { - char done; - char out_of_space; - bool contradiction; - // Has the builtins dict been watched? - bool builtins_watched; - // The current "executing" frame. - _Py_UOpsAbstractFrame *frame; - _Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH]; - int curr_frame_depth; - - // Arena for the symbolic types. - ty_arena t_arena; - - JitOptRef *n_consumed; - JitOptRef *limit; - JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; -} JitOptContext; - extern bool _Py_uop_sym_is_null(JitOptRef sym); extern bool _Py_uop_sym_is_not_null(JitOptRef sym); extern bool _Py_uop_sym_is_const(JitOptContext *ctx, JitOptRef sym); diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h new file mode 100644 index 00000000000000..de8e50921e3311 --- /dev/null +++ b/Include/internal/pycore_optimizer_types.h @@ -0,0 +1,137 @@ +#ifndef Py_INTERNAL_OPTIMIZER_TYPES_H +#define Py_INTERNAL_OPTIMIZER_TYPES_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "pycore_uop.h" // UOP_MAX_TRACE_LENGTH + +// Holds locals, stack, locals, stack ... co_consts (in that order) +#define MAX_ABSTRACT_INTERP_SIZE 4096 + +#define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5) + +// Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH()) +#define MAX_ABSTRACT_FRAME_DEPTH (16) + +// The maximum number of side exits that we can take before requiring forward +// progress (and inserting a new ENTER_EXECUTOR instruction). In practice, this +// is the "maximum amount of polymorphism" that an isolated trace tree can +// handle before rejoining the rest of the program. +#define MAX_CHAIN_DEPTH 4 + +/* Symbols */ +/* See explanation in optimizer_symbols.c */ + + +typedef enum _JitSymType { + JIT_SYM_UNKNOWN_TAG = 1, + JIT_SYM_NULL_TAG = 2, + JIT_SYM_NON_NULL_TAG = 3, + JIT_SYM_BOTTOM_TAG = 4, + JIT_SYM_TYPE_VERSION_TAG = 5, + JIT_SYM_KNOWN_CLASS_TAG = 6, + JIT_SYM_KNOWN_VALUE_TAG = 7, + JIT_SYM_TUPLE_TAG = 8, + JIT_SYM_TRUTHINESS_TAG = 9, + JIT_SYM_COMPACT_INT = 10, +} JitSymType; + +typedef struct _jit_opt_known_class { + uint8_t tag; + uint32_t version; + PyTypeObject *type; +} JitOptKnownClass; + +typedef struct _jit_opt_known_version { + uint8_t tag; + uint32_t version; +} JitOptKnownVersion; + +typedef struct _jit_opt_known_value { + uint8_t tag; + PyObject *value; +} JitOptKnownValue; + +#define MAX_SYMBOLIC_TUPLE_SIZE 7 + +typedef struct _jit_opt_tuple { + uint8_t tag; + uint8_t length; + uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE]; +} JitOptTuple; + +typedef struct { + uint8_t tag; + bool invert; + uint16_t value; +} JitOptTruthiness; + +typedef struct { + uint8_t tag; +} JitOptCompactInt; + +typedef union _jit_opt_symbol { + uint8_t tag; + JitOptKnownClass cls; + JitOptKnownValue value; + JitOptKnownVersion version; + JitOptTuple tuple; + JitOptTruthiness truthiness; + JitOptCompactInt compact; +} JitOptSymbol; + +// This mimics the _PyStackRef API +typedef union { + uintptr_t bits; +} JitOptRef; + +typedef struct _Py_UOpsAbstractFrame { + bool globals_watched; + // The version number of the globals dicts, once checked. 0 if unchecked. + uint32_t globals_checked_version; + // Max stacklen + int stack_len; + int locals_len; + PyFunctionObject *func; + PyCodeObject *code; + + JitOptRef *stack_pointer; + JitOptRef *stack; + JitOptRef *locals; +} _Py_UOpsAbstractFrame; + +typedef struct ty_arena { + int ty_curr_number; + int ty_max_number; + JitOptSymbol arena[TY_ARENA_SIZE]; +} ty_arena; + +typedef struct _JitOptContext { + char done; + char out_of_space; + bool contradiction; + // Has the builtins dict been watched? + bool builtins_watched; + // The current "executing" frame. + _Py_UOpsAbstractFrame *frame; + _Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH]; + int curr_frame_depth; + + // Arena for the symbolic types. + ty_arena t_arena; + + JitOptRef *n_consumed; + JitOptRef *limit; + JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; +} JitOptContext; + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_OPTIMIZER_TYPES_H */ diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h index d8f4bfef98af7e..81cabb4dca47e4 100644 --- a/Include/internal/pycore_tstate.h +++ b/Include/internal/pycore_tstate.h @@ -12,6 +12,7 @@ extern "C" { #include "pycore_freelist_state.h" // struct _Py_freelists #include "pycore_interpframe_structs.h" // _PyInterpreterFrame #include "pycore_mimalloc.h" // struct _mimalloc_thread_state +#include "pycore_optimizer_types.h" // JitOptContext #include "pycore_qsbr.h" // struct qsbr #include "pycore_uop.h" // struct _PyUOpInstruction #include "pycore_structs.h" @@ -52,10 +53,11 @@ typedef struct _PyJitTracerTranslatorState { } _PyJitTracerTranslatorState; typedef struct _PyJitTracerState { - _PyUOpInstruction *code_buffer; _PyJitTracerInitialState initial_state; _PyJitTracerPreviousState prev_state; _PyJitTracerTranslatorState translator_state; + JitOptContext opt_context; + _PyUOpInstruction code_buffer[UOP_MAX_TRACE_LENGTH]; } _PyJitTracerState; #endif diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index 694fea806f7944..a7d57561ead046 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -97,11 +97,6 @@ def reload(module): The module must have been successfully imported before. """ - # If a LazyModule has not yet been materialized, reload is a no-op. - if importlib_util := sys.modules.get('importlib.util'): - if lazy_module_type := getattr(importlib_util, '_LazyModule', None): - if isinstance(module, lazy_module_type): - return module try: name = module.__spec__.name except AttributeError: diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index cfb24a5c457820..ebcd98a0a37776 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -1,8 +1,6 @@ # Python test set -- part 1, grammar. # This just tests whether the parser accepts them all. -from test.support import check_syntax_error, skip_wasi_stack_overflow -from test.support import import_helper import annotationlib import inspect import unittest @@ -18,6 +16,12 @@ import typing from test.typinganndata import ann_module2 import test +from test.support import ( + check_syntax_error, + import_helper, + skip_emscripten_stack_overflow, + skip_wasi_stack_overflow, +) from test.support.numbers import ( VALID_UNDERSCORE_LITERALS, INVALID_UNDERSCORE_LITERALS, @@ -250,6 +254,7 @@ def test_eof_error(self): self.assertIn("was never closed", str(cm.exception)) @skip_wasi_stack_overflow() + @skip_emscripten_stack_overflow() def test_max_level(self): # Macro defined in Parser/lexer/state.h MAXLEVEL = 200 diff --git a/Lib/test/test_importlib/test_lazy.py b/Lib/test/test_importlib/test_lazy.py index c6b26ad75b97f9..e48fad8898f0ef 100644 --- a/Lib/test/test_importlib/test_lazy.py +++ b/Lib/test/test_importlib/test_lazy.py @@ -10,9 +10,6 @@ from test.support import threading_helper from test.test_importlib import util as test_util -# Make sure sys.modules[util] is in sync with the import. -# That is needed as other tests may reload util. -sys.modules['importlib.util'] = util class CollectInit: @@ -195,7 +192,7 @@ def test_lazy_self_referential_modules(self): sys.modules['json'] = module loader.exec_module(module) - # Trigger load with attribute lookup, ensure expected behavior. + # Trigger load with attribute lookup, ensure expected behavior test_load = module.loads('{}') self.assertEqual(test_load, {}) @@ -227,26 +224,6 @@ def __delattr__(self, name): with self.assertRaises(AttributeError): del module.CONSTANT - def test_reload(self): - # Reloading a lazy module that hasn't been materialized is a no-op. - module = self.new_module() - sys.modules[TestingImporter.module_name] = module - - # Change the source code to add a new attribute. - TestingImporter.source_code = 'attr = 42\nnew_attr = 123\n__name__ = {!r}'.format(TestingImporter.mutated_name) - self.assertIsInstance(module, util._LazyModule) - - # Reload the module (should be a no-op since not materialized). - reloaded = importlib.reload(module) - self.assertIs(reloaded, module) - self.assertIsInstance(module, util._LazyModule) - - # Access the new attribute (should trigger materialization, and new_attr should exist). - self.assertEqual(module.attr, 42) - self.assertNotIsInstance(module, util._LazyModule) - self.assertTrue(hasattr(module, 'new_attr')) - self.assertEqual(module.new_attr, 123) - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py index f187f6c51d88e2..0d92bd1796e9af 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py @@ -714,6 +714,7 @@ def test_run_nonexistent_module_exits_cleanly(self): with self.assertRaisesRegex(SamplingModuleNotFoundError, "Module '[\\w/.]+' not found."): main() + @unittest.skipIf(is_emscripten, "subprocess not available") def test_cli_attach_nonexistent_pid(self): fake_pid = "99999" with mock.patch("sys.argv", ["profiling.sampling.cli", "attach", fake_pid]): diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py index ae336ccdb941ce..8e6afa91e89daf 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py @@ -7,6 +7,8 @@ import tempfile import unittest +from test.support import is_emscripten + try: import _remote_debugging # noqa: F401 from profiling.sampling.pstats_collector import PstatsCollector @@ -599,6 +601,7 @@ def test_gecko_collector_basic(self): self.assertGreater(stack_table["length"], 0) self.assertGreater(len(stack_table["frame"]), 0) + @unittest.skipIf(is_emscripten, "threads not available") def test_gecko_collector_export(self): """Test Gecko profile export functionality.""" gecko_out = tempfile.NamedTemporaryFile(suffix=".json", delete=False) diff --git a/Misc/NEWS.d/3.15.0a3.rst b/Misc/NEWS.d/3.15.0a3.rst index 7d52b3d0c80c55..e493c3570847fd 100644 --- a/Misc/NEWS.d/3.15.0a3.rst +++ b/Misc/NEWS.d/3.15.0a3.rst @@ -843,15 +843,6 @@ for :term:`stdlib` modules. .. -.. date: 2025-10-09-15-46-18 -.. gh-issue: 139686 -.. nonce: XwIZB2 -.. section: Library - -Make importlib.reload no-op for lazy modules. - -.. - .. date: 2025-09-09-13-00-42 .. gh-issue: 138697 .. nonce: QVwJw_ diff --git a/Misc/NEWS.d/next/Library/2026-01-08-13-41-58.gh-issue-139686.S_nzkl.rst b/Misc/NEWS.d/next/Library/2026-01-08-13-41-58.gh-issue-139686.S_nzkl.rst new file mode 100644 index 00000000000000..6d21a48613465f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-08-13-41-58.gh-issue-139686.S_nzkl.rst @@ -0,0 +1,3 @@ +Revert 0a97941245f1dda6d838f9aaf0512104e5253929 and +57db12514ac686f0a752ec8fe1c08b6daa0c6219 which made importlib.reload a no-op +for lazy modules; caused Buildbot failures. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 3c0b454503be66..1d4c0f6785c4b8 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -2015,30 +2015,20 @@ frame_clear_impl(PyFrameObject *self) { if (self->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { PyGenObject *gen = _PyGen_GetGeneratorFromFrame(self->f_frame); - if (gen->gi_frame_state == FRAME_EXECUTING) { - goto running; - } - if (FRAME_STATE_SUSPENDED(gen->gi_frame_state)) { - goto suspended; + if (_PyGen_ClearFrame(gen) < 0) { + return NULL; } - _PyGen_Finalize((PyObject *)gen); } else if (self->f_frame->owner == FRAME_OWNED_BY_THREAD) { - goto running; + PyErr_SetString(PyExc_RuntimeError, + "cannot clear an executing frame"); + return NULL; } else { assert(self->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT); (void)frame_tp_clear((PyObject *)self); } Py_RETURN_NONE; -running: - PyErr_SetString(PyExc_RuntimeError, - "cannot clear an executing frame"); - return NULL; -suspended: - PyErr_SetString(PyExc_RuntimeError, - "cannot clear a suspended frame"); - return NULL; } /*[clinic input] diff --git a/Objects/genobject.c b/Objects/genobject.c index d1fcda3d608320..09407d60af62be 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -91,8 +91,8 @@ gen_traverse(PyObject *self, visitproc visit, void *arg) return 0; } -void -_PyGen_Finalize(PyObject *self) +static void +gen_finalize(PyObject *self) { PyGenObject *gen = (PyGenObject *)self; @@ -160,6 +160,34 @@ gen_clear_frame(PyGenObject *gen) _PyErr_ClearExcState(&gen->gi_exc_state); } +int +_PyGen_ClearFrame(PyGenObject *gen) +{ + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); + do { + if (FRAME_STATE_FINISHED(frame_state)) { + return 0; + } + else if (frame_state == FRAME_EXECUTING) { + PyErr_SetString(PyExc_RuntimeError, + "cannot clear an executing frame"); + return -1; + } + else if (FRAME_STATE_SUSPENDED(frame_state)) { + PyErr_SetString(PyExc_RuntimeError, + "cannot clear an suspended frame"); + return -1; + } + assert(frame_state == FRAME_CREATED); + } while (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_CLEARED)); + + if (_PyGen_GetCode(gen)->co_flags & CO_COROUTINE) { + _PyErr_WarnUnawaitedCoroutine((PyObject *)gen); + } + gen_clear_frame(gen); + return 0; +} + static void gen_dealloc(PyObject *self) { @@ -1006,7 +1034,7 @@ PyTypeObject PyGen_Type = { 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ - _PyGen_Finalize, /* tp_finalize */ + gen_finalize, /* tp_finalize */ }; static PyObject * @@ -1336,7 +1364,7 @@ PyTypeObject PyCoro_Type = { 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ - _PyGen_Finalize, /* tp_finalize */ + gen_finalize, /* tp_finalize */ }; static void @@ -1762,7 +1790,7 @@ PyTypeObject PyAsyncGen_Type = { 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ - _PyGen_Finalize, /* tp_finalize */ + gen_finalize, /* tp_finalize */ }; diff --git a/Python/optimizer.c b/Python/optimizer.c index d32fae2e489af4..73617f6ca26425 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1025,13 +1025,6 @@ _PyJit_TryInitializeTracing( if (oparg > 0xFFFF) { return 0; } - if (_tstate->jit_tracer_state.code_buffer == NULL) { - _tstate->jit_tracer_state.code_buffer = (_PyUOpInstruction *)_PyObject_VirtualAlloc(UOP_BUFFER_SIZE); - if (_tstate->jit_tracer_state.code_buffer == NULL) { - // Don't error, just go to next instruction. - return 0; - } - } PyObject *func = PyStackRef_AsPyObjectBorrow(frame->f_funcobj); if (func == NULL) { return 0; @@ -1484,8 +1477,8 @@ uop_optimize( OPT_STAT_INC(traces_created); if (!is_noopt) { length = _Py_uop_analyze_and_optimize( - _tstate->jit_tracer_state.initial_state.func, - buffer,length, + _tstate, + buffer, length, curr_stackentries, dependencies); if (length <= 0) { return length; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 29a088e43c2a0f..56d4f9945d6908 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -18,6 +18,7 @@ #include "pycore_opcode_metadata.h" #include "pycore_opcode_utils.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_tstate.h" // _PyThreadStateImpl #include "pycore_uop_metadata.h" #include "pycore_long.h" #include "pycore_interpframe.h" // _PyFrame_GetCode @@ -334,7 +335,7 @@ _Py_opt_assert_within_stack_bounds( /* >0 (length) for success, 0 for not ready, clears all possible errors. */ static int optimize_uops( - PyFunctionObject *func, + _PyThreadStateImpl *tstate, _PyUOpInstruction *trace, int trace_len, int curr_stacklen, @@ -342,9 +343,9 @@ optimize_uops( ) { assert(!PyErr_Occurred()); + PyFunctionObject *func = tstate->jit_tracer_state.initial_state.func; - JitOptContext context; - JitOptContext *ctx = &context; + JitOptContext *ctx = &tstate->jit_tracer_state.opt_context; uint32_t opcode = UINT16_MAX; // Make sure that watchers are set up @@ -574,7 +575,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) // > 0 - length of optimized trace int _Py_uop_analyze_and_optimize( - PyFunctionObject *func, + _PyThreadStateImpl *tstate, _PyUOpInstruction *buffer, int length, int curr_stacklen, @@ -584,7 +585,7 @@ _Py_uop_analyze_and_optimize( OPT_STAT_INC(optimizer_attempts); length = optimize_uops( - func, buffer, + tstate, buffer, length, curr_stacklen, dependencies); if (length == 0) { diff --git a/Python/pystate.c b/Python/pystate.c index 23853f69792450..74507efa5b4cf3 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1553,7 +1553,6 @@ init_threadstate(_PyThreadStateImpl *_tstate, init_policy(&_tstate->policy.jit.side_exit_initial_backoff, "PYTHON_JIT_SIDE_EXIT_INITIAL_BACKOFF", SIDE_EXIT_INITIAL_BACKOFF, 0, MAX_BACKOFF); - _tstate->jit_tracer_state.code_buffer = NULL; #endif tstate->delete_later = NULL; @@ -1868,14 +1867,6 @@ tstate_delete_common(PyThreadState *tstate, int release_gil) assert(tstate_impl->refcounts.values == NULL); #endif -#if _Py_TIER2 - _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; - if (_tstate->jit_tracer_state.code_buffer != NULL) { - _PyObject_VirtualFree(_tstate->jit_tracer_state.code_buffer, UOP_BUFFER_SIZE); - _tstate->jit_tracer_state.code_buffer = NULL; - } -#endif - HEAD_UNLOCK(runtime); // XXX Unbind in PyThreadState_Clear(), or earlier