Issue #27140: Added BUILD_CONST_KEY_MAP opcode.

This commit is contained in:
Serhiy Storchaka 2016-06-12 00:39:41 +03:00
parent d611f4cf10
commit 6a7506a77f
10 changed files with 1362 additions and 1188 deletions

View File

@ -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])``.

View File

@ -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

View File

@ -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__'

View File

@ -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

View File

@ -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

View File

@ -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 }
};

View File

@ -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;

View File

@ -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

View File

@ -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,