mirror of
https://github.com/python/cpython.git
synced 2025-10-17 04:08:28 +00:00
bpo-39320: Handle unpacking of **values in compiler (GH-18141)
* Add DICT_UPDATE and DICT_MERGE bytecodes. Use them for ** unpacking. * Remove BUILD_MAP_UNPACK and BUILD_MAP_UNPACK_WITH_CALL, as they are now unused. * Update magic number for ** unpacking opcodes. * Update dis.rst to incorporate new bytecodes. * Add blurb entry.
This commit is contained in:
parent
72b1004657
commit
8a4cd700a7
10 changed files with 3680 additions and 3672 deletions
|
@ -2801,49 +2801,32 @@ main_loop:
|
|||
DISPATCH();
|
||||
}
|
||||
|
||||
case TARGET(BUILD_MAP_UNPACK): {
|
||||
Py_ssize_t i;
|
||||
PyObject *sum = PyDict_New();
|
||||
if (sum == NULL)
|
||||
goto error;
|
||||
|
||||
for (i = oparg; i > 0; i--) {
|
||||
PyObject *arg = PEEK(i);
|
||||
if (PyDict_Update(sum, arg) < 0) {
|
||||
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"'%.200s' object is not a mapping",
|
||||
arg->ob_type->tp_name);
|
||||
}
|
||||
Py_DECREF(sum);
|
||||
goto error;
|
||||
case TARGET(DICT_UPDATE): {
|
||||
PyObject *update = POP();
|
||||
PyObject *dict = PEEK(oparg);
|
||||
if (PyDict_Update(dict, update) < 0) {
|
||||
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"'%.200s' object is not a mapping",
|
||||
update->ob_type->tp_name);
|
||||
}
|
||||
Py_DECREF(update);
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (oparg--)
|
||||
Py_DECREF(POP());
|
||||
PUSH(sum);
|
||||
Py_DECREF(update);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
case TARGET(BUILD_MAP_UNPACK_WITH_CALL): {
|
||||
Py_ssize_t i;
|
||||
PyObject *sum = PyDict_New();
|
||||
if (sum == NULL)
|
||||
case TARGET(DICT_MERGE): {
|
||||
PyObject *update = POP();
|
||||
PyObject *dict = PEEK(oparg);
|
||||
|
||||
if (_PyDict_MergeEx(dict, update, 2) < 0) {
|
||||
format_kwargs_error(tstate, PEEK(2 + oparg), update);
|
||||
Py_DECREF(update);
|
||||
goto error;
|
||||
|
||||
for (i = oparg; i > 0; i--) {
|
||||
PyObject *arg = PEEK(i);
|
||||
if (_PyDict_MergeEx(sum, arg, 2) < 0) {
|
||||
Py_DECREF(sum);
|
||||
format_kwargs_error(tstate, PEEK(2 + oparg), arg);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
while (oparg--)
|
||||
Py_DECREF(POP());
|
||||
PUSH(sum);
|
||||
Py_DECREF(update);
|
||||
PREDICT(CALL_FUNCTION_EX);
|
||||
DISPATCH();
|
||||
}
|
||||
|
|
|
@ -1007,9 +1007,6 @@ stack_effect(int opcode, int oparg, int jump)
|
|||
case BUILD_SET:
|
||||
case BUILD_STRING:
|
||||
return 1-oparg;
|
||||
case BUILD_MAP_UNPACK:
|
||||
case BUILD_MAP_UNPACK_WITH_CALL:
|
||||
return 1 - oparg;
|
||||
case BUILD_MAP:
|
||||
return 1 - 2*oparg;
|
||||
case BUILD_CONST_KEY_MAP:
|
||||
|
@ -1125,6 +1122,8 @@ stack_effect(int opcode, int oparg, int jump)
|
|||
return 0;
|
||||
case LIST_EXTEND:
|
||||
case SET_UPDATE:
|
||||
case DICT_MERGE:
|
||||
case DICT_UPDATE:
|
||||
return -1;
|
||||
default:
|
||||
return PY_INVALID_STACK_EFFECT;
|
||||
|
@ -3868,37 +3867,58 @@ static int
|
|||
compiler_dict(struct compiler *c, expr_ty e)
|
||||
{
|
||||
Py_ssize_t i, n, elements;
|
||||
int containers;
|
||||
int have_dict;
|
||||
int is_unpacking = 0;
|
||||
n = asdl_seq_LEN(e->v.Dict.values);
|
||||
containers = 0;
|
||||
have_dict = 0;
|
||||
elements = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
is_unpacking = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i) == NULL;
|
||||
if (elements == 0xFFFF || (elements && is_unpacking)) {
|
||||
if (!compiler_subdict(c, e, i - elements, i))
|
||||
return 0;
|
||||
containers++;
|
||||
elements = 0;
|
||||
}
|
||||
if (is_unpacking) {
|
||||
if (elements) {
|
||||
if (!compiler_subdict(c, e, i - elements, i)) {
|
||||
return 0;
|
||||
}
|
||||
if (have_dict) {
|
||||
ADDOP_I(c, DICT_UPDATE, 1);
|
||||
}
|
||||
have_dict = 1;
|
||||
elements = 0;
|
||||
}
|
||||
if (have_dict == 0) {
|
||||
ADDOP_I(c, BUILD_MAP, 0);
|
||||
have_dict = 1;
|
||||
}
|
||||
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i));
|
||||
containers++;
|
||||
ADDOP_I(c, DICT_UPDATE, 1);
|
||||
}
|
||||
else {
|
||||
elements++;
|
||||
if (elements == 0xFFFF) {
|
||||
if (!compiler_subdict(c, e, i - elements, i)) {
|
||||
return 0;
|
||||
}
|
||||
if (have_dict) {
|
||||
ADDOP_I(c, DICT_UPDATE, 1);
|
||||
}
|
||||
have_dict = 1;
|
||||
elements = 0;
|
||||
}
|
||||
else {
|
||||
elements++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (elements || containers == 0) {
|
||||
if (!compiler_subdict(c, e, n - elements, n))
|
||||
if (elements) {
|
||||
if (!compiler_subdict(c, e, n - elements, n)) {
|
||||
return 0;
|
||||
containers++;
|
||||
}
|
||||
if (have_dict) {
|
||||
ADDOP_I(c, DICT_UPDATE, 1);
|
||||
}
|
||||
have_dict = 1;
|
||||
}
|
||||
/* If there is more than one dict, they need to be merged into a new
|
||||
* dict. If there is one dict and it's an unpacking, then it needs
|
||||
* to be copied into a new dict." */
|
||||
if (containers > 1 || is_unpacking) {
|
||||
ADDOP_I(c, BUILD_MAP_UNPACK, containers);
|
||||
if (!have_dict) {
|
||||
ADDOP_I(c, BUILD_MAP, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -4263,8 +4283,8 @@ ex_call:
|
|||
}
|
||||
/* Then keyword arguments */
|
||||
if (nkwelts) {
|
||||
/* the number of dictionaries on the stack */
|
||||
Py_ssize_t nsubkwargs = 0;
|
||||
/* Has a new dict been pushed */
|
||||
int have_dict = 0;
|
||||
|
||||
nseen = 0; /* the number of keyword arguments on the stack following */
|
||||
for (i = 0; i < nkwelts; i++) {
|
||||
|
@ -4272,13 +4292,18 @@ ex_call:
|
|||
if (kw->arg == NULL) {
|
||||
/* A keyword argument unpacking. */
|
||||
if (nseen) {
|
||||
if (!compiler_subkwargs(c, keywords, i - nseen, i))
|
||||
if (!compiler_subkwargs(c, keywords, i - nseen, i)) {
|
||||
return 0;
|
||||
nsubkwargs++;
|
||||
}
|
||||
have_dict = 1;
|
||||
nseen = 0;
|
||||
}
|
||||
if (!have_dict) {
|
||||
ADDOP_I(c, BUILD_MAP, 0);
|
||||
have_dict = 1;
|
||||
}
|
||||
VISIT(c, expr, kw->value);
|
||||
nsubkwargs++;
|
||||
ADDOP_I(c, DICT_MERGE, 1);
|
||||
}
|
||||
else {
|
||||
nseen++;
|
||||
|
@ -4286,14 +4311,15 @@ ex_call:
|
|||
}
|
||||
if (nseen) {
|
||||
/* Pack up any trailing keyword arguments. */
|
||||
if (!compiler_subkwargs(c, keywords, nkwelts - nseen, nkwelts))
|
||||
if (!compiler_subkwargs(c, keywords, nkwelts - nseen, nkwelts)) {
|
||||
return 0;
|
||||
nsubkwargs++;
|
||||
}
|
||||
if (nsubkwargs > 1) {
|
||||
/* Pack it all up */
|
||||
ADDOP_I(c, BUILD_MAP_UNPACK_WITH_CALL, nsubkwargs);
|
||||
}
|
||||
if (have_dict) {
|
||||
ADDOP_I(c, DICT_MERGE, 1);
|
||||
}
|
||||
have_dict = 1;
|
||||
}
|
||||
assert(have_dict);
|
||||
}
|
||||
ADDOP_I(c, CALL_FUNCTION_EX, nkwelts > 0);
|
||||
return 1;
|
||||
|
|
2854
Python/importlib.h
generated
2854
Python/importlib.h
generated
File diff suppressed because it is too large
Load diff
4308
Python/importlib_external.h
generated
4308
Python/importlib_external.h
generated
File diff suppressed because it is too large
Load diff
8
Python/opcode_targets.h
generated
8
Python/opcode_targets.h
generated
|
@ -149,8 +149,8 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_MAP_ADD,
|
||||
&&TARGET_LOAD_CLASSDEREF,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_BUILD_MAP_UNPACK,
|
||||
&&TARGET_BUILD_MAP_UNPACK_WITH_CALL,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_SETUP_ASYNC_WITH,
|
||||
|
@ -163,8 +163,8 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_CALL_METHOD,
|
||||
&&TARGET_LIST_EXTEND,
|
||||
&&TARGET_SET_UPDATE,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_DICT_MERGE,
|
||||
&&TARGET_DICT_UPDATE,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue