Skip to content

Commit 6a17feb

Browse files
authored
zend_compile: Fix array_map() optimization (#21016)
* zend_compile: Fix handling of PFA syntax in array_map() optimization PFA is not implemented and the syntax is rejected at compile-time, thus it was assumed the assertion would be unreachable. However the check for PFA syntax happens after compiling special functions, making it reachable. Fix this by gracefully returning FAILURE which will then correctly emit the error during the compilation of the normal call. Fixes #20991. * zend_compile: Fix array_map() optimization for dynamic function names Fixes #20990. * zend_compile: Adjust array_map() optimization after review feedback
1 parent 9f774e3 commit 6a17feb

File tree

2 files changed

+95
-13
lines changed

2 files changed

+95
-13
lines changed

Zend/zend_compile.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5054,25 +5054,23 @@ static zend_result zend_compile_func_array_map(znode *result, zend_ast_list *arg
50545054
/* Bail out if the callback is assert() due to the AST stringification logic
50555055
* breaking for the generated call.
50565056
*/
5057-
if (callback->kind == ZEND_AST_CALL && zend_string_equals_literal_ci(zend_ast_get_str(callback->child[0]), "assert")) {
5057+
if (callback->kind == ZEND_AST_CALL
5058+
&& callback->child[0]->kind == ZEND_AST_ZVAL
5059+
&& Z_TYPE_P(zend_ast_get_zval(callback->child[0])) == IS_STRING
5060+
&& zend_string_equals_literal_ci(zend_ast_get_str(callback->child[0]), "assert")) {
5061+
return FAILURE;
5062+
}
5063+
5064+
zend_ast_list *callback_args = zend_ast_get_list(((zend_ast_fcc*)args_ast)->args);
5065+
if (callback_args->children != 1 || callback_args->child[0]->attr != ZEND_PLACEHOLDER_VARIADIC) {
5066+
/* Full PFA is not yet implemented, will fail in zend_compile_call_common(). */
50585067
return FAILURE;
50595068
}
50605069

50615070
znode value;
50625071
value.op_type = IS_TMP_VAR;
50635072
value.u.op.var = get_temporary_variable();
5064-
5065-
zend_ast_list *callback_args = zend_ast_get_list(((zend_ast_fcc*)args_ast)->args);
5066-
zend_ast *call_args = zend_ast_create_list(0, ZEND_AST_ARG_LIST);
5067-
for (uint32_t i = 0; i < callback_args->children; i++) {
5068-
zend_ast *child = callback_args->child[i];
5069-
if (child->kind == ZEND_AST_PLACEHOLDER_ARG) {
5070-
call_args = zend_ast_list_add(call_args, zend_ast_create_znode(&value));
5071-
} else {
5072-
ZEND_ASSERT(0 && "not implemented");
5073-
call_args = zend_ast_list_add(call_args, child);
5074-
}
5075-
}
5073+
zend_ast *call_args = zend_ast_create_list(1, ZEND_AST_ARG_LIST, zend_ast_create_znode(&value));
50765074

50775075
zend_op *opline;
50785076

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
--TEST--
2+
array_map(): foreach optimization - dynamic name
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.opt_debug_level=0x20000
9+
--FILE--
10+
<?php
11+
12+
function plus1($x) {
13+
return $x + 1;
14+
}
15+
16+
$array = range(1, 10);
17+
18+
$plus1 = 'plus1';
19+
$foo = array_map($plus1(...), $array);
20+
21+
var_dump($foo);
22+
23+
?>
24+
--EXPECTF--
25+
$_main:
26+
; (lines=%d, args=0, vars=%d, tmps=%d)
27+
; (after optimizer)
28+
; %s
29+
0000 INIT_FCALL 2 %d string("range")
30+
0001 SEND_VAL int(1) 1
31+
0002 SEND_VAL int(10) 2
32+
0003 V3 = DO_ICALL
33+
0004 ASSIGN CV0($array) V3
34+
0005 ASSIGN CV1($plus1) string("plus1")
35+
0006 TYPE_ASSERT 131079 string("array_map") CV0($array)
36+
0007 T3 = INIT_ARRAY 0 (packed) NEXT
37+
0008 V4 = FE_RESET_R CV0($array) 0015
38+
0009 T6 = FE_FETCH_R V4 T5 0015
39+
0010 INIT_DYNAMIC_CALL 1 CV1($plus1)
40+
0011 SEND_VAL_EX T5 1
41+
0012 V5 = DO_FCALL
42+
0013 T3 = ADD_ARRAY_ELEMENT V5 T6
43+
0014 JMP 0009
44+
0015 FE_FREE V4
45+
0016 ASSIGN CV2($foo) T3
46+
0017 INIT_FCALL 1 %d string("var_dump")
47+
0018 SEND_VAR CV2($foo) 1
48+
0019 DO_ICALL
49+
0020 RETURN int(1)
50+
LIVE RANGES:
51+
3: 0008 - 0016 (tmp/var)
52+
4: 0009 - 0015 (loop)
53+
5: 0010 - 0011 (tmp/var)
54+
6: 0010 - 0013 (tmp/var)
55+
56+
plus1:
57+
; (lines=3, args=1, vars=1, tmps=%d)
58+
; (after optimizer)
59+
; %s
60+
0000 CV0($x) = RECV 1
61+
0001 T1 = ADD CV0($x) int(1)
62+
0002 RETURN T1
63+
array(10) {
64+
[0]=>
65+
int(2)
66+
[1]=>
67+
int(3)
68+
[2]=>
69+
int(4)
70+
[3]=>
71+
int(5)
72+
[4]=>
73+
int(6)
74+
[5]=>
75+
int(7)
76+
[6]=>
77+
int(8)
78+
[7]=>
79+
int(9)
80+
[8]=>
81+
int(10)
82+
[9]=>
83+
int(11)
84+
}

0 commit comments

Comments
 (0)