mirror of
https://github.com/python/cpython.git
synced 2024-11-23 09:54:58 +08:00
Issue #27140: Added BUILD_CONST_KEY_MAP opcode.
This commit is contained in:
parent
d611f4cf10
commit
6a7506a77f
@ -768,6 +768,15 @@ All of the following opcodes use their arguments.
|
||||
to hold *count* entries.
|
||||
|
||||
|
||||
.. opcode:: BUILD_CONST_KEY_MAP (count)
|
||||
|
||||
The version of :opcode:`BUILD_MAP` specialized for constant keys. *count*
|
||||
values are consumed from the stack. The top element on the stack contains
|
||||
a tuple of keys.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
|
||||
.. opcode:: LOAD_ATTR (namei)
|
||||
|
||||
Replaces TOS with ``getattr(TOS, co_names[namei])``.
|
||||
|
@ -123,6 +123,7 @@ extern "C" {
|
||||
#define BUILD_SET_UNPACK 153
|
||||
#define SETUP_ASYNC_WITH 154
|
||||
#define FORMAT_VALUE 155
|
||||
#define BUILD_CONST_KEY_MAP 156
|
||||
|
||||
/* EXCEPT_HANDLER is a special, implicit block type which is created when
|
||||
entering an except handler. It is not an opcode but we define it here
|
||||
|
@ -226,6 +226,7 @@ _code_type = type(_write_atomic.__code__)
|
||||
# Python 3.6a0 3360 (add FORMAT_VALUE opcode #25483
|
||||
# Python 3.6a0 3361 (lineno delta of code.co_lnotab becomes signed)
|
||||
# Python 3.6a0 3370 (16 bit wordcode)
|
||||
# Python 3.6a0 3371 (add BUILD_CONST_KEY_MAP opcode #27140)
|
||||
#
|
||||
# MAGIC must change whenever the bytecode emitted by the compiler may no
|
||||
# longer be understood by older implementations of the eval loop (usually
|
||||
@ -234,7 +235,7 @@ _code_type = type(_write_atomic.__code__)
|
||||
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
|
||||
# in PC/launcher.c must also be updated.
|
||||
|
||||
MAGIC_NUMBER = (3370).to_bytes(2, 'little') + b'\r\n'
|
||||
MAGIC_NUMBER = (3371).to_bytes(2, 'little') + b'\r\n'
|
||||
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
|
||||
|
||||
_PYCACHE = '__pycache__'
|
||||
|
@ -213,5 +213,6 @@ def_op('BUILD_TUPLE_UNPACK', 152)
|
||||
def_op('BUILD_SET_UNPACK', 153)
|
||||
|
||||
def_op('FORMAT_VALUE', 155)
|
||||
def_op('BUILD_CONST_KEY_MAP', 156)
|
||||
|
||||
del def_op, name_op, jrel_op, jabs_op
|
||||
|
@ -10,6 +10,8 @@ What's New in Python 3.6.0 alpha 2
|
||||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #27140: Added BUILD_CONST_KEY_MAP opcode.
|
||||
|
||||
- Issue #27186: Add support for os.PathLike objects to open() (part of PEP 519).
|
||||
|
||||
- Issue #27066: Fixed SystemError if a custom opener (for open()) returns a
|
||||
|
@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = {
|
||||
{ 3190, 3230, L"3.3" },
|
||||
{ 3250, 3310, L"3.4" },
|
||||
{ 3320, 3350, L"3.5" },
|
||||
{ 3360, 3370, L"3.6" },
|
||||
{ 3360, 3371, L"3.6" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -2647,6 +2647,39 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(BUILD_CONST_KEY_MAP) {
|
||||
int i;
|
||||
PyObject *map;
|
||||
PyObject *keys = TOP();
|
||||
if (!PyTuple_CheckExact(keys) ||
|
||||
PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"bad BUILD_CONST_KEY_MAP keys argument");
|
||||
goto error;
|
||||
}
|
||||
map = _PyDict_NewPresized((Py_ssize_t)oparg);
|
||||
if (map == NULL) {
|
||||
goto error;
|
||||
}
|
||||
for (i = oparg; i > 0; i--) {
|
||||
int err;
|
||||
PyObject *key = PyTuple_GET_ITEM(keys, oparg - i);
|
||||
PyObject *value = PEEK(i + 1);
|
||||
err = PyDict_SetItem(map, key, value);
|
||||
if (err != 0) {
|
||||
Py_DECREF(map);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(POP());
|
||||
while (oparg--) {
|
||||
Py_DECREF(POP());
|
||||
}
|
||||
PUSH(map);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(BUILD_MAP_UNPACK_WITH_CALL)
|
||||
TARGET(BUILD_MAP_UNPACK) {
|
||||
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
|
||||
|
185
Python/compile.c
185
Python/compile.c
@ -980,6 +980,8 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
|
||||
return 1 - (oparg & 0xFF);
|
||||
case BUILD_MAP:
|
||||
return 1 - 2*oparg;
|
||||
case BUILD_CONST_KEY_MAP:
|
||||
return -oparg;
|
||||
case LOAD_ATTR:
|
||||
return 0;
|
||||
case COMPARE_OP:
|
||||
@ -1234,6 +1236,15 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
|
||||
return 0; \
|
||||
}
|
||||
|
||||
/* Same as ADDOP_O, but steals a reference. */
|
||||
#define ADDOP_N(C, OP, O, TYPE) { \
|
||||
if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) { \
|
||||
Py_DECREF((O)); \
|
||||
return 0; \
|
||||
} \
|
||||
Py_DECREF((O)); \
|
||||
}
|
||||
|
||||
#define ADDOP_NAME(C, OP, O, TYPE) { \
|
||||
if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \
|
||||
return 0; \
|
||||
@ -1309,6 +1320,44 @@ compiler_isdocstring(stmt_ty s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
is_const(expr_ty e)
|
||||
{
|
||||
switch (e->kind) {
|
||||
case Constant_kind:
|
||||
case Num_kind:
|
||||
case Str_kind:
|
||||
case Bytes_kind:
|
||||
case Ellipsis_kind:
|
||||
case NameConstant_kind:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_const_value(expr_ty e)
|
||||
{
|
||||
switch (e->kind) {
|
||||
case Constant_kind:
|
||||
return e->v.Constant.value;
|
||||
case Num_kind:
|
||||
return e->v.Num.n;
|
||||
case Str_kind:
|
||||
return e->v.Str.s;
|
||||
case Bytes_kind:
|
||||
return e->v.Bytes.s;
|
||||
case Ellipsis_kind:
|
||||
return Py_Ellipsis;
|
||||
case NameConstant_kind:
|
||||
return e->v.NameConstant.value;
|
||||
default:
|
||||
assert(!is_const(e));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compile a sequence of statements, checking for a docstring. */
|
||||
|
||||
static int
|
||||
@ -2604,19 +2653,9 @@ compiler_visit_stmt_expr(struct compiler *c, expr_ty value)
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (value->kind)
|
||||
{
|
||||
case Str_kind:
|
||||
case Num_kind:
|
||||
case Ellipsis_kind:
|
||||
case Bytes_kind:
|
||||
case NameConstant_kind:
|
||||
case Constant_kind:
|
||||
if (is_const(value)) {
|
||||
/* ignore constant statement */
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
VISIT(c, expr, value);
|
||||
@ -3095,6 +3134,49 @@ compiler_set(struct compiler *c, expr_ty e)
|
||||
BUILD_SET, BUILD_SET_UNPACK);
|
||||
}
|
||||
|
||||
static int
|
||||
are_all_items_const(asdl_seq *seq, Py_ssize_t begin, Py_ssize_t end)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
for (i = begin; i < end; i++) {
|
||||
expr_ty key = (expr_ty)asdl_seq_GET(seq, i);
|
||||
if (key == NULL || !is_const(key))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_subdict(struct compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end)
|
||||
{
|
||||
Py_ssize_t i, n = end - begin;
|
||||
PyObject *keys, *key;
|
||||
if (n > 1 && are_all_items_const(e->v.Dict.keys, begin, end)) {
|
||||
for (i = begin; i < end; i++) {
|
||||
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i));
|
||||
}
|
||||
keys = PyTuple_New(n);
|
||||
if (keys == NULL) {
|
||||
return 0;
|
||||
}
|
||||
for (i = begin; i < end; i++) {
|
||||
key = get_const_value((expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
|
||||
Py_INCREF(key);
|
||||
PyTuple_SET_ITEM(keys, i - begin, key);
|
||||
}
|
||||
ADDOP_N(c, LOAD_CONST, keys, consts);
|
||||
ADDOP_I(c, BUILD_CONST_KEY_MAP, n);
|
||||
}
|
||||
else {
|
||||
for (i = begin; i < end; i++) {
|
||||
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
|
||||
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i));
|
||||
}
|
||||
ADDOP_I(c, BUILD_MAP, n);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_dict(struct compiler *c, expr_ty e)
|
||||
{
|
||||
@ -3107,7 +3189,8 @@ compiler_dict(struct compiler *c, expr_ty e)
|
||||
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)) {
|
||||
ADDOP_I(c, BUILD_MAP, elements);
|
||||
if (!compiler_subdict(c, e, i - elements, i))
|
||||
return 0;
|
||||
containers++;
|
||||
elements = 0;
|
||||
}
|
||||
@ -3116,13 +3199,12 @@ compiler_dict(struct compiler *c, expr_ty e)
|
||||
containers++;
|
||||
}
|
||||
else {
|
||||
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
|
||||
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i));
|
||||
elements++;
|
||||
}
|
||||
}
|
||||
if (elements || containers == 0) {
|
||||
ADDOP_I(c, BUILD_MAP, elements);
|
||||
if (!compiler_subdict(c, e, n - elements, n))
|
||||
return 0;
|
||||
containers++;
|
||||
}
|
||||
/* If there is more than one dict, they need to be merged into a new
|
||||
@ -3266,6 +3348,42 @@ compiler_formatted_value(struct compiler *c, expr_ty e)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_subkwargs(struct compiler *c, asdl_seq *keywords, Py_ssize_t begin, Py_ssize_t end)
|
||||
{
|
||||
Py_ssize_t i, n = end - begin;
|
||||
keyword_ty kw;
|
||||
PyObject *keys, *key;
|
||||
assert(n > 0);
|
||||
if (n > 1) {
|
||||
for (i = begin; i < end; i++) {
|
||||
kw = asdl_seq_GET(keywords, i);
|
||||
VISIT(c, expr, kw->value);
|
||||
}
|
||||
keys = PyTuple_New(n);
|
||||
if (keys == NULL) {
|
||||
return 0;
|
||||
}
|
||||
for (i = begin; i < end; i++) {
|
||||
key = ((keyword_ty) asdl_seq_GET(keywords, i))->arg;
|
||||
Py_INCREF(key);
|
||||
PyTuple_SET_ITEM(keys, i - begin, key);
|
||||
}
|
||||
ADDOP_N(c, LOAD_CONST, keys, consts);
|
||||
ADDOP_I(c, BUILD_CONST_KEY_MAP, n);
|
||||
}
|
||||
else {
|
||||
/* a for loop only executes once */
|
||||
for (i = begin; i < end; i++) {
|
||||
kw = asdl_seq_GET(keywords, i);
|
||||
ADDOP_O(c, LOAD_CONST, kw->arg, consts);
|
||||
VISIT(c, expr, kw->value);
|
||||
}
|
||||
ADDOP_I(c, BUILD_MAP, n);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* shared code between compiler_call and compiler_class */
|
||||
static int
|
||||
compiler_call_helper(struct compiler *c,
|
||||
@ -3332,29 +3450,38 @@ compiler_call_helper(struct compiler *c,
|
||||
if (kw->arg == NULL) {
|
||||
/* A keyword argument unpacking. */
|
||||
if (nseen) {
|
||||
ADDOP_I(c, BUILD_MAP, nseen);
|
||||
if (nsubkwargs) {
|
||||
if (!compiler_subkwargs(c, keywords, i - nseen, i))
|
||||
return 0;
|
||||
nsubkwargs++;
|
||||
}
|
||||
else {
|
||||
Py_ssize_t j;
|
||||
for (j = 0; j < nseen; j++) {
|
||||
VISIT(c, keyword, asdl_seq_GET(keywords, j));
|
||||
}
|
||||
nkw = nseen;
|
||||
}
|
||||
nseen = 0;
|
||||
nsubkwargs++;
|
||||
}
|
||||
VISIT(c, expr, kw->value);
|
||||
nsubkwargs++;
|
||||
}
|
||||
else if (nsubkwargs) {
|
||||
/* A keyword argument and we already have a dict. */
|
||||
ADDOP_O(c, LOAD_CONST, kw->arg, consts);
|
||||
VISIT(c, expr, kw->value);
|
||||
nseen++;
|
||||
}
|
||||
else {
|
||||
/* keyword argument */
|
||||
VISIT(c, keyword, kw)
|
||||
nkw++;
|
||||
nseen++;
|
||||
}
|
||||
}
|
||||
if (nseen) {
|
||||
/* Pack up any trailing keyword arguments. */
|
||||
ADDOP_I(c, BUILD_MAP, nseen);
|
||||
nsubkwargs++;
|
||||
if (nsubkwargs) {
|
||||
/* Pack up any trailing keyword arguments. */
|
||||
if (!compiler_subkwargs(c, keywords, nelts - nseen, nelts))
|
||||
return 0;
|
||||
nsubkwargs++;
|
||||
}
|
||||
else {
|
||||
VISIT_SEQ(c, keyword, keywords);
|
||||
nkw = nseen;
|
||||
}
|
||||
}
|
||||
if (nsubkwargs) {
|
||||
code |= 2;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -155,7 +155,7 @@ static void *opcode_targets[256] = {
|
||||
&&TARGET_BUILD_SET_UNPACK,
|
||||
&&TARGET_SETUP_ASYNC_WITH,
|
||||
&&TARGET_FORMAT_VALUE,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_BUILD_CONST_KEY_MAP,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
|
Loading…
Reference in New Issue
Block a user