mirror of
https://github.com/python/cpython.git
synced 2025-10-17 04:08:28 +00:00
GH-104584: Fix ENTER_EXECUTOR (GH-106141)
* Check eval-breaker in ENTER_EXECUTOR. * Make sure that frame->prev_instr is set before entering executor.
This commit is contained in:
parent
7f4c8121db
commit
e5862113dd
8 changed files with 272 additions and 269 deletions
|
@ -152,6 +152,8 @@ extern struct _PyInterpreterFrame* _PyEval_GetFrame(void);
|
||||||
|
|
||||||
extern PyObject* _Py_MakeCoro(PyFunctionObject *func);
|
extern PyObject* _Py_MakeCoro(PyFunctionObject *func);
|
||||||
|
|
||||||
|
/* Handle signals, pending calls, GIL drop request
|
||||||
|
and asynchronous exception */
|
||||||
extern int _Py_HandlePending(PyThreadState *tstate);
|
extern int _Py_HandlePending(PyThreadState *tstate);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -141,8 +141,8 @@ dummy_func(
|
||||||
ERROR_IF(err, error);
|
ERROR_IF(err, error);
|
||||||
next_instr--;
|
next_instr--;
|
||||||
}
|
}
|
||||||
else if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) {
|
else if (oparg < 2) {
|
||||||
goto handle_eval_breaker;
|
CHECK_EVAL_BREAKER();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +158,9 @@ dummy_func(
|
||||||
next_instr--;
|
next_instr--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (oparg < 2) {
|
||||||
|
CHECK_EVAL_BREAKER();
|
||||||
|
}
|
||||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||||
int err = _Py_call_instrumentation(
|
int err = _Py_call_instrumentation(
|
||||||
tstate, oparg > 0, frame, next_instr-1);
|
tstate, oparg > 0, frame, next_instr-1);
|
||||||
|
@ -168,9 +171,6 @@ dummy_func(
|
||||||
next_instr = frame->prev_instr;
|
next_instr = frame->prev_instr;
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) {
|
|
||||||
goto handle_eval_breaker;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2223,6 +2223,7 @@ dummy_func(
|
||||||
}
|
}
|
||||||
|
|
||||||
inst(JUMP_BACKWARD, (--)) {
|
inst(JUMP_BACKWARD, (--)) {
|
||||||
|
CHECK_EVAL_BREAKER();
|
||||||
_Py_CODEUNIT *here = next_instr - 1;
|
_Py_CODEUNIT *here = next_instr - 1;
|
||||||
assert(oparg <= INSTR_OFFSET());
|
assert(oparg <= INSTR_OFFSET());
|
||||||
JUMPBY(1-oparg);
|
JUMPBY(1-oparg);
|
||||||
|
@ -2240,7 +2241,6 @@ dummy_func(
|
||||||
goto resume_frame;
|
goto resume_frame;
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_SPECIALIZATION */
|
#endif /* ENABLE_SPECIALIZATION */
|
||||||
CHECK_EVAL_BREAKER();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudo(JUMP) = {
|
pseudo(JUMP) = {
|
||||||
|
@ -2254,8 +2254,13 @@ dummy_func(
|
||||||
};
|
};
|
||||||
|
|
||||||
inst(ENTER_EXECUTOR, (--)) {
|
inst(ENTER_EXECUTOR, (--)) {
|
||||||
|
CHECK_EVAL_BREAKER();
|
||||||
|
|
||||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||||
_PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255];
|
_PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255];
|
||||||
|
int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00);
|
||||||
|
JUMPBY(1-original_oparg);
|
||||||
|
frame->prev_instr = next_instr - 1;
|
||||||
Py_INCREF(executor);
|
Py_INCREF(executor);
|
||||||
frame = executor->execute(executor, frame, stack_pointer);
|
frame = executor->execute(executor, frame, stack_pointer);
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
|
@ -3570,8 +3575,8 @@ dummy_func(
|
||||||
}
|
}
|
||||||
|
|
||||||
inst(INSTRUMENTED_JUMP_BACKWARD, ( -- )) {
|
inst(INSTRUMENTED_JUMP_BACKWARD, ( -- )) {
|
||||||
INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP);
|
|
||||||
CHECK_EVAL_BREAKER();
|
CHECK_EVAL_BREAKER();
|
||||||
|
INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) {
|
inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) {
|
||||||
|
|
|
@ -763,68 +763,6 @@ resume_frame:
|
||||||
|
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
|
||||||
handle_eval_breaker:
|
|
||||||
|
|
||||||
/* Do periodic things, like check for signals and async I/0.
|
|
||||||
* We need to do reasonably frequently, but not too frequently.
|
|
||||||
* All loops should include a check of the eval breaker.
|
|
||||||
* We also check on return from any builtin function.
|
|
||||||
*
|
|
||||||
* ## More Details ###
|
|
||||||
*
|
|
||||||
* The eval loop (this function) normally executes the instructions
|
|
||||||
* of a code object sequentially. However, the runtime supports a
|
|
||||||
* number of out-of-band execution scenarios that may pause that
|
|
||||||
* sequential execution long enough to do that out-of-band work
|
|
||||||
* in the current thread using the current PyThreadState.
|
|
||||||
*
|
|
||||||
* The scenarios include:
|
|
||||||
*
|
|
||||||
* - cyclic garbage collection
|
|
||||||
* - GIL drop requests
|
|
||||||
* - "async" exceptions
|
|
||||||
* - "pending calls" (some only in the main thread)
|
|
||||||
* - signal handling (only in the main thread)
|
|
||||||
*
|
|
||||||
* When the need for one of the above is detected, the eval loop
|
|
||||||
* pauses long enough to handle the detected case. Then, if doing
|
|
||||||
* so didn't trigger an exception, the eval loop resumes executing
|
|
||||||
* the sequential instructions.
|
|
||||||
*
|
|
||||||
* To make this work, the eval loop periodically checks if any
|
|
||||||
* of the above needs to happen. The individual checks can be
|
|
||||||
* expensive if computed each time, so a while back we switched
|
|
||||||
* to using pre-computed, per-interpreter variables for the checks,
|
|
||||||
* and later consolidated that to a single "eval breaker" variable
|
|
||||||
* (now a PyInterpreterState field).
|
|
||||||
*
|
|
||||||
* For the longest time, the eval breaker check would happen
|
|
||||||
* frequently, every 5 or so times through the loop, regardless
|
|
||||||
* of what instruction ran last or what would run next. Then, in
|
|
||||||
* early 2021 (gh-18334, commit 4958f5d), we switched to checking
|
|
||||||
* the eval breaker less frequently, by hard-coding the check to
|
|
||||||
* specific places in the eval loop (e.g. certain instructions).
|
|
||||||
* The intent then was to check after returning from calls
|
|
||||||
* and on the back edges of loops.
|
|
||||||
*
|
|
||||||
* In addition to being more efficient, that approach keeps
|
|
||||||
* the eval loop from running arbitrary code between instructions
|
|
||||||
* that don't handle that well. (See gh-74174.)
|
|
||||||
*
|
|
||||||
* Currently, the eval breaker check happens here at the
|
|
||||||
* "handle_eval_breaker" label. Some instructions come here
|
|
||||||
* explicitly (goto) and some indirectly. Notably, the check
|
|
||||||
* happens on back edges in the control flow graph, which
|
|
||||||
* pretty much applies to all loops and most calls.
|
|
||||||
* (See bytecodes.c for exact information.)
|
|
||||||
*
|
|
||||||
* One consequence of this approach is that it might not be obvious
|
|
||||||
* how to force any specific thread to pick up the eval breaker,
|
|
||||||
* or for any specific thread to not pick it up. Mostly this
|
|
||||||
* involves judicious uses of locks and careful ordering of code,
|
|
||||||
* while avoiding code that might trigger the eval breaker
|
|
||||||
* until so desired.
|
|
||||||
*/
|
|
||||||
if (_Py_HandlePending(tstate) != 0) {
|
if (_Py_HandlePending(tstate) != 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -2796,13 +2734,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
_PyUOpExecutorObject *self = (_PyUOpExecutorObject *)executor;
|
_PyUOpExecutorObject *self = (_PyUOpExecutorObject *)executor;
|
||||||
|
|
||||||
// Equivalent to CHECK_EVAL_BREAKER()
|
CHECK_EVAL_BREAKER();
|
||||||
_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY();
|
|
||||||
if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker)) {
|
|
||||||
if (_Py_HandlePending(tstate) != 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OBJECT_STAT_INC(optimization_traces_executed);
|
OBJECT_STAT_INC(optimization_traces_executed);
|
||||||
_Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
|
_Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
|
||||||
|
|
|
@ -1052,8 +1052,65 @@ _PyEval_FiniState(struct _ceval_state *ceval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle signals, pending calls, GIL drop request
|
|
||||||
and asynchronous exception */
|
/* Do periodic things, like check for signals and async I/0.
|
||||||
|
* We need to do reasonably frequently, but not too frequently.
|
||||||
|
* All loops should include a check of the eval breaker.
|
||||||
|
* We also check on return from any builtin function.
|
||||||
|
*
|
||||||
|
* ## More Details ###
|
||||||
|
*
|
||||||
|
* The eval loop (this function) normally executes the instructions
|
||||||
|
* of a code object sequentially. However, the runtime supports a
|
||||||
|
* number of out-of-band execution scenarios that may pause that
|
||||||
|
* sequential execution long enough to do that out-of-band work
|
||||||
|
* in the current thread using the current PyThreadState.
|
||||||
|
*
|
||||||
|
* The scenarios include:
|
||||||
|
*
|
||||||
|
* - cyclic garbage collection
|
||||||
|
* - GIL drop requests
|
||||||
|
* - "async" exceptions
|
||||||
|
* - "pending calls" (some only in the main thread)
|
||||||
|
* - signal handling (only in the main thread)
|
||||||
|
*
|
||||||
|
* When the need for one of the above is detected, the eval loop
|
||||||
|
* pauses long enough to handle the detected case. Then, if doing
|
||||||
|
* so didn't trigger an exception, the eval loop resumes executing
|
||||||
|
* the sequential instructions.
|
||||||
|
*
|
||||||
|
* To make this work, the eval loop periodically checks if any
|
||||||
|
* of the above needs to happen. The individual checks can be
|
||||||
|
* expensive if computed each time, so a while back we switched
|
||||||
|
* to using pre-computed, per-interpreter variables for the checks,
|
||||||
|
* and later consolidated that to a single "eval breaker" variable
|
||||||
|
* (now a PyInterpreterState field).
|
||||||
|
*
|
||||||
|
* For the longest time, the eval breaker check would happen
|
||||||
|
* frequently, every 5 or so times through the loop, regardless
|
||||||
|
* of what instruction ran last or what would run next. Then, in
|
||||||
|
* early 2021 (gh-18334, commit 4958f5d), we switched to checking
|
||||||
|
* the eval breaker less frequently, by hard-coding the check to
|
||||||
|
* specific places in the eval loop (e.g. certain instructions).
|
||||||
|
* The intent then was to check after returning from calls
|
||||||
|
* and on the back edges of loops.
|
||||||
|
*
|
||||||
|
* In addition to being more efficient, that approach keeps
|
||||||
|
* the eval loop from running arbitrary code between instructions
|
||||||
|
* that don't handle that well. (See gh-74174.)
|
||||||
|
*
|
||||||
|
* Currently, the eval breaker check happens on back edges in
|
||||||
|
* the control flow graph, which pretty much applies to all loops,
|
||||||
|
* and most calls.
|
||||||
|
* (See bytecodes.c for exact information.)
|
||||||
|
*
|
||||||
|
* One consequence of this approach is that it might not be obvious
|
||||||
|
* how to force any specific thread to pick up the eval breaker,
|
||||||
|
* or for any specific thread to not pick it up. Mostly this
|
||||||
|
* involves judicious uses of locks and careful ordering of code,
|
||||||
|
* while avoiding code that might trigger the eval breaker
|
||||||
|
* until so desired.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
_Py_HandlePending(PyThreadState *tstate)
|
_Py_HandlePending(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
|
|
|
@ -117,7 +117,9 @@
|
||||||
#define CHECK_EVAL_BREAKER() \
|
#define CHECK_EVAL_BREAKER() \
|
||||||
_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \
|
_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \
|
||||||
if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker)) { \
|
if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker)) { \
|
||||||
goto handle_eval_breaker; \
|
if (_Py_HandlePending(tstate) != 0) { \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
44
Python/executor_cases.c.h
generated
44
Python/executor_cases.c.h
generated
|
@ -1629,7 +1629,7 @@
|
||||||
case GET_LEN: {
|
case GET_LEN: {
|
||||||
PyObject *obj = stack_pointer[-1];
|
PyObject *obj = stack_pointer[-1];
|
||||||
PyObject *len_o;
|
PyObject *len_o;
|
||||||
#line 2304 "Python/bytecodes.c"
|
#line 2309 "Python/bytecodes.c"
|
||||||
// PUSH(len(TOS))
|
// PUSH(len(TOS))
|
||||||
Py_ssize_t len_i = PyObject_Length(obj);
|
Py_ssize_t len_i = PyObject_Length(obj);
|
||||||
if (len_i < 0) goto error;
|
if (len_i < 0) goto error;
|
||||||
|
@ -1646,7 +1646,7 @@
|
||||||
PyObject *type = stack_pointer[-2];
|
PyObject *type = stack_pointer[-2];
|
||||||
PyObject *subject = stack_pointer[-3];
|
PyObject *subject = stack_pointer[-3];
|
||||||
PyObject *attrs;
|
PyObject *attrs;
|
||||||
#line 2312 "Python/bytecodes.c"
|
#line 2317 "Python/bytecodes.c"
|
||||||
// Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or
|
// Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or
|
||||||
// None on failure.
|
// None on failure.
|
||||||
assert(PyTuple_CheckExact(names));
|
assert(PyTuple_CheckExact(names));
|
||||||
|
@ -1655,7 +1655,7 @@
|
||||||
Py_DECREF(subject);
|
Py_DECREF(subject);
|
||||||
Py_DECREF(type);
|
Py_DECREF(type);
|
||||||
Py_DECREF(names);
|
Py_DECREF(names);
|
||||||
#line 2317 "Python/bytecodes.c"
|
#line 2322 "Python/bytecodes.c"
|
||||||
if (attrs) {
|
if (attrs) {
|
||||||
assert(PyTuple_CheckExact(attrs)); // Success!
|
assert(PyTuple_CheckExact(attrs)); // Success!
|
||||||
}
|
}
|
||||||
|
@ -1672,7 +1672,7 @@
|
||||||
case MATCH_MAPPING: {
|
case MATCH_MAPPING: {
|
||||||
PyObject *subject = stack_pointer[-1];
|
PyObject *subject = stack_pointer[-1];
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
#line 2327 "Python/bytecodes.c"
|
#line 2332 "Python/bytecodes.c"
|
||||||
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING;
|
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING;
|
||||||
res = match ? Py_True : Py_False;
|
res = match ? Py_True : Py_False;
|
||||||
#line 1679 "Python/executor_cases.c.h"
|
#line 1679 "Python/executor_cases.c.h"
|
||||||
|
@ -1684,7 +1684,7 @@
|
||||||
case MATCH_SEQUENCE: {
|
case MATCH_SEQUENCE: {
|
||||||
PyObject *subject = stack_pointer[-1];
|
PyObject *subject = stack_pointer[-1];
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
#line 2332 "Python/bytecodes.c"
|
#line 2337 "Python/bytecodes.c"
|
||||||
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE;
|
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE;
|
||||||
res = match ? Py_True : Py_False;
|
res = match ? Py_True : Py_False;
|
||||||
#line 1691 "Python/executor_cases.c.h"
|
#line 1691 "Python/executor_cases.c.h"
|
||||||
|
@ -1697,7 +1697,7 @@
|
||||||
PyObject *keys = stack_pointer[-1];
|
PyObject *keys = stack_pointer[-1];
|
||||||
PyObject *subject = stack_pointer[-2];
|
PyObject *subject = stack_pointer[-2];
|
||||||
PyObject *values_or_none;
|
PyObject *values_or_none;
|
||||||
#line 2337 "Python/bytecodes.c"
|
#line 2342 "Python/bytecodes.c"
|
||||||
// On successful match, PUSH(values). Otherwise, PUSH(None).
|
// On successful match, PUSH(values). Otherwise, PUSH(None).
|
||||||
values_or_none = match_keys(tstate, subject, keys);
|
values_or_none = match_keys(tstate, subject, keys);
|
||||||
if (values_or_none == NULL) goto error;
|
if (values_or_none == NULL) goto error;
|
||||||
|
@ -1710,12 +1710,12 @@
|
||||||
case GET_ITER: {
|
case GET_ITER: {
|
||||||
PyObject *iterable = stack_pointer[-1];
|
PyObject *iterable = stack_pointer[-1];
|
||||||
PyObject *iter;
|
PyObject *iter;
|
||||||
#line 2343 "Python/bytecodes.c"
|
#line 2348 "Python/bytecodes.c"
|
||||||
/* before: [obj]; after [getiter(obj)] */
|
/* before: [obj]; after [getiter(obj)] */
|
||||||
iter = PyObject_GetIter(iterable);
|
iter = PyObject_GetIter(iterable);
|
||||||
#line 1717 "Python/executor_cases.c.h"
|
#line 1717 "Python/executor_cases.c.h"
|
||||||
Py_DECREF(iterable);
|
Py_DECREF(iterable);
|
||||||
#line 2346 "Python/bytecodes.c"
|
#line 2351 "Python/bytecodes.c"
|
||||||
if (iter == NULL) goto pop_1_error;
|
if (iter == NULL) goto pop_1_error;
|
||||||
#line 1721 "Python/executor_cases.c.h"
|
#line 1721 "Python/executor_cases.c.h"
|
||||||
stack_pointer[-1] = iter;
|
stack_pointer[-1] = iter;
|
||||||
|
@ -1725,7 +1725,7 @@
|
||||||
case GET_YIELD_FROM_ITER: {
|
case GET_YIELD_FROM_ITER: {
|
||||||
PyObject *iterable = stack_pointer[-1];
|
PyObject *iterable = stack_pointer[-1];
|
||||||
PyObject *iter;
|
PyObject *iter;
|
||||||
#line 2350 "Python/bytecodes.c"
|
#line 2355 "Python/bytecodes.c"
|
||||||
/* before: [obj]; after [getiter(obj)] */
|
/* before: [obj]; after [getiter(obj)] */
|
||||||
if (PyCoro_CheckExact(iterable)) {
|
if (PyCoro_CheckExact(iterable)) {
|
||||||
/* `iterable` is a coroutine */
|
/* `iterable` is a coroutine */
|
||||||
|
@ -1750,7 +1750,7 @@
|
||||||
}
|
}
|
||||||
#line 1752 "Python/executor_cases.c.h"
|
#line 1752 "Python/executor_cases.c.h"
|
||||||
Py_DECREF(iterable);
|
Py_DECREF(iterable);
|
||||||
#line 2373 "Python/bytecodes.c"
|
#line 2378 "Python/bytecodes.c"
|
||||||
}
|
}
|
||||||
#line 1756 "Python/executor_cases.c.h"
|
#line 1756 "Python/executor_cases.c.h"
|
||||||
stack_pointer[-1] = iter;
|
stack_pointer[-1] = iter;
|
||||||
|
@ -1762,7 +1762,7 @@
|
||||||
PyObject *lasti = stack_pointer[-3];
|
PyObject *lasti = stack_pointer[-3];
|
||||||
PyObject *exit_func = stack_pointer[-4];
|
PyObject *exit_func = stack_pointer[-4];
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
#line 2605 "Python/bytecodes.c"
|
#line 2610 "Python/bytecodes.c"
|
||||||
/* At the top of the stack are 4 values:
|
/* At the top of the stack are 4 values:
|
||||||
- val: TOP = exc_info()
|
- val: TOP = exc_info()
|
||||||
- unused: SECOND = previous exception
|
- unused: SECOND = previous exception
|
||||||
|
@ -1792,7 +1792,7 @@
|
||||||
case PUSH_EXC_INFO: {
|
case PUSH_EXC_INFO: {
|
||||||
PyObject *new_exc = stack_pointer[-1];
|
PyObject *new_exc = stack_pointer[-1];
|
||||||
PyObject *prev_exc;
|
PyObject *prev_exc;
|
||||||
#line 2644 "Python/bytecodes.c"
|
#line 2649 "Python/bytecodes.c"
|
||||||
_PyErr_StackItem *exc_info = tstate->exc_info;
|
_PyErr_StackItem *exc_info = tstate->exc_info;
|
||||||
if (exc_info->exc_value != NULL) {
|
if (exc_info->exc_value != NULL) {
|
||||||
prev_exc = exc_info->exc_value;
|
prev_exc = exc_info->exc_value;
|
||||||
|
@ -1811,7 +1811,7 @@
|
||||||
|
|
||||||
case EXIT_INIT_CHECK: {
|
case EXIT_INIT_CHECK: {
|
||||||
PyObject *should_be_none = stack_pointer[-1];
|
PyObject *should_be_none = stack_pointer[-1];
|
||||||
#line 3013 "Python/bytecodes.c"
|
#line 3018 "Python/bytecodes.c"
|
||||||
assert(STACK_LEVEL() == 2);
|
assert(STACK_LEVEL() == 2);
|
||||||
if (should_be_none != Py_None) {
|
if (should_be_none != Py_None) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
@ -1827,7 +1827,7 @@
|
||||||
case MAKE_FUNCTION: {
|
case MAKE_FUNCTION: {
|
||||||
PyObject *codeobj = stack_pointer[-1];
|
PyObject *codeobj = stack_pointer[-1];
|
||||||
PyObject *func;
|
PyObject *func;
|
||||||
#line 3427 "Python/bytecodes.c"
|
#line 3432 "Python/bytecodes.c"
|
||||||
|
|
||||||
PyFunctionObject *func_obj = (PyFunctionObject *)
|
PyFunctionObject *func_obj = (PyFunctionObject *)
|
||||||
PyFunction_New(codeobj, GLOBALS());
|
PyFunction_New(codeobj, GLOBALS());
|
||||||
|
@ -1847,7 +1847,7 @@
|
||||||
case SET_FUNCTION_ATTRIBUTE: {
|
case SET_FUNCTION_ATTRIBUTE: {
|
||||||
PyObject *func = stack_pointer[-1];
|
PyObject *func = stack_pointer[-1];
|
||||||
PyObject *attr = stack_pointer[-2];
|
PyObject *attr = stack_pointer[-2];
|
||||||
#line 3441 "Python/bytecodes.c"
|
#line 3446 "Python/bytecodes.c"
|
||||||
assert(PyFunction_Check(func));
|
assert(PyFunction_Check(func));
|
||||||
PyFunctionObject *func_obj = (PyFunctionObject *)func;
|
PyFunctionObject *func_obj = (PyFunctionObject *)func;
|
||||||
switch(oparg) {
|
switch(oparg) {
|
||||||
|
@ -1883,13 +1883,13 @@
|
||||||
PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))];
|
PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))];
|
||||||
PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))];
|
PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))];
|
||||||
PyObject *slice;
|
PyObject *slice;
|
||||||
#line 3491 "Python/bytecodes.c"
|
#line 3496 "Python/bytecodes.c"
|
||||||
slice = PySlice_New(start, stop, step);
|
slice = PySlice_New(start, stop, step);
|
||||||
#line 1889 "Python/executor_cases.c.h"
|
#line 1889 "Python/executor_cases.c.h"
|
||||||
Py_DECREF(start);
|
Py_DECREF(start);
|
||||||
Py_DECREF(stop);
|
Py_DECREF(stop);
|
||||||
Py_XDECREF(step);
|
Py_XDECREF(step);
|
||||||
#line 3493 "Python/bytecodes.c"
|
#line 3498 "Python/bytecodes.c"
|
||||||
if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; }
|
if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; }
|
||||||
#line 1895 "Python/executor_cases.c.h"
|
#line 1895 "Python/executor_cases.c.h"
|
||||||
STACK_SHRINK(((oparg == 3) ? 1 : 0));
|
STACK_SHRINK(((oparg == 3) ? 1 : 0));
|
||||||
|
@ -1901,7 +1901,7 @@
|
||||||
case CONVERT_VALUE: {
|
case CONVERT_VALUE: {
|
||||||
PyObject *value = stack_pointer[-1];
|
PyObject *value = stack_pointer[-1];
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
#line 3497 "Python/bytecodes.c"
|
#line 3502 "Python/bytecodes.c"
|
||||||
convertion_func_ptr conv_fn;
|
convertion_func_ptr conv_fn;
|
||||||
assert(oparg >= FVC_STR && oparg <= FVC_ASCII);
|
assert(oparg >= FVC_STR && oparg <= FVC_ASCII);
|
||||||
conv_fn = CONVERSION_FUNCTIONS[oparg];
|
conv_fn = CONVERSION_FUNCTIONS[oparg];
|
||||||
|
@ -1916,7 +1916,7 @@
|
||||||
case FORMAT_SIMPLE: {
|
case FORMAT_SIMPLE: {
|
||||||
PyObject *value = stack_pointer[-1];
|
PyObject *value = stack_pointer[-1];
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
#line 3506 "Python/bytecodes.c"
|
#line 3511 "Python/bytecodes.c"
|
||||||
/* If value is a unicode object, then we know the result
|
/* If value is a unicode object, then we know the result
|
||||||
* of format(value) is value itself. */
|
* of format(value) is value itself. */
|
||||||
if (!PyUnicode_CheckExact(value)) {
|
if (!PyUnicode_CheckExact(value)) {
|
||||||
|
@ -1936,7 +1936,7 @@
|
||||||
PyObject *fmt_spec = stack_pointer[-1];
|
PyObject *fmt_spec = stack_pointer[-1];
|
||||||
PyObject *value = stack_pointer[-2];
|
PyObject *value = stack_pointer[-2];
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
#line 3519 "Python/bytecodes.c"
|
#line 3524 "Python/bytecodes.c"
|
||||||
res = PyObject_Format(value, fmt_spec);
|
res = PyObject_Format(value, fmt_spec);
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
Py_DECREF(fmt_spec);
|
Py_DECREF(fmt_spec);
|
||||||
|
@ -1950,7 +1950,7 @@
|
||||||
case COPY: {
|
case COPY: {
|
||||||
PyObject *bottom = stack_pointer[-(1 + (oparg-1))];
|
PyObject *bottom = stack_pointer[-(1 + (oparg-1))];
|
||||||
PyObject *top;
|
PyObject *top;
|
||||||
#line 3526 "Python/bytecodes.c"
|
#line 3531 "Python/bytecodes.c"
|
||||||
assert(oparg > 0);
|
assert(oparg > 0);
|
||||||
top = Py_NewRef(bottom);
|
top = Py_NewRef(bottom);
|
||||||
#line 1957 "Python/executor_cases.c.h"
|
#line 1957 "Python/executor_cases.c.h"
|
||||||
|
@ -1962,7 +1962,7 @@
|
||||||
case SWAP: {
|
case SWAP: {
|
||||||
PyObject *top = stack_pointer[-1];
|
PyObject *top = stack_pointer[-1];
|
||||||
PyObject *bottom = stack_pointer[-(2 + (oparg-2))];
|
PyObject *bottom = stack_pointer[-(2 + (oparg-2))];
|
||||||
#line 3551 "Python/bytecodes.c"
|
#line 3556 "Python/bytecodes.c"
|
||||||
assert(oparg >= 2);
|
assert(oparg >= 2);
|
||||||
#line 1968 "Python/executor_cases.c.h"
|
#line 1968 "Python/executor_cases.c.h"
|
||||||
stack_pointer[-1] = bottom;
|
stack_pointer[-1] = bottom;
|
||||||
|
|
339
Python/generated_cases.c.h
generated
339
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
2
Python/opcode_metadata.h
generated
2
Python/opcode_metadata.h
generated
|
@ -1087,7 +1087,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
|
||||||
[JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
[JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
[JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
[ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
[ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
[POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
[POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
[POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue