summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
Diffstat (limited to 'Python')
-rw-r--r--Python/abstract_interp_cases.c.h10
-rw-r--r--Python/bytecodes.c29
-rw-r--r--Python/executor_cases.c.h26
-rw-r--r--Python/generated_cases.c.h98
4 files changed, 143 insertions, 20 deletions
diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h
index 1b99b92..07e8a71 100644
--- a/Python/abstract_interp_cases.c.h
+++ b/Python/abstract_interp_cases.c.h
@@ -621,6 +621,16 @@
break;
}
+ case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: {
+ break;
+ }
+
+ case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2 - oparg)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - oparg)), true);
+ break;
+ }
+
case _CHECK_PEP_523: {
break;
}
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index ae459ca..a5cb117 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2940,19 +2940,18 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- // Start out with [NULL, bound_method, arg1, arg2, ...]
- // Transform to [callable, self, arg1, arg2, ...]
- // Then fall through to CALL_PY_EXACT_ARGS
- inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, callable, null, unused[oparg] -- unused)) {
+ op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) {
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
+ }
+
+ op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, unused, unused[oparg] -- func, self, unused[oparg])) {
STAT_INC(CALL, hit);
- PyObject *self = ((PyMethodObject *)callable)->im_self;
- PEEK(oparg + 1) = Py_NewRef(self); // self_or_null
- PyObject *meth = ((PyMethodObject *)callable)->im_func;
- PEEK(oparg + 2) = Py_NewRef(meth); // callable
+ self = Py_NewRef(((PyMethodObject *)callable)->im_self);
+ stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _INIT_CALL_PY_EXACT_ARGS
+ func = Py_NewRef(((PyMethodObject *)callable)->im_func);
+ stack_pointer[-2 - oparg] = func; // This is used by CALL, upon deoptimization
Py_DECREF(callable);
- GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
}
op(_CHECK_PEP_523, (--)) {
@@ -3010,6 +3009,18 @@ dummy_func(
#endif
}
+ macro(CALL_BOUND_METHOD_EXACT_ARGS) =
+ unused/1 + // Skip over the counter
+ _CHECK_PEP_523 +
+ _CHECK_CALL_BOUND_METHOD_EXACT_ARGS +
+ _INIT_CALL_BOUND_METHOD_EXACT_ARGS +
+ _CHECK_FUNCTION_EXACT_ARGS +
+ _CHECK_STACK_SPACE +
+ _INIT_CALL_PY_EXACT_ARGS +
+ SAVE_IP + // Tier 2 only; special-cased oparg
+ SAVE_CURRENT_IP + // Sets frame->prev_instr
+ _PUSH_FRAME;
+
macro(CALL_PY_EXACT_ARGS) =
unused/1 + // Skip over the counter
_CHECK_PEP_523 +
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 89a5bbf..85c60c2 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -2190,6 +2190,32 @@
break;
}
+ case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: {
+ PyObject *null;
+ PyObject *callable;
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
+ DEOPT_IF(null != NULL, CALL);
+ DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
+ break;
+ }
+
+ case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: {
+ PyObject *callable;
+ PyObject *func;
+ PyObject *self;
+ callable = stack_pointer[-2 - oparg];
+ STAT_INC(CALL, hit);
+ self = Py_NewRef(((PyMethodObject *)callable)->im_self);
+ stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _INIT_CALL_PY_EXACT_ARGS
+ func = Py_NewRef(((PyMethodObject *)callable)->im_func);
+ stack_pointer[-2 - oparg] = func; // This is used by CALL, upon deoptimization
+ Py_DECREF(callable);
+ stack_pointer[-2 - oparg] = func;
+ stack_pointer[-1 - oparg] = self;
+ break;
+ }
+
case _CHECK_PEP_523: {
DEOPT_IF(tstate->interp->eval_frame, CALL);
break;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 1724d11..4aa16f8 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -3795,23 +3795,99 @@
TARGET(CALL_BOUND_METHOD_EXACT_ARGS) {
PyObject *null;
PyObject *callable;
+ PyObject *self;
+ PyObject *self_or_null;
+ PyObject *func;
+ PyObject **args;
+ _PyInterpreterFrame *new_frame;
+ // _CHECK_PEP_523
+ {
+ DEOPT_IF(tstate->interp->eval_frame, CALL);
+ }
+ // _CHECK_CALL_BOUND_METHOD_EXACT_ARGS
null = stack_pointer[-1 - oparg];
callable = stack_pointer[-2 - oparg];
- DEOPT_IF(null != NULL, CALL);
- DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
- STAT_INC(CALL, hit);
- PyObject *self = ((PyMethodObject *)callable)->im_self;
- PEEK(oparg + 1) = Py_NewRef(self); // self_or_null
- PyObject *meth = ((PyMethodObject *)callable)->im_func;
- PEEK(oparg + 2) = Py_NewRef(meth); // callable
- Py_DECREF(callable);
- GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
+ {
+ DEOPT_IF(null != NULL, CALL);
+ DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
+ }
+ // _INIT_CALL_BOUND_METHOD_EXACT_ARGS
+ {
+ STAT_INC(CALL, hit);
+ self = Py_NewRef(((PyMethodObject *)callable)->im_self);
+ stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _INIT_CALL_PY_EXACT_ARGS
+ func = Py_NewRef(((PyMethodObject *)callable)->im_func);
+ stack_pointer[-2 - oparg] = func; // This is used by CALL, upon deoptimization
+ Py_DECREF(callable);
+ }
+ // _CHECK_FUNCTION_EXACT_ARGS
+ self_or_null = self;
+ callable = func;
+ {
+ uint32_t func_version = read_u32(&next_instr[1].cache);
+ ASSERT_KWNAMES_IS_NULL();
+ DEOPT_IF(!PyFunction_Check(callable), CALL);
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ DEOPT_IF(func->func_version != func_version, CALL);
+ PyCodeObject *code = (PyCodeObject *)func->func_code;
+ DEOPT_IF(code->co_argcount != oparg + (self_or_null != NULL), CALL);
+ }
+ // _CHECK_STACK_SPACE
+ {
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ PyCodeObject *code = (PyCodeObject *)func->func_code;
+ DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
+ }
+ // _INIT_CALL_PY_EXACT_ARGS
+ args = stack_pointer - oparg;
+ {
+ int argcount = oparg;
+ if (self_or_null != NULL) {
+ args--;
+ argcount++;
+ }
+ STAT_INC(CALL, hit);
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
+ for (int i = 0; i < argcount; i++) {
+ new_frame->localsplus[i] = args[i];
+ }
+ }
+ // SAVE_CURRENT_IP
+ next_instr += 3;
+ {
+ #if TIER_ONE
+ frame->prev_instr = next_instr - 1;
+ #endif
+ #if TIER_TWO
+ // Relies on a preceding SAVE_IP
+ frame->prev_instr--;
+ #endif
+ }
+ // _PUSH_FRAME
STACK_SHRINK(oparg);
- STACK_SHRINK(1);
+ STACK_SHRINK(2);
+ {
+ // Write it out explicitly because it's subtly different.
+ // Eventually this should be the only occurrence of this code.
+ frame->return_offset = 0;
+ assert(tstate->interp->eval_frame == NULL);
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ new_frame->previous = frame;
+ CALL_STAT_INC(inlined_py_calls);
+ frame = tstate->current_frame = new_frame;
+ #if TIER_ONE
+ goto start_frame;
+ #endif
+ #if TIER_TWO
+ if (_Py_EnterRecursivePy(tstate)) goto pop_1_exit_unwind;
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
+ #endif
+ }
}
TARGET(CALL_PY_EXACT_ARGS) {
- PREDICTED(CALL_PY_EXACT_ARGS);
PyObject *self_or_null;
PyObject *callable;
PyObject **args;