]> granicus.if.org Git - php/commitdiff
Only replace IN_ARRAY result type for JMPZ/JMPNZ
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 30 Nov 2020 10:09:28 +0000 (11:09 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 30 Nov 2020 10:18:21 +0000 (11:18 +0100)
Replacing the result type in the general case is dangerous,
because not all opcodes support both VAR and TMP. One common case
is the in_array() result being passed to SEND_VAR, which would
have to be changed to SEND_VAL.

Rather than complicating this logic, reduce the scope to only
doing the type replacement for JMPZ and JMPNZ. The only reason
we're doing this in the first place is to enable the smart branch
optimization, so we can limit it to the relevant opcodes. Replacing
the result type may be marginally useful in other cases as well
(as it may avoid reference checks), but not worth the bother.

ext/opcache/Optimizer/dfa_pass.c
ext/opcache/tests/opt/sccp_in_array.phpt [new file with mode: 0644]

index 765b023f07ee9beb58e325407308dd0451bca7a2..92a7470b9e0ad3dd5ba56392d877273a521b237c 100644 (file)
@@ -474,16 +474,16 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
                                                        int var = ssa_op->result_def;
                                                        int use = ssa->vars[var].use_chain;
 
-                                                       if (ssa->vars[var].phi_use_chain == NULL) {
-                                                               if (ssa->ops[use].op1_use == var
-                                                                && ssa->ops[use].op1_use_chain == -1) {
-                                                                       call_info->caller_call_opline->result_type = IS_TMP_VAR;
-                                                                       op_array->opcodes[use].op1_type = IS_TMP_VAR;
-                                                               } else if (ssa->ops[use].op2_use == var
-                                                                && ssa->ops[use].op2_use_chain == -1) {
-                                                                       call_info->caller_call_opline->result_type = IS_TMP_VAR;
-                                                                       op_array->opcodes[use].op2_type = IS_TMP_VAR;
-                                                               }
+                                                       /* If the result is used only in a JMPZ/JMPNZ, replace result type with
+                                                        * IS_TMP_VAR, which will enable use of smart branches. Don't do this
+                                                        * in other cases, as not all opcodes support both VAR and TMP. */
+                                                       if (ssa->vars[var].phi_use_chain == NULL
+                                                               && ssa->ops[use].op1_use == var
+                                                               && ssa->ops[use].op1_use_chain == -1
+                                                               && (op_array->opcodes[use].opcode == ZEND_JMPZ
+                                                                       || op_array->opcodes[use].opcode == ZEND_JMPNZ)) {
+                                                               call_info->caller_call_opline->result_type = IS_TMP_VAR;
+                                                               op_array->opcodes[use].op1_type = IS_TMP_VAR;
                                                        }
                                                }
                                        }
diff --git a/ext/opcache/tests/opt/sccp_in_array.phpt b/ext/opcache/tests/opt/sccp_in_array.phpt
new file mode 100644 (file)
index 0000000..e7716b8
--- /dev/null
@@ -0,0 +1,14 @@
+--TEST--
+Don't replace IN_ARRAY result type if the using opcode doesn't support it
+--FILE--
+<?php
+
+function test($v) {
+    $ary = ['x', 'y'];
+    var_dump(in_array($v, $ary));
+}
+test('x');
+
+?>
+--EXPECT--
+bool(true)