Hi,

I've already posted this patch and it has since been reviewed and improved. 
I'm re-posting it for discussion before eventually commiting it.

The ternary operator always copies its second or third operand, which is very 
slow compared to an if/else when the operand is an array for example:

$a = range(0,9);

// this takes 0.3 seconds here:

for ($i = 0; $i < 5000000; ++$i) {
        if (true) {
                $b = $a;
        } else {
                $b = $a;
        }
}

// this takes 3.8 seconds:

for ($i = 0; $i < 5000000; ++$i) {
        $b = true ? $a : $a;
}

I've tried to reduce the performance hit by avoiding the copy when possible 
(patch attached).

Benchmark:

Without patch: (the numbers are the time taken to run the code a certain 
amount of times)

$int = 0;
$ary = array(1,2,3,4,5,6,7,8,9);

true ? 1 : 0        0.124
true ? 1+0 : 0      0.109
true ? $ary : 0     2.020 !
true ? $int : 0     0.103
true ? ${'ary'} : 0 2.290 !
true ?: 0           0.091
1+0 ?: 0            0.086
$ary ?: 0           2.151 !
${'var'} ?: 0       2.317 !

With patch:

true ? 1 : 0        0.124
true ? 1+0 : 0      0.195
true ? $ary : 0     0.103
true ? $int : 0     0.089
true ? ${'ary'} : 0 0.103
true ?: 0           0.086
1+0 ?: 0            0.159
$cv ?: 0            0.090
${'var'} ?: 0       0.089


The array copying overhead is eliminated. There is however a slowdown in some 
of the cases, but overall there is no completely unexpected performance hit as 
it is the case currently.

What do you think ? Is there any objection ?

Best regards,
diff --git a/Zend/micro_bench.php b/Zend/micro_bench.php
index 87a1b15..7052588 100644
--- a/Zend/micro_bench.php
+++ b/Zend/micro_bench.php
@@ -202,6 +202,35 @@ function read_str_offset($n) {
 	}
 }
 
+function issetor($n) {
+	$val = array(0,1,2,3,4,5,6,7,8,9);
+	for ($i = 0; $i < $n; ++$i) {
+		$x = $val ?: null;
+	}
+}
+
+function issetor2($n) {
+	$f = false; $j = 0;
+	for ($i = 0; $i < $n; ++$i) {
+		$x = $f ?: $j + 1;
+	}
+}
+
+function ternary($n) {
+	$val = array(0,1,2,3,4,5,6,7,8,9);
+	$f = false;
+	for ($i = 0; $i < $n; ++$i) {
+		$x = $f ? null : $val;
+	}
+}
+
+function ternary2($n) {
+	$f = false; $j = 0;
+	for ($i = 0; $i < $n; ++$i) {
+		$x = $f ? $f : $j + 1;
+	}
+}
+
 /*****/
 
 function empty_loop($n) {
@@ -318,4 +347,12 @@ read_hash(N);
 $t = end_test($t, '$x = $hash[\'v\']', $overhead);
 read_str_offset(N);
 $t = end_test($t, '$x = $str[0]', $overhead);
+issetor(N);
+$t = end_test($t, '$x = $a ?: null', $overhead);
+issetor2(N);
+$t = end_test($t, '$x = $f ?: tmp', $overhead);
+ternary(N);
+$t = end_test($t, '$x = $f ? $f : $a', $overhead);
+ternary2(N);
+$t = end_test($t, '$x = $f ? $f : tmp', $overhead);
 total($t0, "Total");
diff --git a/Zend/tests/ternary.phpt b/Zend/tests/ternary.phpt
new file mode 100644
index 0000000..d1a6d45
--- /dev/null
+++ b/Zend/tests/ternary.phpt
@@ -0,0 +1,429 @@
+--TEST--
+?: and ternary operators
+--FILE--
+<?php
+$a = "val_of_a";
+$b = "val_of_b";
+
+echo "-- 1 --\n";
+var_dump(true ? "foo" : "bar");
+true ? "foo" : "bar";
+$z = true ? "foo" : "bar";
+
+echo "-- 2 --\n";
+var_dump(true ? "foo" : "c"."d");
+true ? "foo" : "c"."d";
+$z = true ? "foo" : "c"."d";
+
+echo "-- 3 --\n";
+var_dump(true ? "foo" : $b);
+true ? "foo" : $b;
+$z = true ? "foo" : $b;
+
+echo "-- 4 --\n";
+var_dump(true ? "foo" : ${'b'});
+true ? "foo" : ${'b'};
+$z = true ? "foo" : ${'b'};
+
+echo "-- 5 --\n";
+var_dump(true ? "a"."b" : "bar");
+true ? "a"."b" : "bar";
+$z = true ? "a"."b" : "bar";
+
+echo "-- 6 --\n";
+var_dump(true ? "a"."b" : "c"."d");
+true ? "a"."b" : "c"."d";
+$z = true ? "a"."b" : "c"."d";
+
+echo "-- 7 --\n";
+var_dump(true ? "a"."b" : $b);
+true ? "a"."b" : $b;
+$z = true ? "a"."b" : $b;
+
+echo "-- 8 --\n";
+var_dump(true ? "a"."b" : ${'b'});
+true ? "a"."b" : ${'b'};
+$z = true ? "a"."b" : ${'b'};
+
+echo "-- 9 --\n";
+var_dump(true ? $a : "bar");
+true ? $a : "bar";
+$z = true ? $a : "bar";
+
+echo "-- 10 --\n";
+var_dump(true ? $a : "c"."d");
+true ? $a : "c"."d";
+$z = true ? $a : "c"."d";
+
+echo "-- 11 --\n";
+var_dump(true ? $a : $b);
+true ? $a : $b;
+$z = true ? $a : $b;
+
+echo "-- 12 --\n";
+var_dump(true ? $a : ${'b'});
+true ? $a : ${'b'};
+$z = true ? $a : ${'b'};
+
+echo "-- 13 --\n";
+var_dump(true ? ${'a'} : "bar");
+true ? ${'a'} : "bar";
+$z = true ? ${'a'} : "bar";
+
+echo "-- 14 --\n";
+var_dump(true ? ${'a'} : "c"."d");
+true ? ${'a'} : "c"."d";
+$z = true ? ${'a'} : "c"."d";
+
+echo "-- 15 --\n";
+var_dump(true ? ${'a'} : $b);
+true ? ${'a'} : $b;
+$z = true ? ${'a'} : $b;
+
+echo "-- 16 --\n";
+var_dump(true ? ${'a'} : ${'b'});
+true ? ${'a'} : ${'b'};
+$z = true ? ${'a'} : ${'b'};
+
+echo "-- 17 --\n";
+var_dump(false ? "foo" : "bar");
+false ? "foo" : "bar";
+$z = false ? "foo" : "bar";
+
+echo "-- 18 --\n";
+var_dump(false ? "foo" : "c"."d");
+false ? "foo" : "c"."d";
+$z = false ? "foo" : "c"."d";
+
+echo "-- 19 --\n";
+var_dump(false ? "foo" : $b);
+false ? "foo" : $b;
+$z = false ? "foo" : $b;
+
+echo "-- 20 --\n";
+var_dump(false ? "foo" : ${'b'});
+false ? "foo" : ${'b'};
+$z = false ? "foo" : ${'b'};
+
+echo "-- 21 --\n";
+var_dump(false ? "a"."b" : "bar");
+false ? "a"."b" : "bar";
+$z = false ? "a"."b" : "bar";
+
+echo "-- 22 --\n";
+var_dump(false ? "a"."b" : "c"."d");
+false ? "a"."b" : "c"."d";
+$z = false ? "a"."b" : "c"."d";
+
+echo "-- 23 --\n";
+var_dump(false ? "a"."b" : $b);
+false ? "a"."b" : $b;
+$z = false ? "a"."b" : $b;
+
+echo "-- 24 --\n";
+var_dump(false ? "a"."b" : ${'b'});
+false ? "a"."b" : ${'b'};
+$z = false ? "a"."b" : ${'b'};
+
+echo "-- 25 --\n";
+var_dump(false ? $a : "bar");
+false ? $a : "bar";
+$z = false ? $a : "bar";
+
+echo "-- 26 --\n";
+var_dump(false ? $a : "c"."d");
+false ? $a : "c"."d";
+$z = false ? $a : "c"."d";
+
+echo "-- 27 --\n";
+var_dump(false ? $a : $b);
+false ? $a : $b;
+$z = false ? $a : $b;
+
+echo "-- 28 --\n";
+var_dump(false ? $a : ${'b'});
+false ? $a : ${'b'};
+$z = false ? $a : ${'b'};
+
+echo "-- 29 --\n";
+var_dump(false ? ${'a'} : "bar");
+false ? ${'a'} : "bar";
+$z = false ? ${'a'} : "bar";
+
+echo "-- 30 --\n";
+var_dump(false ? ${'a'} : "c"."d");
+false ? ${'a'} : "c"."d";
+$z = false ? ${'a'} : "c"."d";
+
+echo "-- 31 --\n";
+var_dump(false ? ${'a'} : $b);
+false ? ${'a'} : $b;
+$z = false ? ${'a'} : $b;
+
+echo "-- 32 --\n";
+var_dump(false ? ${'a'} : ${'b'});
+false ? ${'a'} : ${'b'};
+$z = false ? ${'a'} : ${'b'};
+
+
+
+$a0 = array();
+$a1 = array(1);
+
+echo "-- 33 --\n";
+var_dump("0" ?: "bar");
+"0" ?: "bar";
+$z = "0" ?: "bar";
+
+echo "-- 34 --\n";
+var_dump("0" ?: "c"."d");
+"0" ?: "c"."d";
+$z = "0" ?: "c"."d";
+
+echo "-- 35 --\n";
+var_dump("0" ?: $b);
+"0" ?: $b;
+$z = "0" ?: $b;
+
+echo "-- 36 --\n";
+var_dump("0" ?: ${'b'});
+"0" ?: ${'b'};
+$z = "0" ?: ${'b'};
+
+echo "-- 37 --\n";
+var_dump("1" ?: "bar");
+"1" ?: "bar";
+$z = "1" ?: "bar";
+
+echo "-- 38 --\n";
+var_dump("1" ?: "c"."d");
+"1" ?: "c"."d";
+$z = "1" ?: "c"."d";
+
+echo "-- 39 --\n";
+var_dump("1" ?: $b);
+"1" ?: $b;
+$z = "1" ?: $b;
+
+echo "-- 40 --\n";
+var_dump("1" ?: ${'b'});
+"1" ?: ${'b'};
+$z = "1" ?: ${'b'};
+
+echo "-- 41 --\n";
+var_dump($a0 ?: "bar");
+$a0 ?: "bar";
+$z = $a0 ?: "bar";
+
+echo "-- 42 --\n";
+var_dump($a0 ?: "c"."d");
+$a0 ?: "c"."d";
+$z = $a0 ?: "c"."d";
+
+echo "-- 43 --\n";
+var_dump($a0 ?: $b);
+$a0 ?: $b;
+$z = $a0 ?: $b;
+
+echo "-- 44 --\n";
+var_dump($a0 ?: ${'b'});
+$a0 ?: ${'b'};
+$z = $a0 ?: ${'b'};
+
+echo "-- 45 --\n";
+var_dump($a1 ?: "bar");
+$a1 ?: "bar";
+$z = $a1 ?: "bar";
+
+echo "-- 46 --\n";
+var_dump($a1 ?: "c"."d");
+$a1 ?: "c"."d";
+$z = $a1 ?: "c"."d";
+
+echo "-- 47 --\n";
+var_dump($a1 ?: $b);
+$a1 ?: $b;
+$z = $a1 ?: $b;
+
+echo "-- 48 --\n";
+var_dump($a1 ?: ${'b'});
+$a1 ?: ${'b'};
+$z = $a1 ?: ${'b'};
+
+echo "-- 49 --\n";
+var_dump(${'a0'} ?: "bar");
+${'a0'} ?: "bar";
+$z = ${'a0'} ?: "bar";
+
+echo "-- 50 --\n";
+var_dump(${'a0'} ?: "c"."d");
+${'a0'} ?: "c"."d";
+$z = ${'a0'} ?: "c"."d";
+
+echo "-- 51 --\n";
+var_dump(${'a0'} ?: $b);
+${'a0'} ?: $b;
+$z = ${'a0'} ?: $b;
+
+echo "-- 52 --\n";
+var_dump(${'a0'} ?: ${'b'});
+${'a0'} ?: ${'b'};
+$z = ${'a0'} ?: ${'b'};
+
+echo "-- 53 --\n";
+var_dump(${'a1'} ?: "bar");
+${'a1'} ?: "bar";
+$z = ${'a1'} ?: "bar";
+
+echo "-- 54 --\n";
+var_dump(${'a1'} ?: "c"."d");
+${'a1'} ?: "c"."d";
+$z = ${'a1'} ?: "c"."d";
+
+echo "-- 55 --\n";
+var_dump(${'a1'} ?: $b);
+${'a1'} ?: $b;
+$z = ${'a1'} ?: $b;
+
+echo "-- 56 --\n";
+var_dump(${'a1'} ?: ${'b'});
+${'a1'} ?: ${'b'};
+$z = ${'a1'} ?: ${'b'};
+
+--EXPECT--
+-- 1 --
+string(3) "foo"
+-- 2 --
+string(3) "foo"
+-- 3 --
+string(3) "foo"
+-- 4 --
+string(3) "foo"
+-- 5 --
+string(2) "ab"
+-- 6 --
+string(2) "ab"
+-- 7 --
+string(2) "ab"
+-- 8 --
+string(2) "ab"
+-- 9 --
+string(8) "val_of_a"
+-- 10 --
+string(8) "val_of_a"
+-- 11 --
+string(8) "val_of_a"
+-- 12 --
+string(8) "val_of_a"
+-- 13 --
+string(8) "val_of_a"
+-- 14 --
+string(8) "val_of_a"
+-- 15 --
+string(8) "val_of_a"
+-- 16 --
+string(8) "val_of_a"
+-- 17 --
+string(3) "bar"
+-- 18 --
+string(2) "cd"
+-- 19 --
+string(8) "val_of_b"
+-- 20 --
+string(8) "val_of_b"
+-- 21 --
+string(3) "bar"
+-- 22 --
+string(2) "cd"
+-- 23 --
+string(8) "val_of_b"
+-- 24 --
+string(8) "val_of_b"
+-- 25 --
+string(3) "bar"
+-- 26 --
+string(2) "cd"
+-- 27 --
+string(8) "val_of_b"
+-- 28 --
+string(8) "val_of_b"
+-- 29 --
+string(3) "bar"
+-- 30 --
+string(2) "cd"
+-- 31 --
+string(8) "val_of_b"
+-- 32 --
+string(8) "val_of_b"
+-- 33 --
+string(3) "bar"
+-- 34 --
+string(2) "cd"
+-- 35 --
+string(8) "val_of_b"
+-- 36 --
+string(8) "val_of_b"
+-- 37 --
+string(1) "1"
+-- 38 --
+string(1) "1"
+-- 39 --
+string(1) "1"
+-- 40 --
+string(1) "1"
+-- 41 --
+string(3) "bar"
+-- 42 --
+string(2) "cd"
+-- 43 --
+string(8) "val_of_b"
+-- 44 --
+string(8) "val_of_b"
+-- 45 --
+array(1) {
+  [0]=>
+  int(1)
+}
+-- 46 --
+array(1) {
+  [0]=>
+  int(1)
+}
+-- 47 --
+array(1) {
+  [0]=>
+  int(1)
+}
+-- 48 --
+array(1) {
+  [0]=>
+  int(1)
+}
+-- 49 --
+string(3) "bar"
+-- 50 --
+string(2) "cd"
+-- 51 --
+string(8) "val_of_b"
+-- 52 --
+string(8) "val_of_b"
+-- 53 --
+array(1) {
+  [0]=>
+  int(1)
+}
+-- 54 --
+array(1) {
+  [0]=>
+  int(1)
+}
+-- 55 --
+array(1) {
+  [0]=>
+  int(1)
+}
+-- 56 --
+array(1) {
+  [0]=>
+  int(1)
+}
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index f8fe4ef..221d4f9 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -1469,7 +1469,8 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
 			&& opline->result.var == op1->u.op.var) {
 			if (opline->opcode == ZEND_FETCH_R ||
 			    opline->opcode == ZEND_FETCH_DIM_R ||
-			    opline->opcode == ZEND_FETCH_OBJ_R) {
+			    opline->opcode == ZEND_FETCH_OBJ_R ||
+			    opline->opcode == ZEND_QM_ASSIGN_VAR) {
 				/* It's very rare and useless case. It's better to use
 				   additional FREE opcode and simplify the FETCH handlers
 				   their selves */
@@ -6308,8 +6309,13 @@ void zend_do_jmp_set(const znode *value, znode *jmp_token, znode *colon_token TS
 	int op_number = get_next_op_number(CG(active_op_array));
 	zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
-	opline->opcode = ZEND_JMP_SET;
-	opline->result_type = IS_TMP_VAR;
+	if (value->op_type == IS_VAR || value->op_type == IS_CV) {
+		opline->opcode = ZEND_JMP_SET_VAR;
+		opline->result_type = IS_VAR;
+	} else {
+		opline->opcode = ZEND_JMP_SET;
+		opline->result_type = IS_TMP_VAR;
+	}
 	opline->result.var = get_temporary_variable(CG(active_op_array));
 	SET_NODE(opline->op1, value);
 	SET_UNUSED(opline->op2);
@@ -6326,9 +6332,20 @@ void zend_do_jmp_set_else(znode *result, const znode *false_value, const znode *
 {
 	zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
-	opline->opcode = ZEND_QM_ASSIGN;
-	opline->extended_value = 0;
 	SET_NODE(opline->result, colon_token);
+	if (colon_token->op_type == IS_TMP_VAR) {
+		if (false_value->op_type == IS_VAR || false_value->op_type == IS_CV) {
+			CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].opcode = ZEND_JMP_SET_VAR;
+			CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].result_type = IS_VAR;
+			opline->opcode = ZEND_QM_ASSIGN_VAR;
+			opline->result_type = IS_VAR;
+		} else {
+			opline->opcode = ZEND_QM_ASSIGN;
+		}
+	} else {
+		opline->opcode = ZEND_QM_ASSIGN_VAR;
+	}
+	opline->extended_value = 0;
 	SET_NODE(opline->op1, false_value);
 	SET_UNUSED(opline->op2);
 	
@@ -6363,8 +6380,13 @@ void zend_do_qm_true(const znode *true_value, znode *qm_token, znode *colon_toke
 
 	CG(active_op_array)->opcodes[qm_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array))+1; /* jmp over the ZEND_JMP */
 
-	opline->opcode = ZEND_QM_ASSIGN;
-	opline->result_type = IS_TMP_VAR;
+	if (true_value->op_type == IS_VAR || true_value->op_type == IS_CV) {
+		opline->opcode = ZEND_QM_ASSIGN_VAR;
+		opline->result_type = IS_VAR;
+	} else {
+		opline->opcode = ZEND_QM_ASSIGN;
+		opline->result_type = IS_TMP_VAR;
+	}
 	opline->result.var = get_temporary_variable(CG(active_op_array));
 	SET_NODE(opline->op1, true_value);
 	SET_UNUSED(opline->op2);
@@ -6383,8 +6405,19 @@ void zend_do_qm_false(znode *result, const znode *false_value, const znode *qm_t
 {
 	zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
-	opline->opcode = ZEND_QM_ASSIGN;
 	SET_NODE(opline->result, qm_token);
+	if (qm_token->op_type == IS_TMP_VAR) {
+		if (false_value->op_type == IS_VAR || false_value->op_type == IS_CV) {
+			CG(active_op_array)->opcodes[colon_token->u.op.opline_num - 1].opcode = ZEND_QM_ASSIGN_VAR;
+			CG(active_op_array)->opcodes[colon_token->u.op.opline_num - 1].result_type = IS_VAR;
+			opline->opcode = ZEND_QM_ASSIGN_VAR;
+			opline->result_type = IS_VAR;
+		} else {
+			opline->opcode = ZEND_QM_ASSIGN;
+		}
+	} else {
+		opline->opcode = ZEND_QM_ASSIGN_VAR;
+	}
 	SET_NODE(opline->op1, false_value);
 	SET_UNUSED(opline->op2);
 
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 5ae15f4..888058d 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1299,6 +1299,7 @@ void execute_new_code(TSRMLS_D) /* {{{ */
 			case ZEND_JMPZ_EX:
 			case ZEND_JMPNZ_EX:
 			case ZEND_JMP_SET:
+			case ZEND_JMP_SET_VAR:
 				opline->op2.jmp_addr = &CG(active_op_array)->opcodes[opline->op2.opline_num];
 				break;
 		}
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index 9d4f3e7..65b9aa5 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -529,6 +529,7 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
 			case ZEND_JMPZ_EX:
 			case ZEND_JMPNZ_EX:
 			case ZEND_JMP_SET:
+			case ZEND_JMP_SET_VAR:
 				opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num];
 				break;
 		}
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 4e944a1..238864e 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -4661,8 +4661,45 @@ ZEND_VM_HANDLER(152, ZEND_JMP_SET, CONST|TMP|VAR|CV, ANY)
 
 	if (i_zend_is_true(value)) {
 		ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, value);
-		zendi_zval_copy_ctor(EX_T(opline->result.var).tmp_var);
-		FREE_OP1();
+		if (!IS_OP1_TMP_FREE()) {
+			zendi_zval_copy_ctor(EX_T(opline->result.var).tmp_var);
+		}
+		FREE_OP1_IF_VAR();
+#if DEBUG_ZEND>=2
+		printf("Conditional jmp to %d\n", opline->op2.opline_num);
+#endif
+		ZEND_VM_JMP(opline->op2.jmp_addr);
+	}
+
+	FREE_OP1();
+	CHECK_EXCEPTION();
+	ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_HANDLER(158, ZEND_JMP_SET_VAR, CONST|TMP|VAR|CV, ANY)
+{
+	USE_OPLINE
+	zend_free_op free_op1;
+	zval *value, *ret;
+
+	SAVE_OPLINE();
+	value = GET_OP1_ZVAL_PTR(BP_VAR_R);
+
+	if (i_zend_is_true(value)) {
+		if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
+			Z_ADDREF_P(value);
+			EX_T(opline->result.var).var.ptr = value;
+			EX_T(opline->result.var).var.ptr_ptr = NULL;
+		} else {
+			ALLOC_ZVAL(ret);
+			INIT_PZVAL_COPY(ret, value);
+			EX_T(opline->result.var).var.ptr = ret;
+			EX_T(opline->result.var).var.ptr_ptr = NULL;
+			if (!IS_OP1_TMP_FREE()) {
+				zval_copy_ctor(EX_T(opline->result.var).var.ptr);
+			}
+		}
+		FREE_OP1_IF_VAR();
 #if DEBUG_ZEND>=2
 		printf("Conditional jmp to %d\n", opline->op2.opline_num);
 #endif
@@ -4692,6 +4729,34 @@ ZEND_VM_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY)
 	ZEND_VM_NEXT_OPCODE();
 }
 
+ZEND_VM_HANDLER(157, ZEND_QM_ASSIGN_VAR, CONST|TMP|VAR|CV, ANY)
+{
+	USE_OPLINE
+	zend_free_op free_op1;
+	zval *value, *ret;
+
+	SAVE_OPLINE();
+	value = GET_OP1_ZVAL_PTR(BP_VAR_R);
+
+	if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
+		Z_ADDREF_P(value);
+		EX_T(opline->result.var).var.ptr = value;
+		EX_T(opline->result.var).var.ptr_ptr = NULL;
+	} else {
+		ALLOC_ZVAL(ret);
+		INIT_PZVAL_COPY(ret, value);
+		EX_T(opline->result.var).var.ptr = ret;
+		EX_T(opline->result.var).var.ptr_ptr = NULL;
+		if (!IS_OP1_TMP_FREE()) {
+			zval_copy_ctor(EX_T(opline->result.var).var.ptr);
+		}
+	}
+
+	FREE_OP1_IF_VAR();
+	CHECK_EXCEPTION();
+	ZEND_VM_NEXT_OPCODE();
+}
+
 ZEND_VM_HANDLER(101, ZEND_EXT_STMT, ANY, ANY)
 {
 	SAVE_OPLINE();
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index ed80ddc..9b76b0e 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -157,3 +157,5 @@
 #define ZEND_ADD_TRAIT                       154
 #define ZEND_BIND_TRAITS                     155
 #define ZEND_SEPARATE                        156
+#define ZEND_QM_ASSIGN_VAR                   157
+#define ZEND_JMP_SET_VAR                     158

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to