diff options
author | Neil Schemenauer <nas-github@arctrix.com> | 2024-12-03 18:25:12 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-03 18:25:12 (GMT) |
commit | 276cd66ccbbf85996a57bd1db3dd29b93a6eab64 (patch) | |
tree | a8f7f3676314b21b546c77e5928f28a5efff52e2 | |
parent | 13b68e1a61e92a032d255aff5d5af435bbb63e8b (diff) | |
download | cpython-276cd66ccbbf85996a57bd1db3dd29b93a6eab64.zip cpython-276cd66ccbbf85996a57bd1db3dd29b93a6eab64.tar.gz cpython-276cd66ccbbf85996a57bd1db3dd29b93a6eab64.tar.bz2 |
gh-115999: Add free-threaded specialization for `SEND` (gh-127426)
No additional thread safety changes are required. Note that sending to
a generator that is shared between threads is currently not safe in the
free-threaded build.
-rw-r--r-- | Lib/test/test_opcache.py | 42 | ||||
-rw-r--r-- | Python/bytecodes.c | 4 | ||||
-rw-r--r-- | Python/generated_cases.c.h | 4 | ||||
-rw-r--r-- | Python/specialize.c | 15 |
4 files changed, 50 insertions, 15 deletions
diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 5271144..b7a1813 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -1313,6 +1313,48 @@ class TestSpecializer(TestBase): @cpython_only @requires_specialization_ft + def test_send_with(self): + def run_async(coro): + while True: + try: + coro.send(None) + except StopIteration: + break + + class CM: + async def __aenter__(self): + return self + + async def __aexit__(self, *exc): + pass + + async def send_with(): + for i in range(100): + async with CM(): + x = 1 + + run_async(send_with()) + # Note there are still unspecialized "SEND" opcodes in the + # cleanup paths of the 'with' statement. + self.assert_specialized(send_with, "SEND_GEN") + + @cpython_only + @requires_specialization_ft + def test_send_yield_from(self): + def g(): + yield None + + def send_yield_from(): + yield from g() + + for i in range(100): + list(send_yield_from()) + + self.assert_specialized(send_yield_from, "SEND_GEN") + self.assert_no_opcode(send_yield_from, "SEND") + + @cpython_only + @requires_specialization_ft def test_to_bool(self): def to_bool_bool(): true_cnt, false_cnt = 0, 0 diff --git a/Python/bytecodes.c b/Python/bytecodes.c index dd28aae..d6be3ce 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1117,7 +1117,7 @@ dummy_func( }; specializing op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) { - #if ENABLE_SPECIALIZATION + #if ENABLE_SPECIALIZATION_FT if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_Send(receiver, next_instr); @@ -1125,7 +1125,7 @@ dummy_func( } OPCODE_DEFERRED_INC(SEND); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION */ + #endif /* ENABLE_SPECIALIZATION_FT */ } op(_SEND, (receiver, v -- receiver, retval)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c31601f..ef191f6 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -7065,7 +7065,7 @@ receiver = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION + #if ENABLE_SPECIALIZATION_FT if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -7075,7 +7075,7 @@ } OPCODE_DEFERRED_INC(SEND); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION */ + #endif /* ENABLE_SPECIALIZATION_FT */ } // _SEND { diff --git a/Python/specialize.c b/Python/specialize.c index 0fe4e79..8b2d1a1 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2627,28 +2627,21 @@ _Py_Specialize_Send(_PyStackRef receiver_st, _Py_CODEUNIT *instr) { PyObject *receiver = PyStackRef_AsPyObjectBorrow(receiver_st); - assert(ENABLE_SPECIALIZATION); + assert(ENABLE_SPECIALIZATION_FT); assert(_PyOpcode_Caches[SEND] == INLINE_CACHE_ENTRIES_SEND); - _PySendCache *cache = (_PySendCache *)(instr + 1); PyTypeObject *tp = Py_TYPE(receiver); if (tp == &PyGen_Type || tp == &PyCoro_Type) { if (_PyInterpreterState_GET()->eval_frame) { SPECIALIZATION_FAIL(SEND, SPEC_FAIL_OTHER); goto failure; } - instr->op.code = SEND_GEN; - goto success; + specialize(instr, SEND_GEN); + return; } SPECIALIZATION_FAIL(SEND, _PySpecialization_ClassifyIterator(receiver)); failure: - STAT_INC(SEND, failure); - instr->op.code = SEND; - cache->counter = adaptive_counter_backoff(cache->counter); - return; -success: - STAT_INC(SEND, success); - cache->counter = adaptive_counter_cooldown(); + unspecialize(instr); } #ifdef Py_STATS |