mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
GH-77273: Better bytecodes for f-strings (GH-6132)
This commit is contained in:
parent
307bceaa65
commit
1d857da7f0
15 changed files with 525 additions and 485 deletions
|
@ -52,6 +52,8 @@
|
|||
#define family(name, ...) static int family_##name
|
||||
#define pseudo(name) static int pseudo_##name
|
||||
|
||||
typedef PyObject *(*convertion_func_ptr)(PyObject *);
|
||||
|
||||
// Dummy variables for stack effects.
|
||||
static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub;
|
||||
static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2;
|
||||
|
@ -3367,43 +3369,35 @@ dummy_func(
|
|||
ERROR_IF(slice == NULL, error);
|
||||
}
|
||||
|
||||
inst(FORMAT_VALUE, (value, fmt_spec if ((oparg & FVS_MASK) == FVS_HAVE_SPEC) -- result)) {
|
||||
/* Handles f-string value formatting. */
|
||||
PyObject *(*conv_fn)(PyObject *);
|
||||
int which_conversion = oparg & FVC_MASK;
|
||||
|
||||
/* See if any conversion is specified. */
|
||||
switch (which_conversion) {
|
||||
case FVC_NONE: conv_fn = NULL; break;
|
||||
case FVC_STR: conv_fn = PyObject_Str; break;
|
||||
case FVC_REPR: conv_fn = PyObject_Repr; break;
|
||||
case FVC_ASCII: conv_fn = PyObject_ASCII; break;
|
||||
default:
|
||||
_PyErr_Format(tstate, PyExc_SystemError,
|
||||
"unexpected conversion flag %d",
|
||||
which_conversion);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If there's a conversion function, call it and replace
|
||||
value with that result. Otherwise, just use value,
|
||||
without conversion. */
|
||||
if (conv_fn != NULL) {
|
||||
result = conv_fn(value);
|
||||
Py_DECREF(value);
|
||||
if (result == NULL) {
|
||||
Py_XDECREF(fmt_spec);
|
||||
ERROR_IF(true, error);
|
||||
}
|
||||
value = result;
|
||||
}
|
||||
|
||||
result = PyObject_Format(value, fmt_spec);
|
||||
inst(CONVERT_VALUE, (value -- result)) {
|
||||
convertion_func_ptr conv_fn;
|
||||
assert(oparg >= FVC_STR && oparg <= FVC_ASCII);
|
||||
conv_fn = CONVERSION_FUNCTIONS[oparg];
|
||||
result = conv_fn(value);
|
||||
Py_DECREF(value);
|
||||
Py_XDECREF(fmt_spec);
|
||||
ERROR_IF(result == NULL, error);
|
||||
}
|
||||
|
||||
inst(FORMAT_SIMPLE, (value -- res)) {
|
||||
/* If value is a unicode object, then we know the result
|
||||
* of format(value) is value itself. */
|
||||
if (!PyUnicode_CheckExact(value)) {
|
||||
res = PyObject_Format(value, NULL);
|
||||
Py_DECREF(value);
|
||||
ERROR_IF(res == NULL, error);
|
||||
}
|
||||
else {
|
||||
res = value;
|
||||
}
|
||||
}
|
||||
|
||||
inst(FORMAT_WITH_SPEC, (value, fmt_spec -- res)) {
|
||||
res = PyObject_Format(value, fmt_spec);
|
||||
Py_DECREF(value);
|
||||
Py_DECREF(fmt_spec);
|
||||
ERROR_IF(res == NULL, error);
|
||||
}
|
||||
|
||||
inst(COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) {
|
||||
assert(oparg > 0);
|
||||
top = Py_NewRef(bottom);
|
||||
|
|
|
@ -222,6 +222,14 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
|
|||
static void
|
||||
_PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);
|
||||
|
||||
typedef PyObject *(*convertion_func_ptr)(PyObject *);
|
||||
|
||||
static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = {
|
||||
[FVC_STR] = PyObject_Str,
|
||||
[FVC_REPR] = PyObject_Repr,
|
||||
[FVC_ASCII] = PyObject_ASCII
|
||||
};
|
||||
|
||||
#define UNBOUNDLOCAL_ERROR_MSG \
|
||||
"cannot access local variable '%s' where it is not associated with a value"
|
||||
#define UNBOUNDFREE_ERROR_MSG \
|
||||
|
|
|
@ -4985,26 +4985,26 @@ compiler_formatted_value(struct compiler *c, expr_ty e)
|
|||
/* The expression to be formatted. */
|
||||
VISIT(c, expr, e->v.FormattedValue.value);
|
||||
|
||||
switch (conversion) {
|
||||
case 's': oparg = FVC_STR; break;
|
||||
case 'r': oparg = FVC_REPR; break;
|
||||
case 'a': oparg = FVC_ASCII; break;
|
||||
case -1: oparg = FVC_NONE; break;
|
||||
default:
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
location loc = LOC(e);
|
||||
if (conversion != -1) {
|
||||
switch (conversion) {
|
||||
case 's': oparg = FVC_STR; break;
|
||||
case 'r': oparg = FVC_REPR; break;
|
||||
case 'a': oparg = FVC_ASCII; break;
|
||||
default:
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"Unrecognized conversion character %d", conversion);
|
||||
return ERROR;
|
||||
return ERROR;
|
||||
}
|
||||
ADDOP_I(c, loc, CONVERT_VALUE, oparg);
|
||||
}
|
||||
if (e->v.FormattedValue.format_spec) {
|
||||
/* Evaluate the format spec, and update our opcode arg. */
|
||||
VISIT(c, expr, e->v.FormattedValue.format_spec);
|
||||
oparg |= FVS_HAVE_SPEC;
|
||||
ADDOP(c, loc, FORMAT_WITH_SPEC);
|
||||
} else {
|
||||
ADDOP(c, loc, FORMAT_SIMPLE);
|
||||
}
|
||||
|
||||
/* And push our opcode and oparg */
|
||||
location loc = LOC(e);
|
||||
ADDOP_I(c, loc, FORMAT_VALUE, oparg);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
|
616
Python/generated_cases.c.h
generated
616
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
|
@ -402,8 +402,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
|
|||
return 0;
|
||||
case BUILD_SLICE:
|
||||
return ((oparg == 3) ? 1 : 0) + 2;
|
||||
case FORMAT_VALUE:
|
||||
return (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0) + 1;
|
||||
case CONVERT_VALUE:
|
||||
return 1;
|
||||
case FORMAT_SIMPLE:
|
||||
return 1;
|
||||
case FORMAT_WITH_SPEC:
|
||||
return 2;
|
||||
case COPY:
|
||||
return (oparg-1) + 1;
|
||||
case BINARY_OP:
|
||||
|
@ -820,7 +824,11 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
|
|||
return 0;
|
||||
case BUILD_SLICE:
|
||||
return 1;
|
||||
case FORMAT_VALUE:
|
||||
case CONVERT_VALUE:
|
||||
return 1;
|
||||
case FORMAT_SIMPLE:
|
||||
return 1;
|
||||
case FORMAT_WITH_SPEC:
|
||||
return 1;
|
||||
case COPY:
|
||||
return (oparg-1) + 2;
|
||||
|
@ -1064,7 +1072,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
|
|||
[SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
[RETURN_GENERATOR] = { true, INSTR_FMT_IX, 0 },
|
||||
[BUILD_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
[FORMAT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
[CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
[FORMAT_SIMPLE] = { true, INSTR_FMT_IX, 0 },
|
||||
[FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, 0 },
|
||||
[COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
[BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
|
||||
[SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
|
|
44
Python/opcode_targets.h
generated
44
Python/opcode_targets.h
generated
|
@ -39,6 +39,8 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_CHECK_EG_MATCH,
|
||||
&&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS,
|
||||
&&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
|
||||
&&TARGET_FORMAT_SIMPLE,
|
||||
&&TARGET_FORMAT_WITH_SPEC,
|
||||
&&TARGET_CALL_NO_KW_BUILTIN_FAST,
|
||||
&&TARGET_CALL_NO_KW_BUILTIN_O,
|
||||
&&TARGET_CALL_NO_KW_ISINSTANCE,
|
||||
|
@ -46,8 +48,6 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_CALL_NO_KW_LIST_APPEND,
|
||||
&&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST,
|
||||
&&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS,
|
||||
&&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O,
|
||||
&&TARGET_CALL_NO_KW_STR_1,
|
||||
&&TARGET_WITH_EXCEPT_START,
|
||||
&&TARGET_GET_AITER,
|
||||
&&TARGET_GET_ANEXT,
|
||||
|
@ -55,39 +55,39 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_BEFORE_WITH,
|
||||
&&TARGET_END_ASYNC_FOR,
|
||||
&&TARGET_CLEANUP_THROW,
|
||||
&&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O,
|
||||
&&TARGET_CALL_NO_KW_STR_1,
|
||||
&&TARGET_CALL_NO_KW_TUPLE_1,
|
||||
&&TARGET_CALL_NO_KW_TYPE_1,
|
||||
&&TARGET_COMPARE_OP_FLOAT,
|
||||
&&TARGET_COMPARE_OP_INT,
|
||||
&&TARGET_STORE_SUBSCR,
|
||||
&&TARGET_DELETE_SUBSCR,
|
||||
&&TARGET_COMPARE_OP_FLOAT,
|
||||
&&TARGET_COMPARE_OP_INT,
|
||||
&&TARGET_COMPARE_OP_STR,
|
||||
&&TARGET_FOR_ITER_LIST,
|
||||
&&TARGET_FOR_ITER_TUPLE,
|
||||
&&TARGET_FOR_ITER_RANGE,
|
||||
&&TARGET_FOR_ITER_GEN,
|
||||
&&TARGET_LOAD_SUPER_ATTR_ATTR,
|
||||
&&TARGET_GET_ITER,
|
||||
&&TARGET_GET_YIELD_FROM_ITER,
|
||||
&&TARGET_LOAD_SUPER_ATTR_METHOD,
|
||||
&&TARGET_FOR_ITER_GEN,
|
||||
&&TARGET_LOAD_BUILD_CLASS,
|
||||
&&TARGET_LOAD_ATTR_CLASS,
|
||||
&&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
|
||||
&&TARGET_LOAD_SUPER_ATTR_ATTR,
|
||||
&&TARGET_LOAD_SUPER_ATTR_METHOD,
|
||||
&&TARGET_LOAD_ASSERTION_ERROR,
|
||||
&&TARGET_RETURN_GENERATOR,
|
||||
&&TARGET_LOAD_ATTR_CLASS,
|
||||
&&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
|
||||
&&TARGET_LOAD_ATTR_INSTANCE_VALUE,
|
||||
&&TARGET_LOAD_ATTR_MODULE,
|
||||
&&TARGET_LOAD_ATTR_PROPERTY,
|
||||
&&TARGET_LOAD_ATTR_SLOT,
|
||||
&&TARGET_LOAD_ATTR_WITH_HINT,
|
||||
&&TARGET_LOAD_ATTR_METHOD_LAZY_DICT,
|
||||
&&TARGET_LOAD_ATTR_METHOD_NO_DICT,
|
||||
&&TARGET_RETURN_VALUE,
|
||||
&&TARGET_LOAD_ATTR_METHOD_WITH_VALUES,
|
||||
&&TARGET_LOAD_ATTR_METHOD_LAZY_DICT,
|
||||
&&TARGET_SETUP_ANNOTATIONS,
|
||||
&&TARGET_LOAD_GLOBAL_BUILTIN,
|
||||
&&TARGET_LOAD_ATTR_METHOD_NO_DICT,
|
||||
&&TARGET_LOAD_LOCALS,
|
||||
&&TARGET_LOAD_GLOBAL_MODULE,
|
||||
&&TARGET_LOAD_ATTR_METHOD_WITH_VALUES,
|
||||
&&TARGET_POP_EXCEPT,
|
||||
&&TARGET_STORE_NAME,
|
||||
&&TARGET_DELETE_NAME,
|
||||
|
@ -110,9 +110,9 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_IMPORT_NAME,
|
||||
&&TARGET_IMPORT_FROM,
|
||||
&&TARGET_JUMP_FORWARD,
|
||||
&&TARGET_LOAD_GLOBAL_BUILTIN,
|
||||
&&TARGET_LOAD_GLOBAL_MODULE,
|
||||
&&TARGET_STORE_ATTR_INSTANCE_VALUE,
|
||||
&&TARGET_STORE_ATTR_SLOT,
|
||||
&&TARGET_STORE_ATTR_WITH_HINT,
|
||||
&&TARGET_POP_JUMP_IF_FALSE,
|
||||
&&TARGET_POP_JUMP_IF_TRUE,
|
||||
&&TARGET_LOAD_GLOBAL,
|
||||
|
@ -131,7 +131,7 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_POP_JUMP_IF_NONE,
|
||||
&&TARGET_RAISE_VARARGS,
|
||||
&&TARGET_GET_AWAITABLE,
|
||||
&&TARGET_STORE_SUBSCR_DICT,
|
||||
&&TARGET_STORE_ATTR_SLOT,
|
||||
&&TARGET_BUILD_SLICE,
|
||||
&&TARGET_JUMP_BACKWARD_NO_INTERRUPT,
|
||||
&&TARGET_MAKE_CELL,
|
||||
|
@ -147,20 +147,20 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_LIST_APPEND,
|
||||
&&TARGET_SET_ADD,
|
||||
&&TARGET_MAP_ADD,
|
||||
&&TARGET_STORE_SUBSCR_LIST_INT,
|
||||
&&TARGET_STORE_ATTR_WITH_HINT,
|
||||
&&TARGET_COPY_FREE_VARS,
|
||||
&&TARGET_YIELD_VALUE,
|
||||
&&TARGET_RESUME,
|
||||
&&TARGET_MATCH_CLASS,
|
||||
&&TARGET_STORE_SUBSCR_DICT,
|
||||
&&TARGET_STORE_SUBSCR_LIST_INT,
|
||||
&&TARGET_UNPACK_SEQUENCE_LIST,
|
||||
&&TARGET_UNPACK_SEQUENCE_TUPLE,
|
||||
&&TARGET_FORMAT_VALUE,
|
||||
&&TARGET_BUILD_CONST_KEY_MAP,
|
||||
&&TARGET_BUILD_STRING,
|
||||
&&TARGET_CONVERT_VALUE,
|
||||
&&TARGET_UNPACK_SEQUENCE_TUPLE,
|
||||
&&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
|
||||
&&TARGET_SEND_GEN,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_LIST_EXTEND,
|
||||
&&TARGET_SET_UPDATE,
|
||||
&&TARGET_DICT_MERGE,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue