Skip to content

Commit

Permalink
gh-106581: Add 10 new opcodes by allowing assert(kwnames == NULL) (#…
Browse files Browse the repository at this point in the history
…106707)

By turning `assert(kwnames == NULL)` into a macro that is not in the "forbidden" list, many instructions that formerly were skipped because they contained such an assert (but no other mention of `kwnames`) are now supported in Tier 2. This covers 10 instructions in total (all specializations of `CALL` that invoke some C code):
- `CALL_NO_KW_TYPE_1`
- `CALL_NO_KW_STR_1`
- `CALL_NO_KW_TUPLE_1`
- `CALL_NO_KW_BUILTIN_O`
- `CALL_NO_KW_BUILTIN_FAST`
- `CALL_NO_KW_LEN`
- `CALL_NO_KW_ISINSTANCE`
- `CALL_NO_KW_METHOD_DESCRIPTOR_O`
- `CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS`
- `CALL_NO_KW_METHOD_DESCRIPTOR_FAST`
  • Loading branch information
gvanrossum authored Jul 17, 2023
1 parent b2b261a commit 2b94a05
Show file tree
Hide file tree
Showing 7 changed files with 385 additions and 34 deletions.
10 changes: 10 additions & 0 deletions Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 15 additions & 15 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2776,7 +2776,7 @@ dummy_func(
}

inst(KW_NAMES, (--)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS));
kwnames = GETITEM(FRAME_CO_CONSTS, oparg);
}
Expand Down Expand Up @@ -2927,7 +2927,7 @@ dummy_func(
}

inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(tstate->interp->eval_frame, CALL);
int is_meth = method != NULL;
int argcount = oparg;
Expand Down Expand Up @@ -2955,7 +2955,7 @@ dummy_func(
}

inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(tstate->interp->eval_frame, CALL);
int is_meth = method != NULL;
int argcount = oparg;
Expand Down Expand Up @@ -2993,7 +2993,7 @@ dummy_func(
}

inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
PyObject *obj = args[0];
Expand All @@ -3005,7 +3005,7 @@ dummy_func(
}

inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL);
Expand All @@ -3019,7 +3019,7 @@ dummy_func(
}

inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL);
Expand All @@ -3038,7 +3038,7 @@ dummy_func(
* 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``)
* 3. Pushes the frame for ``__init__`` to the frame stack
* */
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
_PyCallCache *cache = (_PyCallCache *)next_instr;
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(!PyType_Check(callable), CALL);
Expand Down Expand Up @@ -3122,7 +3122,7 @@ dummy_func(

inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
/* Builtin METH_O functions */
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
Expand Down Expand Up @@ -3153,7 +3153,7 @@ dummy_func(

inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
/* Builtin METH_FASTCALL functions, without keywords */
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
Expand Down Expand Up @@ -3222,7 +3222,7 @@ dummy_func(
}

inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
/* len(o) */
int is_meth = method != NULL;
int total_args = oparg;
Expand All @@ -3249,7 +3249,7 @@ dummy_func(
}

inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
/* isinstance(o, o2) */
int is_meth = method != NULL;
int total_args = oparg;
Expand Down Expand Up @@ -3279,7 +3279,7 @@ dummy_func(

// This is secretly a super-instruction
inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
assert(method != NULL);
PyInterpreterState *interp = _PyInterpreterState_GET();
Expand All @@ -3299,7 +3299,7 @@ dummy_func(
}

inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
Expand Down Expand Up @@ -3365,7 +3365,7 @@ dummy_func(
}

inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 0 || oparg == 1);
int is_meth = method != NULL;
int total_args = oparg;
Expand Down Expand Up @@ -3397,7 +3397,7 @@ dummy_func(
}

inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
assert(kwnames == NULL);
ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
Expand Down
4 changes: 4 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -2706,6 +2706,9 @@ void Py_LeaveRecursiveCall(void)

///////////////////// Experimental UOp Interpreter /////////////////////

#undef ASSERT_KWNAMES_IS_NULL
#define ASSERT_KWNAMES_IS_NULL() (void)0

#undef DEOPT_IF
#define DEOPT_IF(COND, INSTNAME) \
if ((COND)) { \
Expand Down Expand Up @@ -2746,6 +2749,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
int opcode;
uint64_t operand;
int oparg;

for (;;) {
opcode = self->trace[pc].opcode;
operand = self->trace[pc].operand;
Expand Down
2 changes: 2 additions & 0 deletions Python/ceval_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,5 @@ static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = {
[FVC_REPR] = PyObject_Repr,
[FVC_ASCII] = PyObject_ASCII
};

#define ASSERT_KWNAMES_IS_NULL() assert(kwnames == NULL)
Loading

0 comments on commit 2b94a05

Please sign in to comment.