diff Python/ceval.c @ 51853:643d8d4fc8eb

http://bugs.python.org/issue4715 This patch by Antoine Pitrou optimizes the bytecode for conditional branches by merging the following "POP_TOP" instruction into the conditional jump. For example, the list comprehension "[x for x in l if not x]" produced the following bytecode: 1 0 BUILD_LIST 0 3 LOAD_FAST 0 (.0) >> 6 FOR_ITER 23 (to 32) 9 STORE_FAST 1 (x) 12 LOAD_FAST 1 (x) 15 JUMP_IF_TRUE 10 (to 28) 18 POP_TOP 19 LOAD_FAST 1 (x) 22 LIST_APPEND 2 25 JUMP_ABSOLUTE 6 >> 28 POP_TOP 29 JUMP_ABSOLUTE 6 >> 32 RETURN_VALUE but after the patch it produces the following bytecode: 1 0 BUILD_LIST 0 3 LOAD_FAST 0 (.0) >> 6 FOR_ITER 18 (to 27) 9 STORE_FAST 1 (x) 12 LOAD_FAST 1 (x) 15 POP_JUMP_IF_TRUE 6 18 LOAD_FAST 1 (x) 21 LIST_APPEND 2 24 JUMP_ABSOLUTE 6 >> 27 RETURN_VALUE Notice that not only the code is shorter, but the conditional jump (POP_JUMP_IF_TRUE) jumps right to the start of the loop instead of going through the JUMP_ABSOLUTE at the end. "continue" statements are helped similarly. Furthermore, the old jump opcodes (JUMP_IF_FALSE, JUMP_IF_TRUE) have been replaced by two new opcodes: - JUMP_IF_TRUE_OR_POP, which jumps if true and pops otherwise - JUMP_IF_FALSE_OR_POP, which jumps if false and pops otherwise
author Jeffrey Yasskin <jyasskin@gmail.com>
date Wed, 25 Feb 2009 02:25:04 +0000
parents d86e23318b41
children 3722ce458318
line wrap: on
line diff
--- a/Python/ceval.c	Wed Feb 25 00:58:47 2009 +0000
+++ b/Python/ceval.c	Wed Feb 25 02:25:04 2009 +0000
@@ -1295,7 +1295,6 @@
 			SETLOCAL(oparg, v);
 			FAST_DISPATCH();
 
-		PREDICTED(POP_TOP);
 		TARGET(POP_TOP)
 			v = POP();
 			Py_DECREF(v);
@@ -2204,8 +2203,8 @@
 			Py_DECREF(w);
 			SET_TOP(x);
 			if (x == NULL) break;
-			PREDICT(JUMP_IF_FALSE);
-			PREDICT(JUMP_IF_TRUE);
+			PREDICT(POP_JUMP_IF_FALSE);
+			PREDICT(POP_JUMP_IF_TRUE);
 			DISPATCH();
 
 		TARGET(IMPORT_NAME)
@@ -2282,44 +2281,95 @@
 			JUMPBY(oparg);
 			FAST_DISPATCH();
 
-		PREDICTED_WITH_ARG(JUMP_IF_FALSE);
-		TARGET(JUMP_IF_FALSE)
-			w = TOP();
+		PREDICTED_WITH_ARG(POP_JUMP_IF_FALSE);
+		TARGET(POP_JUMP_IF_FALSE)
+			w = POP();
 			if (w == Py_True) {
-				PREDICT(POP_TOP);
+				Py_DECREF(w);
 				FAST_DISPATCH();
 			}
 			if (w == Py_False) {
-				JUMPBY(oparg);
+				Py_DECREF(w);
+				JUMPTO(oparg);
 				FAST_DISPATCH();
 			}
 			err = PyObject_IsTrue(w);
+			Py_DECREF(w);
 			if (err > 0)
 				err = 0;
 			else if (err == 0)
-				JUMPBY(oparg);
+				JUMPTO(oparg);
+			else
+				break;
+			DISPATCH();
+
+		PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE);
+		TARGET(POP_JUMP_IF_TRUE)
+			w = POP();
+			if (w == Py_False) {
+				Py_DECREF(w);
+				FAST_DISPATCH();
+			}
+			if (w == Py_True) {
+				Py_DECREF(w);
+				JUMPTO(oparg);
+				FAST_DISPATCH();
+			}
+			err = PyObject_IsTrue(w);
+			Py_DECREF(w);
+			if (err > 0) {
+				err = 0;
+				JUMPTO(oparg);
+			}
+			else if (err == 0)
+				;
 			else
 				break;
 			DISPATCH();
 
-		PREDICTED_WITH_ARG(JUMP_IF_TRUE);
-		TARGET(JUMP_IF_TRUE)
+		TARGET(JUMP_IF_FALSE_OR_POP)
+			w = TOP();
+			if (w == Py_True) {
+				STACKADJ(-1);
+				Py_DECREF(w);
+				FAST_DISPATCH();
+			}
+			if (w == Py_False) {
+				JUMPTO(oparg);
+				FAST_DISPATCH();
+			}
+			err = PyObject_IsTrue(w);
+			if (err > 0) {
+				STACKADJ(-1);
+				Py_DECREF(w);
+				err = 0;
+			}
+			else if (err == 0)
+				JUMPTO(oparg);
+			else
+				break;
+			DISPATCH();
+
+		TARGET(JUMP_IF_TRUE_OR_POP)
 			w = TOP();
 			if (w == Py_False) {
-				PREDICT(POP_TOP);
+				STACKADJ(-1);
+				Py_DECREF(w);
 				FAST_DISPATCH();
 			}
 			if (w == Py_True) {
-				JUMPBY(oparg);
+				JUMPTO(oparg);
 				FAST_DISPATCH();
 			}
 			err = PyObject_IsTrue(w);
 			if (err > 0) {
 				err = 0;
-				JUMPBY(oparg);
+				JUMPTO(oparg);
 			}
-			else if (err == 0)
-				;
+			else if (err == 0) {
+				STACKADJ(-1);
+				Py_DECREF(w);
+			}
 			else
 				break;
 			DISPATCH();