mirror of
https://github.com/python/cpython.git
synced 2025-11-01 18:51:43 +00:00
gh-115999: Enable specialization of CALL instructions in free-threaded builds (#127123)
The CALL family of instructions were mostly thread-safe already and only required a small number of changes, which are documented below.
A few changes were needed to make CALL_ALLOC_AND_ENTER_INIT thread-safe:
Added _PyType_LookupRefAndVersion, which returns the type version corresponding to the returned ref.
Added _PyType_CacheInitForSpecialization, which takes an init method and the corresponding type version and only populates the specialization cache if the current type version matches the supplied version. This prevents potentially caching a stale value in free-threaded builds if we race with an update to __init__.
Only cache __init__ functions that are deferred in free-threaded builds. This ensures that the reference to __init__ that is stored in the specialization cache is valid if the type version guard in _CHECK_AND_ALLOCATE_OBJECT passes.
Fix a bug in _CREATE_INIT_FRAME where the frame is pushed to the stack on failure.
A few other miscellaneous changes were also needed:
Use {LOCK,UNLOCK}_OBJECT in LIST_APPEND. This ensures that the list's per-object lock is held while we are appending to it.
Add missing co_tlbc for _Py_InitCleanup.
Stop/start the world around setting the eval frame hook. This allows us to read interp->eval_frame non-atomically and preserves the behavior of _CHECK_PEP_523 documented below.
This commit is contained in:
parent
fc5a0dc224
commit
dabcecfd6d
11 changed files with 220 additions and 92 deletions
|
|
@ -11,7 +11,7 @@ import types
|
|||
import unittest
|
||||
|
||||
import test.support
|
||||
from test.support import requires_specialization, script_helper
|
||||
from test.support import requires_specialization_ft, script_helper
|
||||
from test.support.import_helper import import_module
|
||||
|
||||
_testcapi = test.support.import_helper.import_module("_testcapi")
|
||||
|
|
@ -850,6 +850,13 @@ class ReturnRecorder:
|
|||
def __call__(self, code, offset, val):
|
||||
self.events.append(("return", code.co_name, val))
|
||||
|
||||
# gh-127274: CALL_ALLOC_AND_ENTER_INIT will only cache __init__ methods that
|
||||
# are deferred. We only defer functions defined at the top-level.
|
||||
class ValueErrorRaiser:
|
||||
def __init__(self):
|
||||
raise ValueError()
|
||||
|
||||
|
||||
class ExceptionMonitoringTest(CheckEvents):
|
||||
|
||||
exception_recorders = (
|
||||
|
|
@ -1045,16 +1052,12 @@ class ExceptionMonitoringTest(CheckEvents):
|
|||
)
|
||||
self.assertEqual(events[0], ("throw", IndexError))
|
||||
|
||||
@requires_specialization
|
||||
@requires_specialization_ft
|
||||
def test_no_unwind_for_shim_frame(self):
|
||||
|
||||
class B:
|
||||
def __init__(self):
|
||||
raise ValueError()
|
||||
|
||||
def f():
|
||||
try:
|
||||
return B()
|
||||
return ValueErrorRaiser()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue