case ZEND_FETCH_OBJ_FUNC_ARG:
case ZEND_FETCH_DIM_FUNC_ARG:
if (call_stack[call - 1].func) {
- if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call].func, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
+ if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
opline->extended_value = 0;
opline->opcode -= 9;
} else {
break;
case ZEND_SEND_VAL:
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
- if (ARG_MUST_BE_SENT_BY_REF(call_stack[call].func, opline->op2.num)) {
+ if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
/* We won't convert it into_DO_FCALL to emit error at run-time */
- call_stack[call].opline = NULL;
+ call_stack[call - 1].opline = NULL;
} else {
opline->extended_value = ZEND_DO_FCALL;
}
break;
case ZEND_SEND_VAR:
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
- if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call].func, opline->op2.num)) {
+ if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
opline->opcode = ZEND_SEND_REF;
}
opline->extended_value = ZEND_DO_FCALL;
break;
case ZEND_SEND_VAR_NO_REF:
if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) {
- if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call].func, opline->op2.num)) {
+ if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND | ZEND_ARG_SEND_BY_REF;
} else if (opline->extended_value) {
opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND;
case ZEND_SEND_REF:
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
/* We won't handle run-time pass by reference */
- call_stack[call].opline = NULL;
+ call_stack[call - 1].opline = NULL;
}
break;
--- /dev/null
+--TEST--
+Test with optimization of function calls
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+class A {
+ public $obj;
+ public function test($a) {
+ }
+}
+
+function a(&$b) {
+ $b = "changed";
+ return "done";
+}
+
+$a = "a";
+$b = "b";
+$c = "c";
+$f = "a";
+
+/*
+ * INIT_FCALL_BY_NAME
+ * SEND_VAR
+ * DO_FCALL
+ * DO_FCALL_BY_NAME
+ */
+foo(a($a));
+var_dump($a);
+$a = "a";
+
+/*
+ * INIT_FCALL_BY_NAME
+ * INIT_FCALL_BY_NAME -- un-optimizable
+ * DO_FCALL_BY_NAME -- un-optimizable
+ * DO_FCALL_BY_NAME
+ */
+foo($f($a));
+var_dump($a);
+
+/*
+ * INIT_FCALL_BY_NAME
+ * ZEND_NEW
+ * DO_FCALL_BY_NAME
+ * DO_FCALL_BY_NAME
+ */
+foo(new A());
+
+/*
+ * INIT_FCALL_BY_NAME
+ * FETCH_OBJ_FUNC_ARG
+ * ZEND_SEND_VAR
+ * DO_FCALL_BY_NAME
+ */
+foo((new A)->obj);
+$obj = new A;
+ref($obj->obj);
+var_dump($obj->obj);
+
+ref(retarray()[0]);
+
+$a = "a";
+foo(a($a), $a, ref($b, $c), $obj);
+var_dump($a);
+var_dump($b);
+
+/*
+ * INIT_FCALL_BY_NAME
+ * SEND_VAL
+ * DO_FCALL_BY_NAME
+ */
+ref("xxx");
+
+function retarray() {
+ return array("retarray");
+}
+
+function foo($a) {
+ print_r(func_get_args());
+}
+
+function ref(&$b) {
+ $b = "changed";
+ return "ref";
+}
+--EXPECTF--
+Array
+(
+ [0] => done
+)
+string(7) "changed"
+Array
+(
+ [0] => done
+)
+string(7) "changed"
+Array
+(
+ [0] => A Object
+ (
+ [obj] =>
+ )
+
+)
+Array
+(
+ [0] =>
+)
+string(7) "changed"
+Array
+(
+ [0] => done
+ [1] => changed
+ [2] => ref
+ [3] => A Object
+ (
+ [obj] => changed
+ )
+
+)
+string(7) "changed"
+string(7) "changed"
+
+Fatal error: Cannot pass parameter 1 by reference in %soptimize_func_calls.php on line %d