Commit 6a7506a7 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #27140: Added BUILD_CONST_KEY_MAP opcode.

parent d611f4cf
...@@ -768,6 +768,15 @@ All of the following opcodes use their arguments. ...@@ -768,6 +768,15 @@ All of the following opcodes use their arguments.
to hold *count* entries. 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) .. opcode:: LOAD_ATTR (namei)
Replaces TOS with ``getattr(TOS, co_names[namei])``. Replaces TOS with ``getattr(TOS, co_names[namei])``.
......
...@@ -123,6 +123,7 @@ extern "C" { ...@@ -123,6 +123,7 @@ extern "C" {
#define BUILD_SET_UNPACK 153 #define BUILD_SET_UNPACK 153
#define SETUP_ASYNC_WITH 154 #define SETUP_ASYNC_WITH 154
#define FORMAT_VALUE 155 #define FORMAT_VALUE 155
#define BUILD_CONST_KEY_MAP 156
/* EXCEPT_HANDLER is a special, implicit block type which is created when /* 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 entering an except handler. It is not an opcode but we define it here
......
...@@ -226,6 +226,7 @@ _code_type = type(_write_atomic.__code__) ...@@ -226,6 +226,7 @@ _code_type = type(_write_atomic.__code__)
# Python 3.6a0 3360 (add FORMAT_VALUE opcode #25483 # Python 3.6a0 3360 (add FORMAT_VALUE opcode #25483
# Python 3.6a0 3361 (lineno delta of code.co_lnotab becomes signed) # Python 3.6a0 3361 (lineno delta of code.co_lnotab becomes signed)
# Python 3.6a0 3370 (16 bit wordcode) # 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 # MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually # longer be understood by older implementations of the eval loop (usually
...@@ -234,7 +235,7 @@ _code_type = type(_write_atomic.__code__) ...@@ -234,7 +235,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # 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 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'
......
...@@ -213,5 +213,6 @@ def_op('BUILD_TUPLE_UNPACK', 152) ...@@ -213,5 +213,6 @@ def_op('BUILD_TUPLE_UNPACK', 152)
def_op('BUILD_SET_UNPACK', 153) def_op('BUILD_SET_UNPACK', 153)
def_op('FORMAT_VALUE', 155) def_op('FORMAT_VALUE', 155)
def_op('BUILD_CONST_KEY_MAP', 156)
del def_op, name_op, jrel_op, jabs_op del def_op, name_op, jrel_op, jabs_op
...@@ -10,6 +10,8 @@ What's New in Python 3.6.0 alpha 2 ...@@ -10,6 +10,8 @@ What's New in Python 3.6.0 alpha 2
Core and Builtins 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 #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 - Issue #27066: Fixed SystemError if a custom opener (for open()) returns a
......
...@@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = { ...@@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = {
{ 3190, 3230, L"3.3" }, { 3190, 3230, L"3.3" },
{ 3250, 3310, L"3.4" }, { 3250, 3310, L"3.4" },
{ 3320, 3350, L"3.5" }, { 3320, 3350, L"3.5" },
{ 3360, 3370, L"3.6" }, { 3360, 3371, L"3.6" },
{ 0 } { 0 }
}; };
......
...@@ -2647,6 +2647,39 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2647,6 +2647,39 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); 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_WITH_CALL)
TARGET(BUILD_MAP_UNPACK) { TARGET(BUILD_MAP_UNPACK) {
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL; int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
......
...@@ -980,6 +980,8 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) ...@@ -980,6 +980,8 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
return 1 - (oparg & 0xFF); return 1 - (oparg & 0xFF);
case BUILD_MAP: case BUILD_MAP:
return 1 - 2*oparg; return 1 - 2*oparg;
case BUILD_CONST_KEY_MAP:
return -oparg;
case LOAD_ATTR: case LOAD_ATTR:
return 0; return 0;
case COMPARE_OP: case COMPARE_OP:
...@@ -1234,6 +1236,15 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) ...@@ -1234,6 +1236,15 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
return 0; \ 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) { \ #define ADDOP_NAME(C, OP, O, TYPE) { \
if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \ if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \
return 0; \ return 0; \
...@@ -1309,6 +1320,44 @@ compiler_isdocstring(stmt_ty s) ...@@ -1309,6 +1320,44 @@ compiler_isdocstring(stmt_ty s)
return 0; 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. */ /* Compile a sequence of statements, checking for a docstring. */
static int static int
...@@ -2604,19 +2653,9 @@ compiler_visit_stmt_expr(struct compiler *c, expr_ty value) ...@@ -2604,19 +2653,9 @@ compiler_visit_stmt_expr(struct compiler *c, expr_ty value)
return 1; return 1;
} }
switch (value->kind) if (is_const(value)) {
{
case Str_kind:
case Num_kind:
case Ellipsis_kind:
case Bytes_kind:
case NameConstant_kind:
case Constant_kind:
/* ignore constant statement */ /* ignore constant statement */
return 1; return 1;
default:
break;
} }
VISIT(c, expr, value); VISIT(c, expr, value);
...@@ -3095,6 +3134,49 @@ compiler_set(struct compiler *c, expr_ty e) ...@@ -3095,6 +3134,49 @@ compiler_set(struct compiler *c, expr_ty e)
BUILD_SET, BUILD_SET_UNPACK); 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 static int
compiler_dict(struct compiler *c, expr_ty e) compiler_dict(struct compiler *c, expr_ty e)
{ {
...@@ -3107,7 +3189,8 @@ 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++) { for (i = 0; i < n; i++) {
is_unpacking = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i) == NULL; is_unpacking = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i) == NULL;
if (elements == 0xFFFF || (elements && is_unpacking)) { if (elements == 0xFFFF || (elements && is_unpacking)) {
ADDOP_I(c, BUILD_MAP, elements); if (!compiler_subdict(c, e, i - elements, i))
return 0;
containers++; containers++;
elements = 0; elements = 0;
} }
...@@ -3116,13 +3199,12 @@ compiler_dict(struct compiler *c, expr_ty e) ...@@ -3116,13 +3199,12 @@ compiler_dict(struct compiler *c, expr_ty e)
containers++; containers++;
} }
else { 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++; elements++;
} }
} }
if (elements || containers == 0) { if (elements || containers == 0) {
ADDOP_I(c, BUILD_MAP, elements); if (!compiler_subdict(c, e, n - elements, n))
return 0;
containers++; containers++;
} }
/* If there is more than one dict, they need to be merged into a new /* 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) ...@@ -3266,6 +3348,42 @@ compiler_formatted_value(struct compiler *c, expr_ty e)
return 1; 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 */ /* shared code between compiler_call and compiler_class */
static int static int
compiler_call_helper(struct compiler *c, compiler_call_helper(struct compiler *c,
...@@ -3332,30 +3450,39 @@ compiler_call_helper(struct compiler *c, ...@@ -3332,30 +3450,39 @@ compiler_call_helper(struct compiler *c,
if (kw->arg == NULL) { if (kw->arg == NULL) {
/* A keyword argument unpacking. */ /* A keyword argument unpacking. */
if (nseen) { if (nseen) {
ADDOP_I(c, BUILD_MAP, nseen); if (nsubkwargs) {
nseen = 0; if (!compiler_subkwargs(c, keywords, i - nseen, i))
return 0;
nsubkwargs++; nsubkwargs++;
} }
VISIT(c, expr, kw->value); else {
nsubkwargs++; Py_ssize_t j;
for (j = 0; j < nseen; j++) {
VISIT(c, keyword, asdl_seq_GET(keywords, j));
}
nkw = nseen;
}
nseen = 0;
} }
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); VISIT(c, expr, kw->value);
nseen++; nsubkwargs++;
} }
else { else {
/* keyword argument */ nseen++;
VISIT(c, keyword, kw)
nkw++;
} }
} }
if (nseen) { if (nseen) {
if (nsubkwargs) {
/* Pack up any trailing keyword arguments. */ /* Pack up any trailing keyword arguments. */
ADDOP_I(c, BUILD_MAP, nseen); if (!compiler_subkwargs(c, keywords, nelts - nseen, nelts))
return 0;
nsubkwargs++; nsubkwargs++;
} }
else {
VISIT_SEQ(c, keyword, keywords);
nkw = nseen;
}
}
if (nsubkwargs) { if (nsubkwargs) {
code |= 2; code |= 2;
if (nsubkwargs > 1) { if (nsubkwargs > 1) {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -155,7 +155,7 @@ static void *opcode_targets[256] = { ...@@ -155,7 +155,7 @@ static void *opcode_targets[256] = {
&&TARGET_BUILD_SET_UNPACK, &&TARGET_BUILD_SET_UNPACK,
&&TARGET_SETUP_ASYNC_WITH, &&TARGET_SETUP_ASYNC_WITH,
&&TARGET_FORMAT_VALUE, &&TARGET_FORMAT_VALUE,
&&_unknown_opcode, &&TARGET_BUILD_CONST_KEY_MAP,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment