Skip to content

Commit 9feaae3

Browse files
committed
Omit free for frameless calls returning non-RC types
1 parent 241e43f commit 9feaae3

2 files changed

Lines changed: 53 additions & 3 deletions

File tree

Zend/zend_compile.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,17 @@ static void zend_do_free(znode *op1) /* {{{ */
795795
case ZEND_PRE_DEC:
796796
SET_UNUSED(opline->result);
797797
return;
798+
case ZEND_FRAMELESS_ICALL_0:
799+
case ZEND_FRAMELESS_ICALL_1:
800+
case ZEND_FRAMELESS_ICALL_2:
801+
case ZEND_FRAMELESS_ICALL_3: {
802+
const zend_type return_type = ZEND_FLF_FUNC(opline)->common.arg_info[-1].type;
803+
if (!ZEND_TYPE_IS_COMPLEX(return_type)
804+
&& !(ZEND_TYPE_PURE_MASK(return_type) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
805+
return;
806+
}
807+
break;
808+
}
798809
}
799810
}
800811

@@ -816,9 +827,11 @@ static void zend_do_free(znode *op1) /* {{{ */
816827
} else {
817828
/* Frameless calls usually use the return value, so always emit a free. This should be
818829
* faster than checking RETURN_VALUE_USED inside the handler. */
819-
// FIXME: We may actually look at the function signature to determine whether a free
820-
// is necessary.
821-
zend_emit_op(NULL, ZEND_FREE, op1, NULL);
830+
const zend_type return_type = ZEND_FLF_FUNC(opline)->common.arg_info[-1].type;
831+
if (ZEND_TYPE_IS_COMPLEX(return_type)
832+
|| (ZEND_TYPE_PURE_MASK(return_type) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
833+
zend_emit_op(NULL, ZEND_FREE, op1, NULL);
834+
}
822835
}
823836
} else {
824837
while (opline >= CG(active_op_array)->opcodes) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
Frameless returning non-RC types can omit free at compile-time
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.opt_debug_level=0x10000
9+
--FILE--
10+
<?php
11+
12+
function test(array $array) {
13+
class_exists('Foo');
14+
preg_match('(foo)', 'foo');
15+
implode(', ', $array);
16+
}
17+
18+
?>
19+
--EXPECTF--
20+
$_main:
21+
; (lines=%d, args=0, vars=0, tmps=%d)
22+
; (before optimizer)
23+
; %s
24+
; return [] RANGE[0..0]
25+
0000 RETURN int(1)
26+
27+
test:
28+
; (lines=%d, args=1, vars=1, tmps=%d)
29+
; (before optimizer)
30+
; %s
31+
; return [] RANGE[0..0]
32+
0000 CV0($array) = RECV 1
33+
0001 T1 = FRAMELESS_ICALL_1(class_exists) string("Foo")
34+
0002 T2 = FRAMELESS_ICALL_2(preg_match) string("(foo)") string("foo")
35+
0003 T3 = FRAMELESS_ICALL_2(implode) string(", ") CV0($array)
36+
0004 FREE T3
37+
0005 RETURN null

0 commit comments

Comments
 (0)