Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6a7506a

Browse files
Issue #27140: Added BUILD_CONST_KEY_MAP opcode.
1 parent d611f4c commit 6a7506a

10 files changed

Lines changed: 1361 additions & 1187 deletions

File tree

Doc/library/dis.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,15 @@ All of the following opcodes use their arguments.
768768
to hold *count* entries.
769769

770770

771+
.. opcode:: BUILD_CONST_KEY_MAP (count)
772+
773+
The version of :opcode:`BUILD_MAP` specialized for constant keys. *count*
774+
values are consumed from the stack. The top element on the stack contains
775+
a tuple of keys.
776+
777+
.. versionadded:: 3.6
778+
779+
771780
.. opcode:: LOAD_ATTR (namei)
772781

773782
Replaces TOS with ``getattr(TOS, co_names[namei])``.

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ extern "C" {
123123
#define BUILD_SET_UNPACK 153
124124
#define SETUP_ASYNC_WITH 154
125125
#define FORMAT_VALUE 155
126+
#define BUILD_CONST_KEY_MAP 156
126127

127128
/* EXCEPT_HANDLER is a special, implicit block type which is created when
128129
entering an except handler. It is not an opcode but we define it here

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ def _write_atomic(path, data, mode=0o666):
226226
# Python 3.6a0 3360 (add FORMAT_VALUE opcode #25483
227227
# Python 3.6a0 3361 (lineno delta of code.co_lnotab becomes signed)
228228
# Python 3.6a0 3370 (16 bit wordcode)
229+
# Python 3.6a0 3371 (add BUILD_CONST_KEY_MAP opcode #27140)
229230
#
230231
# MAGIC must change whenever the bytecode emitted by the compiler may no
231232
# longer be understood by older implementations of the eval loop (usually
@@ -234,7 +235,7 @@ def _write_atomic(path, data, mode=0o666):
234235
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
235236
# in PC/launcher.c must also be updated.
236237

237-
MAGIC_NUMBER = (3370).to_bytes(2, 'little') + b'\r\n'
238+
MAGIC_NUMBER = (3371).to_bytes(2, 'little') + b'\r\n'
238239
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
239240

240241
_PYCACHE = '__pycache__'

Lib/opcode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,5 +213,6 @@ def jabs_op(name, op):
213213
def_op('BUILD_SET_UNPACK', 153)
214214

215215
def_op('FORMAT_VALUE', 155)
216+
def_op('BUILD_CONST_KEY_MAP', 156)
216217

217218
del def_op, name_op, jrel_op, jabs_op

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ What's New in Python 3.6.0 alpha 2
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #27140: Added BUILD_CONST_KEY_MAP opcode.
14+
1315
- Issue #27186: Add support for os.PathLike objects to open() (part of PEP 519).
1416

1517
- Issue #27066: Fixed SystemError if a custom opener (for open()) returns a

PC/launcher.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = {
10891089
{ 3190, 3230, L"3.3" },
10901090
{ 3250, 3310, L"3.4" },
10911091
{ 3320, 3350, L"3.5" },
1092-
{ 3360, 3370, L"3.6" },
1092+
{ 3360, 3371, L"3.6" },
10931093
{ 0 }
10941094
};
10951095

Python/ceval.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2647,6 +2647,39 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
26472647
DISPATCH();
26482648
}
26492649

2650+
TARGET(BUILD_CONST_KEY_MAP) {
2651+
int i;
2652+
PyObject *map;
2653+
PyObject *keys = TOP();
2654+
if (!PyTuple_CheckExact(keys) ||
2655+
PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) {
2656+
PyErr_SetString(PyExc_SystemError,
2657+
"bad BUILD_CONST_KEY_MAP keys argument");
2658+
goto error;
2659+
}
2660+
map = _PyDict_NewPresized((Py_ssize_t)oparg);
2661+
if (map == NULL) {
2662+
goto error;
2663+
}
2664+
for (i = oparg; i > 0; i--) {
2665+
int err;
2666+
PyObject *key = PyTuple_GET_ITEM(keys, oparg - i);
2667+
PyObject *value = PEEK(i + 1);
2668+
err = PyDict_SetItem(map, key, value);
2669+
if (err != 0) {
2670+
Py_DECREF(map);
2671+
goto error;
2672+
}
2673+
}
2674+
2675+
Py_DECREF(POP());
2676+
while (oparg--) {
2677+
Py_DECREF(POP());
2678+
}
2679+
PUSH(map);
2680+
DISPATCH();
2681+
}
2682+
26502683
TARGET(BUILD_MAP_UNPACK_WITH_CALL)
26512684
TARGET(BUILD_MAP_UNPACK) {
26522685
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;

Python/compile.c

Lines changed: 156 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,8 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
980980
return 1 - (oparg & 0xFF);
981981
case BUILD_MAP:
982982
return 1 - 2*oparg;
983+
case BUILD_CONST_KEY_MAP:
984+
return -oparg;
983985
case LOAD_ATTR:
984986
return 0;
985987
case COMPARE_OP:
@@ -1234,6 +1236,15 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
12341236
return 0; \
12351237
}
12361238

1239+
/* Same as ADDOP_O, but steals a reference. */
1240+
#define ADDOP_N(C, OP, O, TYPE) { \
1241+
if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) { \
1242+
Py_DECREF((O)); \
1243+
return 0; \
1244+
} \
1245+
Py_DECREF((O)); \
1246+
}
1247+
12371248
#define ADDOP_NAME(C, OP, O, TYPE) { \
12381249
if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \
12391250
return 0; \
@@ -1309,6 +1320,44 @@ compiler_isdocstring(stmt_ty s)
13091320
return 0;
13101321
}
13111322

1323+
static int
1324+
is_const(expr_ty e)
1325+
{
1326+
switch (e->kind) {
1327+
case Constant_kind:
1328+
case Num_kind:
1329+
case Str_kind:
1330+
case Bytes_kind:
1331+
case Ellipsis_kind:
1332+
case NameConstant_kind:
1333+
return 1;
1334+
default:
1335+
return 0;
1336+
}
1337+
}
1338+
1339+
static PyObject *
1340+
get_const_value(expr_ty e)
1341+
{
1342+
switch (e->kind) {
1343+
case Constant_kind:
1344+
return e->v.Constant.value;
1345+
case Num_kind:
1346+
return e->v.Num.n;
1347+
case Str_kind:
1348+
return e->v.Str.s;
1349+
case Bytes_kind:
1350+
return e->v.Bytes.s;
1351+
case Ellipsis_kind:
1352+
return Py_Ellipsis;
1353+
case NameConstant_kind:
1354+
return e->v.NameConstant.value;
1355+
default:
1356+
assert(!is_const(e));
1357+
return NULL;
1358+
}
1359+
}
1360+
13121361
/* Compile a sequence of statements, checking for a docstring. */
13131362

13141363
static int
@@ -2604,19 +2653,9 @@ compiler_visit_stmt_expr(struct compiler *c, expr_ty value)
26042653
return 1;
26052654
}
26062655

2607-
switch (value->kind)
2608-
{
2609-
case Str_kind:
2610-
case Num_kind:
2611-
case Ellipsis_kind:
2612-
case Bytes_kind:
2613-
case NameConstant_kind:
2614-
case Constant_kind:
2656+
if (is_const(value)) {
26152657
/* ignore constant statement */
26162658
return 1;
2617-
2618-
default:
2619-
break;
26202659
}
26212660

26222661
VISIT(c, expr, value);
@@ -3095,6 +3134,49 @@ compiler_set(struct compiler *c, expr_ty e)
30953134
BUILD_SET, BUILD_SET_UNPACK);
30963135
}
30973136

3137+
static int
3138+
are_all_items_const(asdl_seq *seq, Py_ssize_t begin, Py_ssize_t end)
3139+
{
3140+
Py_ssize_t i;
3141+
for (i = begin; i < end; i++) {
3142+
expr_ty key = (expr_ty)asdl_seq_GET(seq, i);
3143+
if (key == NULL || !is_const(key))
3144+
return 0;
3145+
}
3146+
return 1;
3147+
}
3148+
3149+
static int
3150+
compiler_subdict(struct compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end)
3151+
{
3152+
Py_ssize_t i, n = end - begin;
3153+
PyObject *keys, *key;
3154+
if (n > 1 && are_all_items_const(e->v.Dict.keys, begin, end)) {
3155+
for (i = begin; i < end; i++) {
3156+
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i));
3157+
}
3158+
keys = PyTuple_New(n);
3159+
if (keys == NULL) {
3160+
return 0;
3161+
}
3162+
for (i = begin; i < end; i++) {
3163+
key = get_const_value((expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
3164+
Py_INCREF(key);
3165+
PyTuple_SET_ITEM(keys, i - begin, key);
3166+
}
3167+
ADDOP_N(c, LOAD_CONST, keys, consts);
3168+
ADDOP_I(c, BUILD_CONST_KEY_MAP, n);
3169+
}
3170+
else {
3171+
for (i = begin; i < end; i++) {
3172+
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
3173+
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i));
3174+
}
3175+
ADDOP_I(c, BUILD_MAP, n);
3176+
}
3177+
return 1;
3178+
}
3179+
30983180
static int
30993181
compiler_dict(struct compiler *c, expr_ty e)
31003182
{
@@ -3107,7 +3189,8 @@ compiler_dict(struct compiler *c, expr_ty e)
31073189
for (i = 0; i < n; i++) {
31083190
is_unpacking = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i) == NULL;
31093191
if (elements == 0xFFFF || (elements && is_unpacking)) {
3110-
ADDOP_I(c, BUILD_MAP, elements);
3192+
if (!compiler_subdict(c, e, i - elements, i))
3193+
return 0;
31113194
containers++;
31123195
elements = 0;
31133196
}
@@ -3116,13 +3199,12 @@ compiler_dict(struct compiler *c, expr_ty e)
31163199
containers++;
31173200
}
31183201
else {
3119-
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
3120-
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i));
31213202
elements++;
31223203
}
31233204
}
31243205
if (elements || containers == 0) {
3125-
ADDOP_I(c, BUILD_MAP, elements);
3206+
if (!compiler_subdict(c, e, n - elements, n))
3207+
return 0;
31263208
containers++;
31273209
}
31283210
/* 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)
32663348
return 1;
32673349
}
32683350

3351+
static int
3352+
compiler_subkwargs(struct compiler *c, asdl_seq *keywords, Py_ssize_t begin, Py_ssize_t end)
3353+
{
3354+
Py_ssize_t i, n = end - begin;
3355+
keyword_ty kw;
3356+
PyObject *keys, *key;
3357+
assert(n > 0);
3358+
if (n > 1) {
3359+
for (i = begin; i < end; i++) {
3360+
kw = asdl_seq_GET(keywords, i);
3361+
VISIT(c, expr, kw->value);
3362+
}
3363+
keys = PyTuple_New(n);
3364+
if (keys == NULL) {
3365+
return 0;
3366+
}
3367+
for (i = begin; i < end; i++) {
3368+
key = ((keyword_ty) asdl_seq_GET(keywords, i))->arg;
3369+
Py_INCREF(key);
3370+
PyTuple_SET_ITEM(keys, i - begin, key);
3371+
}
3372+
ADDOP_N(c, LOAD_CONST, keys, consts);
3373+
ADDOP_I(c, BUILD_CONST_KEY_MAP, n);
3374+
}
3375+
else {
3376+
/* a for loop only executes once */
3377+
for (i = begin; i < end; i++) {
3378+
kw = asdl_seq_GET(keywords, i);
3379+
ADDOP_O(c, LOAD_CONST, kw->arg, consts);
3380+
VISIT(c, expr, kw->value);
3381+
}
3382+
ADDOP_I(c, BUILD_MAP, n);
3383+
}
3384+
return 1;
3385+
}
3386+
32693387
/* shared code between compiler_call and compiler_class */
32703388
static int
32713389
compiler_call_helper(struct compiler *c,
@@ -3332,29 +3450,38 @@ compiler_call_helper(struct compiler *c,
33323450
if (kw->arg == NULL) {
33333451
/* A keyword argument unpacking. */
33343452
if (nseen) {
3335-
ADDOP_I(c, BUILD_MAP, nseen);
3453+
if (nsubkwargs) {
3454+
if (!compiler_subkwargs(c, keywords, i - nseen, i))
3455+
return 0;
3456+
nsubkwargs++;
3457+
}
3458+
else {
3459+
Py_ssize_t j;
3460+
for (j = 0; j < nseen; j++) {
3461+
VISIT(c, keyword, asdl_seq_GET(keywords, j));
3462+
}
3463+
nkw = nseen;
3464+
}
33363465
nseen = 0;
3337-
nsubkwargs++;
33383466
}
33393467
VISIT(c, expr, kw->value);
33403468
nsubkwargs++;
33413469
}
3342-
else if (nsubkwargs) {
3343-
/* A keyword argument and we already have a dict. */
3344-
ADDOP_O(c, LOAD_CONST, kw->arg, consts);
3345-
VISIT(c, expr, kw->value);
3346-
nseen++;
3347-
}
33483470
else {
3349-
/* keyword argument */
3350-
VISIT(c, keyword, kw)
3351-
nkw++;
3471+
nseen++;
33523472
}
33533473
}
33543474
if (nseen) {
3355-
/* Pack up any trailing keyword arguments. */
3356-
ADDOP_I(c, BUILD_MAP, nseen);
3357-
nsubkwargs++;
3475+
if (nsubkwargs) {
3476+
/* Pack up any trailing keyword arguments. */
3477+
if (!compiler_subkwargs(c, keywords, nelts - nseen, nelts))
3478+
return 0;
3479+
nsubkwargs++;
3480+
}
3481+
else {
3482+
VISIT_SEQ(c, keyword, keywords);
3483+
nkw = nseen;
3484+
}
33583485
}
33593486
if (nsubkwargs) {
33603487
code |= 2;

0 commit comments

Comments
 (0)