Skip to content

Commit cfbd6ca

Browse files
committed
Merge remote-tracking branch 'upstream/main' into binary_subscr_to_op
2 parents 99173b9 + 49bd47d commit cfbd6ca

File tree

14 files changed

+104
-353
lines changed

14 files changed

+104
-353
lines changed

Doc/whatsnew/3.14.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ For further information on how to build Python, see
238238
__ https://en.wikipedia.org/wiki/Tail_call
239239

240240
(Contributed by Ken Jin in :gh:`128718`, with ideas on how to implement this
241-
in CPython by Mark Shannon, Garret Gu, Haoran Xu, and Josh Haberman.)
241+
in CPython by Mark Shannon, Garrett Gu, Haoran Xu, and Josh Haberman.)
242242

243243

244244
Other language changes

Include/internal/pycore_uop_metadata.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_asyncio/test_tasks.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,7 +2254,6 @@ def test_wait_invalid_args(self):
22542254
asyncio.wait([]))
22552255

22562256
def test_log_destroyed_pending_task(self):
2257-
Task = self.__class__.Task
22582257

22592258
async def kill_me(loop):
22602259
future = self.new_future(loop)
@@ -2269,7 +2268,7 @@ async def kill_me(loop):
22692268

22702269
# schedule the task
22712270
coro = kill_me(self.loop)
2272-
task = asyncio.ensure_future(coro, loop=self.loop)
2271+
task = self.new_task(self.loop, coro)
22732272

22742273
self.assertEqual(self.all_tasks(loop=self.loop), {task})
22752274

@@ -2286,14 +2285,17 @@ async def kill_me(loop):
22862285
# no more reference to kill_me() task: the task is destroyed by the GC
22872286
support.gc_collect()
22882287

2289-
self.assertEqual(self.all_tasks(loop=self.loop), set())
2290-
22912288
mock_handler.assert_called_with(self.loop, {
22922289
'message': 'Task was destroyed but it is pending!',
22932290
'task': mock.ANY,
22942291
'source_traceback': source_traceback,
22952292
})
22962293
mock_handler.reset_mock()
2294+
# task got resurrected by the exception handler
2295+
support.gc_collect()
2296+
2297+
self.assertEqual(self.all_tasks(loop=self.loop), set())
2298+
22972299

22982300
@mock.patch('asyncio.base_events.logger')
22992301
def test_tb_logger_not_called_after_cancel(self, m_log):

Python/bytecodes.c

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3498,6 +3498,7 @@ dummy_func(
34983498
}
34993499

35003500
op(_MAYBE_EXPAND_METHOD, (callable[1], self_or_null[1], args[oparg] -- func[1], maybe_self[1], args[oparg])) {
3501+
(void)args;
35013502
if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) {
35023503
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
35033504
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
@@ -3864,6 +3865,7 @@ dummy_func(
38643865
_CHECK_PERIODIC;
38653866

38663867
op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable[1], null[1], args[oparg] -- init[1], self[1], args[oparg])) {
3868+
(void)args;
38673869
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
38683870
DEOPT_IF(!PyStackRef_IsNull(null[0]));
38693871
DEOPT_IF(!PyType_Check(callable_o));
@@ -4091,7 +4093,7 @@ dummy_func(
40914093
PyObject *res_o = PyLong_FromSsize_t(len_i);
40924094
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
40934095
if (res_o == NULL) {
4094-
GOTO_ERROR(error);
4096+
ERROR_NO_POP();
40954097
}
40964098
PyStackRef_CLOSE(arg_stackref);
40974099
DEAD(args);
@@ -4336,6 +4338,7 @@ dummy_func(
43364338
}
43374339

43384340
op(_MAYBE_EXPAND_METHOD_KW, (callable[1], self_or_null[1], args[oparg], kwnames_in -- func[1], maybe_self[1], args[oparg], kwnames_out)) {
4341+
(void)args;
43394342
if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) {
43404343
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
43414344
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
@@ -4994,7 +4997,7 @@ dummy_func(
49944997
if (frame->lltrace >= 2) {
49954998
printf("SIDE EXIT: [UOp ");
49964999
_PyUOpPrint(&next_uop[-1]);
4997-
printf(", exit %u, temp %d, target %d -> %s]\n",
5000+
printf(", exit %lu, temp %d, target %d -> %s]\n",
49985001
exit - current_executor->exits, exit->temperature.value_and_backoff,
49995002
(int)(target - _PyFrame_GetBytecode(frame)),
50005003
_PyOpcode_OpName[target->op.code]);
@@ -5004,11 +5007,11 @@ dummy_func(
50045007
exit->temperature = initial_temperature_backoff_counter();
50055008
Py_CLEAR(exit->executor);
50065009
}
5010+
tstate->previous_executor = (PyObject *)current_executor;
50075011
if (exit->executor == NULL) {
50085012
_Py_BackoffCounter temperature = exit->temperature;
50095013
if (!backoff_counter_triggers(temperature)) {
50105014
exit->temperature = advance_backoff_counter(temperature);
5011-
tstate->previous_executor = (PyObject *)current_executor;
50125015
GOTO_TIER_ONE(target);
50135016
}
50145017
_PyExecutorObject *executor;
@@ -5021,20 +5024,13 @@ dummy_func(
50215024
int optimized = _PyOptimizer_Optimize(frame, target, &executor, chain_depth);
50225025
if (optimized <= 0) {
50235026
exit->temperature = restart_backoff_counter(temperature);
5024-
if (optimized < 0) {
5025-
GOTO_UNWIND();
5026-
}
5027-
tstate->previous_executor = (PyObject *)current_executor;
5028-
GOTO_TIER_ONE(target);
5029-
}
5030-
else {
5031-
exit->temperature = initial_temperature_backoff_counter();
5027+
GOTO_TIER_ONE(optimized < 0 ? NULL : target);
50325028
}
5029+
exit->temperature = initial_temperature_backoff_counter();
50335030
}
50345031
exit->executor = executor;
50355032
}
50365033
Py_INCREF(exit->executor);
5037-
tstate->previous_executor = (PyObject *)current_executor;
50385034
GOTO_TIER_TWO(exit->executor);
50395035
}
50405036

@@ -5102,7 +5098,7 @@ dummy_func(
51025098
if (frame->lltrace >= 2) {
51035099
printf("DYNAMIC EXIT: [UOp ");
51045100
_PyUOpPrint(&next_uop[-1]);
5105-
printf(", exit %u, temp %d, target %d -> %s]\n",
5101+
printf(", exit %lu, temp %d, target %d -> %s]\n",
51065102
exit - current_executor->exits, exit->temperature.value_and_backoff,
51075103
(int)(target - _PyFrame_GetBytecode(frame)),
51085104
_PyOpcode_OpName[target->op.code]);
@@ -5122,21 +5118,15 @@ dummy_func(
51225118
int optimized = _PyOptimizer_Optimize(frame, target, &executor, 0);
51235119
if (optimized <= 0) {
51245120
exit->temperature = restart_backoff_counter(exit->temperature);
5125-
if (optimized < 0) {
5126-
GOTO_UNWIND();
5127-
}
5128-
GOTO_TIER_ONE(target);
5129-
}
5130-
else {
5131-
exit->temperature = initial_temperature_backoff_counter();
5121+
GOTO_TIER_ONE(optimized < 0 ? NULL : target);
51325122
}
5123+
exit->temperature = initial_temperature_backoff_counter();
51335124
}
51345125
GOTO_TIER_TWO(executor);
51355126
}
51365127

51375128
tier2 op(_START_EXECUTOR, (executor/4 --)) {
5138-
Py_DECREF(tstate->previous_executor);
5139-
tstate->previous_executor = NULL;
5129+
Py_CLEAR(tstate->previous_executor);
51405130
#ifndef _Py_JIT
51415131
current_executor = (_PyExecutorObject*)executor;
51425132
#endif
@@ -5162,14 +5152,16 @@ dummy_func(
51625152
}
51635153

51645154
tier2 op(_DEOPT, (--)) {
5165-
EXIT_TO_TIER1();
5155+
tstate->previous_executor = (PyObject *)current_executor;
5156+
GOTO_TIER_ONE(_PyFrame_GetBytecode(frame) + CURRENT_TARGET());
51665157
}
51675158

51685159
tier2 op(_ERROR_POP_N, (target/2 --)) {
5160+
tstate->previous_executor = (PyObject *)current_executor;
51695161
assert(oparg == 0);
51705162
frame->instr_ptr = _PyFrame_GetBytecode(frame) + target;
51715163
SYNC_SP();
5172-
GOTO_UNWIND();
5164+
GOTO_TIER_ONE(NULL);
51735165
}
51745166

51755167
/* Progress is guaranteed if we DEOPT on the eval breaker, because

Python/ceval.c

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -880,9 +880,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
880880
#undef LOAD_IP
881881
#define LOAD_IP(UNUSED) (void)0
882882

883-
#undef GOTO_ERROR
884-
#define GOTO_ERROR(LABEL) goto LABEL ## _tier_two
885-
886883
#ifdef Py_STATS
887884
// Disable these macros that apply to Tier 1 stats when we are in Tier 2
888885
#undef STAT_INC
@@ -958,46 +955,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
958955
_PyOpcode_OpName[frame->instr_ptr->op.code]);
959956
}
960957
#endif
961-
assert (next_uop[-1].format == UOP_FORMAT_JUMP);
958+
assert(next_uop[-1].format == UOP_FORMAT_JUMP);
962959
uint16_t target = uop_get_error_target(&next_uop[-1]);
963960
next_uop = current_executor->trace + target;
964961
goto tier2_dispatch;
965962

966-
error_tier_two:
967-
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
968-
assert(next_uop[-1].format == UOP_FORMAT_TARGET);
969-
frame->return_offset = 0; // Don't leave this random
970-
Py_DECREF(current_executor);
971-
tstate->previous_executor = NULL;
972-
next_instr = frame->instr_ptr;
973-
goto error;
974-
975963
jump_to_jump_target:
976964
assert(next_uop[-1].format == UOP_FORMAT_JUMP);
977965
target = uop_get_jump_target(&next_uop[-1]);
978966
next_uop = current_executor->trace + target;
979967
goto tier2_dispatch;
980968

981-
exit_to_tier1_dynamic:
982-
next_instr = frame->instr_ptr;
983-
goto goto_to_tier1;
984-
exit_to_tier1:
985-
assert(next_uop[-1].format == UOP_FORMAT_TARGET);
986-
next_instr = next_uop[-1].target + _PyFrame_GetBytecode(frame);
987-
goto_to_tier1:
988-
#ifdef Py_DEBUG
989-
if (frame->lltrace >= 2) {
990-
printf("DEOPT: [UOp ");
991-
_PyUOpPrint(&next_uop[-1]);
992-
printf(" -> %s]\n",
993-
_PyOpcode_OpName[next_instr->op.code]);
994-
}
995-
#endif
996-
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
997-
Py_DECREF(current_executor);
998-
tstate->previous_executor = NULL;
999-
DISPATCH();
1000-
1001969
#endif // _Py_JIT
1002970

1003971
#endif // _Py_TIER2

Python/ceval_macros.h

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,6 @@ do { \
161161
JUMP_TO_LABEL(start_frame); \
162162
} while (0)
163163

164-
// Use this instead of 'goto error' so Tier 2 can go to a different label
165-
#define GOTO_ERROR(LABEL) JUMP_TO_LABEL(LABEL)
166-
167164
/* Tuple access macros */
168165

169166
#ifndef Py_DEBUG
@@ -387,17 +384,19 @@ _PyFrame_SetStackPointer(frame, stack_pointer)
387384
#define GOTO_TIER_TWO(EXECUTOR) \
388385
do { \
389386
OPT_STAT_INC(traces_executed); \
390-
jit_func jitted = (EXECUTOR)->jit_code; \
387+
_PyExecutorObject *_executor = (EXECUTOR); \
388+
jit_func jitted = _executor->jit_code; \
389+
/* Keep the shim frame alive via the executor: */ \
390+
Py_INCREF(_executor); \
391391
next_instr = jitted(frame, stack_pointer, tstate); \
392-
Py_DECREF(tstate->previous_executor); \
393-
tstate->previous_executor = NULL; \
392+
Py_DECREF(_executor); \
393+
Py_CLEAR(tstate->previous_executor); \
394394
frame = tstate->current_frame; \
395+
stack_pointer = _PyFrame_GetStackPointer(frame); \
395396
if (next_instr == NULL) { \
396397
next_instr = frame->instr_ptr; \
397-
stack_pointer = _PyFrame_GetStackPointer(frame); \
398398
goto error; \
399399
} \
400-
stack_pointer = _PyFrame_GetStackPointer(frame); \
401400
DISPATCH(); \
402401
} while (0)
403402
#else
@@ -410,24 +409,25 @@ do { \
410409
} while (0)
411410
#endif
412411

413-
#define GOTO_TIER_ONE(TARGET) \
414-
do { \
415-
Py_DECREF(tstate->previous_executor); \
416-
tstate->previous_executor = NULL; \
417-
next_instr = target; \
418-
DISPATCH(); \
412+
#define GOTO_TIER_ONE(TARGET) \
413+
do { \
414+
next_instr = (TARGET); \
415+
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \
416+
Py_CLEAR(tstate->previous_executor); \
417+
if (next_instr == NULL) { \
418+
next_instr = frame->instr_ptr; \
419+
goto error; \
420+
} \
421+
DISPATCH(); \
419422
} while (0)
420423

421-
#define CURRENT_OPARG() (next_uop[-1].oparg)
422-
424+
#define CURRENT_OPARG() (next_uop[-1].oparg)
423425
#define CURRENT_OPERAND0() (next_uop[-1].operand0)
424426
#define CURRENT_OPERAND1() (next_uop[-1].operand1)
427+
#define CURRENT_TARGET() (next_uop[-1].target)
425428

426429
#define JUMP_TO_JUMP_TARGET() goto jump_to_jump_target
427430
#define JUMP_TO_ERROR() goto jump_to_error_target
428-
#define GOTO_UNWIND() goto error_tier_two
429-
#define EXIT_TO_TIER1() goto exit_to_tier1
430-
#define EXIT_TO_TIER1_DYNAMIC() goto exit_to_tier1_dynamic;
431431

432432
/* Stackref macros */
433433

0 commit comments

Comments
 (0)