diff -r 470954641f3b Doc/library/dis.rst --- a/Doc/library/dis.rst Sun Jun 05 12:07:48 2016 +0000 +++ b/Doc/library/dis.rst Sun Jun 05 22:31:29 2016 +0300 @@ -779,6 +779,12 @@ All of the following opcodes use their a ``cmp_op[opname]``. +.. opcode:: CHAINED_COMPARE_OP (opname) + + Works as :opcode:`COMPARE_OP`, but if the result of a Boolean operation + is true, puts the right operand under TOS. + + .. opcode:: IMPORT_NAME (namei) Imports the module ``co_names[namei]``. TOS and TOS1 are popped and provide diff -r 470954641f3b Include/opcode.h --- a/Include/opcode.h Sun Jun 05 12:07:48 2016 +0000 +++ b/Include/opcode.h Sun Jun 05 22:31:29 2016 +0300 @@ -91,6 +91,7 @@ extern "C" { #define POP_JUMP_IF_FALSE 114 #define POP_JUMP_IF_TRUE 115 #define LOAD_GLOBAL 116 +#define CHAINED_COMPARE_OP 117 #define CONTINUE_LOOP 119 #define SETUP_LOOP 120 #define SETUP_EXCEPT 121 diff -r 470954641f3b Lib/importlib/_bootstrap_external.py --- a/Lib/importlib/_bootstrap_external.py Sun Jun 05 12:07:48 2016 +0000 +++ b/Lib/importlib/_bootstrap_external.py Sun Jun 05 22:31:29 2016 +0300 @@ -226,6 +226,7 @@ def _write_atomic(path, data, mode=0o666 # 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 CHAINED_COMPARE_OP opcode #XXXXX) # # 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 @@ def _write_atomic(path, data, mode=0o666 # 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__' diff -r 470954641f3b Lib/opcode.py --- a/Lib/opcode.py Sun Jun 05 12:07:48 2016 +0000 +++ b/Lib/opcode.py Sun Jun 05 22:31:29 2016 +0300 @@ -158,6 +158,9 @@ jabs_op('POP_JUMP_IF_TRUE', 115) # " name_op('LOAD_GLOBAL', 116) # Index in name list +def_op('CHAINED_COMPARE_OP', 117) # Chained comparison operator +hascompare.append(117) + jabs_op('CONTINUE_LOOP', 119) # Target address jrel_op('SETUP_LOOP', 120) # Distance to target address jrel_op('SETUP_EXCEPT', 121) # "" diff -r 470954641f3b PC/launcher.c --- a/PC/launcher.c Sun Jun 05 12:07:48 2016 +0000 +++ b/PC/launcher.c Sun Jun 05 22:31:29 2016 +0300 @@ -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 } }; diff -r 470954641f3b Python/ceval.c --- a/Python/ceval.c Sun Jun 05 12:07:48 2016 +0000 +++ b/Python/ceval.c Sun Jun 05 22:31:29 2016 +0300 @@ -2733,6 +2733,27 @@ PyEval_EvalFrameEx(PyFrameObject *f, int DISPATCH(); } + TARGET(CHAINED_COMPARE_OP) { + PyObject *right = TOP(); + PyObject *left = SECOND(); + PyObject *res = cmp_outcome(oparg, left, right); + int r; + if (res == NULL || (r = PyObject_IsTrue(res)) < 0) { + goto error; + } + Py_DECREF(left); + if (r == 1) { + SET_SECOND(right); + } + else { + (void)POP(); + Py_DECREF(right); + } + SET_TOP(res); + PREDICT(JUMP_IF_FALSE_OR_POP); + DISPATCH(); + } + TARGET(IMPORT_NAME) { _Py_IDENTIFIER(__import__); PyObject *name = GETITEM(names, oparg); @@ -2869,6 +2890,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int DISPATCH(); } + PREDICTED(JUMP_IF_FALSE_OR_POP); TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = TOP(); int err; diff -r 470954641f3b Python/compile.c --- a/Python/compile.c Sun Jun 05 12:07:48 2016 +0000 +++ b/Python/compile.c Sun Jun 05 22:31:29 2016 +0300 @@ -984,6 +984,8 @@ PyCompile_OpcodeStackEffect(int opcode, return 0; case COMPARE_OP: return -1; + case CHAINED_COMPARE_OP: + return 0; /* -1 if the result is false */ case IMPORT_NAME: return -1; case IMPORT_FROM: @@ -3141,26 +3143,24 @@ static int compiler_compare(struct compiler *c, expr_ty e) { Py_ssize_t i, n; - basicblock *cleanup = NULL; + basicblock *end = NULL; /* XXX the logic can be cleaned up for 1 or multiple comparisons */ VISIT(c, expr, e->v.Compare.left); n = asdl_seq_LEN(e->v.Compare.ops); assert(n > 0); if (n > 1) { - cleanup = compiler_new_block(c); - if (cleanup == NULL) + end = compiler_new_block(c); + if (end == NULL) return 0; VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0)); } for (i = 1; i < n; i++) { - ADDOP(c, DUP_TOP); - ADDOP(c, ROT_THREE); - ADDOP_I(c, COMPARE_OP, + ADDOP_I(c, CHAINED_COMPARE_OP, cmpop((cmpop_ty)(asdl_seq_GET( e->v.Compare.ops, i - 1)))); - ADDOP_JABS(c, JUMP_IF_FALSE_OR_POP, cleanup); + ADDOP_JABS(c, JUMP_IF_FALSE_OR_POP, end); NEXT_BLOCK(c); if (i < (n - 1)) VISIT(c, expr, @@ -3170,13 +3170,6 @@ compiler_compare(struct compiler *c, exp ADDOP_I(c, COMPARE_OP, cmpop((cmpop_ty)(asdl_seq_GET(e->v.Compare.ops, n - 1)))); if (n > 1) { - basicblock *end = compiler_new_block(c); - if (end == NULL) - return 0; - ADDOP_JREL(c, JUMP_FORWARD, end); - compiler_use_next_block(c, cleanup); - ADDOP(c, ROT_TWO); - ADDOP(c, POP_TOP); compiler_use_next_block(c, end); } return 1; diff -r 470954641f3b Python/opcode_targets.h --- a/Python/opcode_targets.h Sun Jun 05 12:07:48 2016 +0000 +++ b/Python/opcode_targets.h Sun Jun 05 22:31:29 2016 +0300 @@ -116,7 +116,7 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, - &&_unknown_opcode, + &&TARGET_CHAINED_COMPARE_OP, &&_unknown_opcode, &&TARGET_CONTINUE_LOOP, &&TARGET_SETUP_LOOP,