summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorBrandt Bucher <brandtbucher@microsoft.com>2024-07-18 21:24:58 (GMT)
committerGitHub <noreply@github.com>2024-07-18 21:24:58 (GMT)
commit7b36b67b1e585c541b418eaa190c56e73f9a2d87 (patch)
tree140da7113d0f7c2ebcfb1fd6ff53ec01fd0aba6d /Python
parent7dd52b63cef3ff60868dea510ef7a9adcc6611cc (diff)
downloadcpython-7b36b67b1e585c541b418eaa190c56e73f9a2d87.zip
cpython-7b36b67b1e585c541b418eaa190c56e73f9a2d87.tar.gz
cpython-7b36b67b1e585c541b418eaa190c56e73f9a2d87.tar.bz2
GH-118093: Add tier two support to several instructions (GH-121884)
Diffstat (limited to 'Python')
-rw-r--r--Python/bytecodes.c58
-rw-r--r--Python/ceval.c11
-rw-r--r--Python/executor_cases.c.h163
-rw-r--r--Python/generated_cases.c.h90
-rw-r--r--Python/optimizer.c18
-rw-r--r--Python/optimizer_bytecodes.c5
-rw-r--r--Python/optimizer_cases.c.h48
7 files changed, 311 insertions, 82 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 142f97d..4800450 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1154,23 +1154,26 @@ dummy_func(
macro(SEND) = _SPECIALIZE_SEND + _SEND;
- inst(SEND_GEN, (unused/1, receiver, v -- receiver, unused)) {
- DEOPT_IF(tstate->interp->eval_frame);
+ op(_SEND_GEN_FRAME, (receiver, v -- receiver, gen_frame: _PyInterpreterFrame *)) {
PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver);
DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type);
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING);
STAT_INC(SEND, hit);
- _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
- STACK_SHRINK(1);
+ gen_frame = &gen->gi_iframe;
_PyFrame_StackPush(gen_frame, v);
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
- assert(next_instr - this_instr + oparg <= UINT16_MAX);
- frame->return_offset = (uint16_t)(next_instr - this_instr + oparg);
- DISPATCH_INLINED(gen_frame);
+ assert(1 + INLINE_CACHE_ENTRIES_SEND + oparg <= UINT16_MAX);
+ frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_SEND + oparg);
}
+ macro(SEND_GEN) =
+ unused/1 +
+ _CHECK_PEP_523 +
+ _SEND_GEN_FRAME +
+ _PUSH_FRAME;
+
inst(INSTRUMENTED_YIELD_VALUE, (retval -- unused)) {
assert(frame != &entry_frame);
frame->instr_ptr = next_instr;
@@ -1547,22 +1550,16 @@ dummy_func(
ERROR_IF(true, error);
}
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
- if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v_o) < 0) {
- ERROR_NO_POP();
- }
+ ERROR_IF(PyMapping_GetOptionalItem(mod_or_class_dict, name, &v_o) < 0, error);
if (v_o == NULL) {
- if (PyDict_GetItemRef(GLOBALS(), name, &v_o) < 0) {
- ERROR_NO_POP();
- }
+ ERROR_IF(PyDict_GetItemRef(GLOBALS(), name, &v_o) < 0, error);
if (v_o == NULL) {
- if (PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0) {
- ERROR_NO_POP();
- }
+ ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0, error);
if (v_o == NULL) {
_PyEval_FormatExcCheckArg(
tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
- ERROR_NO_POP();
+ ERROR_IF(true, error);
}
}
}
@@ -1828,7 +1825,8 @@ dummy_func(
inst(BUILD_SET, (values[oparg] -- set)) {
PyObject *set_o = PySet_New(NULL);
if (set_o == NULL) {
- ERROR_NO_POP();
+ DECREF_INPUTS();
+ ERROR_IF(true, error);
}
int err = 0;
for (int i = 0; i < oparg; i++) {
@@ -2616,9 +2614,9 @@ dummy_func(
b = res ? PyStackRef_True : PyStackRef_False;
}
- tier1 inst(IMPORT_NAME, (level, fromlist -- res)) {
+ inst(IMPORT_NAME, (level, fromlist -- res)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
- PyObject *res_o = import_name(tstate, frame, name,
+ PyObject *res_o = _PyEval_ImportName(tstate, frame, name,
PyStackRef_AsPyObjectBorrow(fromlist),
PyStackRef_AsPyObjectBorrow(level));
DECREF_INPUTS();
@@ -2626,9 +2624,9 @@ dummy_func(
res = PyStackRef_FromPyObjectSteal(res_o);
}
- tier1 inst(IMPORT_FROM, (from -- from, res)) {
+ inst(IMPORT_FROM, (from -- from, res)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
- PyObject *res_o = import_from(tstate, PyStackRef_AsPyObjectBorrow(from), name);
+ PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name);
ERROR_IF(res_o == NULL, error);
res = PyStackRef_FromPyObjectSteal(res_o);
}
@@ -2898,7 +2896,7 @@ dummy_func(
}
/* iterator ended normally */
/* The translator sets the deopt target just past the matching END_FOR */
- DEOPT_IF(true);
+ EXIT_IF(true);
}
next = PyStackRef_FromPyObjectSteal(next_o);
// Common case: no jump, leave it to the code generator
@@ -3942,7 +3940,7 @@ dummy_func(
}
// This is secretly a super-instruction
- tier1 inst(CALL_LIST_APPEND, (unused/1, unused/2, callable, self, arg -- unused)) {
+ inst(CALL_LIST_APPEND, (unused/1, unused/2, callable, self, arg -- )) {
assert(oparg == 1);
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
PyObject *self_o = PyStackRef_AsPyObjectBorrow(self);
@@ -3952,16 +3950,16 @@ dummy_func(
assert(self_o != NULL);
DEOPT_IF(!PyList_Check(self_o));
STAT_INC(CALL, hit);
- if (_PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)) < 0) {
- goto pop_1_error; // Since arg is DECREF'ed already
- }
+ int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg));
PyStackRef_CLOSE(self);
PyStackRef_CLOSE(callable);
- STACK_SHRINK(3);
- // Skip POP_TOP
+ ERROR_IF(err, error);
+ #if TIER_ONE
+ // Skip the following POP_TOP. This is done here in tier one, and
+ // during trace projection in tier two:
assert(next_instr->op.code == POP_TOP);
SKIP_OVER(1);
- DISPATCH();
+ #endif
}
op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res)) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 97d4b82..1e911d3 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -245,9 +245,6 @@ static void monitor_throw(PyThreadState *tstate,
_PyInterpreterFrame *frame,
_Py_CODEUNIT *instr);
-static PyObject * import_name(PyThreadState *, _PyInterpreterFrame *,
- PyObject *, PyObject *, PyObject *);
-static PyObject * import_from(PyThreadState *, PyObject *, PyObject *);
static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg);
static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
static _PyInterpreterFrame *
@@ -2727,8 +2724,8 @@ _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi)
return 1;
}
-static PyObject *
-import_name(PyThreadState *tstate, _PyInterpreterFrame *frame,
+PyObject *
+_PyEval_ImportName(PyThreadState *tstate, _PyInterpreterFrame *frame,
PyObject *name, PyObject *fromlist, PyObject *level)
{
PyObject *import_func;
@@ -2766,8 +2763,8 @@ import_name(PyThreadState *tstate, _PyInterpreterFrame *frame,
return res;
}
-static PyObject *
-import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
+PyObject *
+_PyEval_ImportFrom(PyThreadState *tstate, PyObject *v, PyObject *name)
{
PyObject *x;
PyObject *fullmodname, *pkgname, *pkgpath, *pkgname_or_unknown, *errmsg;
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 375e1fb..e9f73f0 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -1227,7 +1227,33 @@
/* _SEND is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */
- /* _SEND_GEN is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */
+ case _SEND_GEN_FRAME: {
+ _PyStackRef v;
+ _PyStackRef receiver;
+ _PyInterpreterFrame *gen_frame;
+ oparg = CURRENT_OPARG();
+ v = stack_pointer[-1];
+ receiver = stack_pointer[-2];
+ PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver);
+ if (Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type) {
+ UOP_STAT_INC(uopcode, miss);
+ JUMP_TO_JUMP_TARGET();
+ }
+ if (gen->gi_frame_state >= FRAME_EXECUTING) {
+ UOP_STAT_INC(uopcode, miss);
+ JUMP_TO_JUMP_TARGET();
+ }
+ STAT_INC(SEND, hit);
+ gen_frame = &gen->gi_iframe;
+ _PyFrame_StackPush(gen_frame, v);
+ gen->gi_frame_state = FRAME_EXECUTING;
+ gen->gi_exc_state.previous_item = tstate->exc_info;
+ tstate->exc_info = &gen->gi_exc_state;
+ assert(1 + INLINE_CACHE_ENTRIES_SEND + oparg <= UINT16_MAX);
+ frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_SEND + oparg);
+ stack_pointer[-1].bits = (uintptr_t)gen_frame;
+ break;
+ }
/* _INSTRUMENTED_YIELD_VALUE is not a viable micro-op for tier 2 because it is instrumented */
@@ -1551,7 +1577,36 @@
/* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 because it has both popping and not-popping errors */
- /* _LOAD_NAME is not a viable micro-op for tier 2 because it has both popping and not-popping errors */
+ case _LOAD_NAME: {
+ _PyStackRef v;
+ oparg = CURRENT_OPARG();
+ PyObject *v_o;
+ PyObject *mod_or_class_dict = LOCALS();
+ if (mod_or_class_dict == NULL) {
+ _PyErr_SetString(tstate, PyExc_SystemError,
+ "no locals found");
+ if (true) JUMP_TO_ERROR();
+ }
+ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
+ if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v_o) < 0) JUMP_TO_ERROR();
+ if (v_o == NULL) {
+ if (PyDict_GetItemRef(GLOBALS(), name, &v_o) < 0) JUMP_TO_ERROR();
+ if (v_o == NULL) {
+ if (PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0) JUMP_TO_ERROR();
+ if (v_o == NULL) {
+ _PyEval_FormatExcCheckArg(
+ tstate, PyExc_NameError,
+ NAME_ERROR_MSG, name);
+ if (true) JUMP_TO_ERROR();
+ }
+ }
+ }
+ v = PyStackRef_FromPyObjectSteal(v_o);
+ stack_pointer[0] = v;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
case _LOAD_GLOBAL: {
_PyStackRef res;
@@ -1890,7 +1945,36 @@
break;
}
- /* _BUILD_SET is not a viable micro-op for tier 2 because it has both popping and not-popping errors */
+ case _BUILD_SET: {
+ _PyStackRef *values;
+ _PyStackRef set;
+ oparg = CURRENT_OPARG();
+ values = &stack_pointer[-oparg];
+ PyObject *set_o = PySet_New(NULL);
+ if (set_o == NULL) {
+ for (int _i = oparg; --_i >= 0;) {
+ PyStackRef_CLOSE(values[_i]);
+ }
+ if (true) JUMP_TO_ERROR();
+ }
+ int err = 0;
+ for (int i = 0; i < oparg; i++) {
+ PyObject *item = PyStackRef_AsPyObjectSteal(values[i]);
+ if (err == 0) {
+ err = PySet_Add(set_o, item);
+ }
+ Py_DECREF(item);
+ }
+ if (err != 0) {
+ Py_DECREF(set_o);
+ if (true) JUMP_TO_ERROR();
+ }
+ set = PyStackRef_FromPyObjectSteal(set_o);
+ stack_pointer[-oparg] = set;
+ stack_pointer += 1 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
case _BUILD_MAP: {
_PyStackRef *values;
@@ -2843,6 +2927,42 @@
break;
}
+ case _IMPORT_NAME: {
+ _PyStackRef fromlist;
+ _PyStackRef level;
+ _PyStackRef res;
+ oparg = CURRENT_OPARG();
+ fromlist = stack_pointer[-1];
+ level = stack_pointer[-2];
+ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
+ PyObject *res_o = _PyEval_ImportName(tstate, frame, name,
+ PyStackRef_AsPyObjectBorrow(fromlist),
+ PyStackRef_AsPyObjectBorrow(level));
+ PyStackRef_CLOSE(level);
+ PyStackRef_CLOSE(fromlist);
+ if (res_o == NULL) JUMP_TO_ERROR();
+ res = PyStackRef_FromPyObjectSteal(res_o);
+ stack_pointer[-2] = res;
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _IMPORT_FROM: {
+ _PyStackRef from;
+ _PyStackRef res;
+ oparg = CURRENT_OPARG();
+ from = stack_pointer[-1];
+ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
+ PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name);
+ if (res_o == NULL) JUMP_TO_ERROR();
+ res = PyStackRef_FromPyObjectSteal(res_o);
+ stack_pointer[0] = res;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
/* _POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 because it is replaced */
/* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 because it is replaced */
@@ -4251,6 +4371,43 @@
break;
}
+ case _CALL_LIST_APPEND: {
+ _PyStackRef arg;
+ _PyStackRef self;
+ _PyStackRef callable;
+ oparg = CURRENT_OPARG();
+ arg = stack_pointer[-1];
+ self = stack_pointer[-2];
+ callable = stack_pointer[-3];
+ assert(oparg == 1);
+ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
+ PyObject *self_o = PyStackRef_AsPyObjectBorrow(self);
+ PyInterpreterState *interp = tstate->interp;
+ if (callable_o != interp->callable_cache.list_append) {
+ UOP_STAT_INC(uopcode, miss);
+ JUMP_TO_JUMP_TARGET();
+ }
+ assert(self_o != NULL);
+ if (!PyList_Check(self_o)) {
+ UOP_STAT_INC(uopcode, miss);
+ JUMP_TO_JUMP_TARGET();
+ }
+ STAT_INC(CALL, hit);
+ int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg));
+ PyStackRef_CLOSE(self);
+ PyStackRef_CLOSE(callable);
+ if (err) JUMP_TO_ERROR();
+ #if TIER_ONE
+ // Skip the following POP_TOP. This is done here in tier one, and
+ // during trace projection in tier two:
+ assert(next_instr->op.code == POP_TOP);
+ SKIP_OVER(1);
+ #endif
+ stack_pointer += -3;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
case _CALL_METHOD_DESCRIPTOR_O: {
_PyStackRef *args;
_PyStackRef self_or_null;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 3822884..585e682 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -688,7 +688,10 @@
values = &stack_pointer[-oparg];
PyObject *set_o = PySet_New(NULL);
if (set_o == NULL) {
- goto error;
+ for (int _i = oparg; --_i >= 0;) {
+ PyStackRef_CLOSE(values[_i]);
+ }
+ if (true) { stack_pointer += -oparg; goto error; }
}
int err = 0;
for (int i = 0; i < oparg; i++) {
@@ -1744,15 +1747,18 @@
assert(self_o != NULL);
DEOPT_IF(!PyList_Check(self_o), CALL);
STAT_INC(CALL, hit);
- if (_PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)) < 0) {
- goto pop_1_error; // Since arg is DECREF'ed already
- }
+ int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg));
PyStackRef_CLOSE(self);
PyStackRef_CLOSE(callable);
- STACK_SHRINK(3);
- // Skip POP_TOP
+ if (err) goto pop_3_error;
+ #if TIER_ONE
+ // Skip the following POP_TOP. This is done here in tier one, and
+ // during trace projection in tier two:
assert(next_instr->op.code == POP_TOP);
SKIP_OVER(1);
+ #endif
+ stack_pointer += -3;
+ assert(WITHIN_STACK_BOUNDS());
DISPATCH();
}
@@ -3488,7 +3494,7 @@
_PyStackRef res;
from = stack_pointer[-1];
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
- PyObject *res_o = import_from(tstate, PyStackRef_AsPyObjectBorrow(from), name);
+ PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name);
if (res_o == NULL) goto error;
res = PyStackRef_FromPyObjectSteal(res_o);
stack_pointer[0] = res;
@@ -3507,7 +3513,7 @@
fromlist = stack_pointer[-1];
level = stack_pointer[-2];
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
- PyObject *res_o = import_name(tstate, frame, name,
+ PyObject *res_o = _PyEval_ImportName(tstate, frame, name,
PyStackRef_AsPyObjectBorrow(fromlist),
PyStackRef_AsPyObjectBorrow(level));
PyStackRef_CLOSE(level);
@@ -4980,22 +4986,16 @@
if (true) goto error;
}
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
- if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v_o) < 0) {
- goto error;
- }
+ if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v_o) < 0) goto error;
if (v_o == NULL) {
- if (PyDict_GetItemRef(GLOBALS(), name, &v_o) < 0) {
- goto error;
- }
+ if (PyDict_GetItemRef(GLOBALS(), name, &v_o) < 0) goto error;
if (v_o == NULL) {
- if (PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0) {
- goto error;
- }
+ if (PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0) goto error;
if (v_o == NULL) {
_PyEval_FormatExcCheckArg(
tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
- goto error;
+ if (true) goto error;
}
}
}
@@ -5806,29 +5806,53 @@
}
TARGET(SEND_GEN) {
- _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr;
+ frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(SEND_GEN);
static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size");
_PyStackRef receiver;
_PyStackRef v;
+ _PyInterpreterFrame *gen_frame;
+ _PyInterpreterFrame *new_frame;
/* Skip 1 cache entry */
+ // _CHECK_PEP_523
+ {
+ DEOPT_IF(tstate->interp->eval_frame, SEND);
+ }
+ // _SEND_GEN_FRAME
v = stack_pointer[-1];
receiver = stack_pointer[-2];
- DEOPT_IF(tstate->interp->eval_frame, SEND);
- PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver);
- DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND);
- DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
- STAT_INC(SEND, hit);
- _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
- STACK_SHRINK(1);
- _PyFrame_StackPush(gen_frame, v);
- gen->gi_frame_state = FRAME_EXECUTING;
- gen->gi_exc_state.previous_item = tstate->exc_info;
- tstate->exc_info = &gen->gi_exc_state;
- assert(next_instr - this_instr + oparg <= UINT16_MAX);
- frame->return_offset = (uint16_t)(next_instr - this_instr + oparg);
- DISPATCH_INLINED(gen_frame);
+ {
+ PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver);
+ DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND);
+ DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
+ STAT_INC(SEND, hit);
+ gen_frame = &gen->gi_iframe;
+ _PyFrame_StackPush(gen_frame, v);
+ gen->gi_frame_state = FRAME_EXECUTING;
+ gen->gi_exc_state.previous_item = tstate->exc_info;
+ tstate->exc_info = &gen->gi_exc_state;
+ assert(1 + INLINE_CACHE_ENTRIES_SEND + oparg <= UINT16_MAX);
+ frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_SEND + oparg);
+ }
+ // _PUSH_FRAME
+ new_frame = gen_frame;
+ {
+ // Write it out explicitly because it's subtly different.
+ // Eventually this should be the only occurrence of this code.
+ assert(tstate->interp->eval_frame == NULL);
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ new_frame->previous = frame;
+ CALL_STAT_INC(inlined_py_calls);
+ frame = tstate->current_frame = new_frame;
+ tstate->py_recursion_remaining--;
+ LOAD_SP();
+ LOAD_IP(0);
+ LLTRACE_RESUME_FRAME();
+ }
+ DISPATCH();
}
TARGET(SETUP_ANNOTATIONS) {
diff --git a/Python/optimizer.c b/Python/optimizer.c
index 561ec4e..a43eed4 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -797,6 +797,13 @@ top: // Jump here after _PUSH_FRAME or likely branches
if (uop == _PUSH_FRAME) {
assert(i + 1 == nuops);
+ if (opcode == FOR_ITER_GEN || opcode == SEND_GEN) {
+ DPRINTF(2, "Bailing due to dynamic target\n");
+ ADD_TO_TRACE(uop, oparg, 0, target);
+ ADD_TO_TRACE(_DYNAMIC_EXIT, 0, 0, 0);
+ goto done;
+ }
+ assert(_PyOpcode_Deopt[opcode] == CALL);
int func_version_offset =
offsetof(_PyCallCache, func_version)/sizeof(_Py_CODEUNIT)
// Add one to account for the actual opcode/oparg pair:
@@ -828,12 +835,6 @@ top: // Jump here after _PUSH_FRAME or likely branches
ADD_TO_TRACE(_EXIT_TRACE, 0, 0, 0);
goto done;
}
- if (opcode == FOR_ITER_GEN) {
- DPRINTF(2, "Bailing due to dynamic target\n");
- ADD_TO_TRACE(uop, oparg, 0, target);
- ADD_TO_TRACE(_DYNAMIC_EXIT, 0, 0, 0);
- goto done;
- }
// Increment IP to the return address
instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + 1;
TRACE_STACK_PUSH();
@@ -886,6 +887,11 @@ top: // Jump here after _PUSH_FRAME or likely branches
instr++;
// Add cache size for opcode
instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]];
+
+ if (opcode == CALL_LIST_APPEND) {
+ assert(instr->op.code == POP_TOP);
+ instr++;
+ }
} // End for (;;)
done:
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index 2ea839f..a506f99 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -658,6 +658,11 @@ dummy_func(void) {
ctx->done = true;
}
+ op(_SEND_GEN_FRAME, ( -- )) {
+ // We are about to hit the end of the trace:
+ ctx->done = true;
+ }
+
op(_CHECK_STACK_SPACE, ( --)) {
assert(corresponding_check_stack == NULL);
corresponding_check_stack = this_instr;
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 978aa91..60cfb21 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -644,7 +644,11 @@
/* _SEND is not a viable micro-op for tier 2 */
- /* _SEND_GEN is not a viable micro-op for tier 2 */
+ case _SEND_GEN_FRAME: {
+ // We are about to hit the end of the trace:
+ ctx->done = true;
+ break;
+ }
/* _INSTRUMENTED_YIELD_VALUE is not a viable micro-op for tier 2 */
@@ -787,7 +791,14 @@
/* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 */
- /* _LOAD_NAME is not a viable micro-op for tier 2 */
+ case _LOAD_NAME: {
+ _Py_UopsSymbol *v;
+ v = sym_new_not_null(ctx);
+ stack_pointer[0] = v;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
case _LOAD_GLOBAL: {
_Py_UopsSymbol *res;
@@ -910,7 +921,14 @@
break;
}
- /* _BUILD_SET is not a viable micro-op for tier 2 */
+ case _BUILD_SET: {
+ _Py_UopsSymbol *set;
+ set = sym_new_not_null(ctx);
+ stack_pointer[-oparg] = set;
+ stack_pointer += 1 - oparg;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
case _BUILD_MAP: {
_Py_UopsSymbol *map;
@@ -1307,6 +1325,24 @@
break;
}
+ case _IMPORT_NAME: {
+ _Py_UopsSymbol *res;
+ res = sym_new_not_null(ctx);
+ stack_pointer[-2] = res;
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _IMPORT_FROM: {
+ _Py_UopsSymbol *res;
+ res = sym_new_not_null(ctx);
+ stack_pointer[0] = res;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
/* _POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 */
/* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */
@@ -1846,6 +1882,12 @@
break;
}
+ case _CALL_LIST_APPEND: {
+ stack_pointer += -3;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
case _CALL_METHOD_DESCRIPTOR_O: {
_Py_UopsSymbol *res;
res = sym_new_not_null(ctx);