@@ -41,6 +41,91 @@ typedef struct _optimizer_call_info {
41
41
zend_op * opline ;
42
42
} optimizer_call_info ;
43
43
44
+ static void zend_delete_call_instructions (zend_op * opline )
45
+ {
46
+ int call = 0 ;
47
+
48
+ while (1 ) {
49
+ switch (opline -> opcode ) {
50
+ case ZEND_INIT_FCALL_BY_NAME :
51
+ case ZEND_INIT_NS_FCALL_BY_NAME :
52
+ case ZEND_INIT_STATIC_METHOD_CALL :
53
+ case ZEND_INIT_METHOD_CALL :
54
+ case ZEND_INIT_FCALL :
55
+ if (call == 0 ) {
56
+ MAKE_NOP (opline );
57
+ return ;
58
+ }
59
+ /* break missing intentionally */
60
+ case ZEND_NEW :
61
+ case ZEND_INIT_DYNAMIC_CALL :
62
+ case ZEND_INIT_USER_CALL :
63
+ call -- ;
64
+ break ;
65
+ case ZEND_DO_FCALL :
66
+ case ZEND_DO_ICALL :
67
+ case ZEND_DO_UCALL :
68
+ case ZEND_DO_FCALL_BY_NAME :
69
+ call ++ ;
70
+ break ;
71
+ case ZEND_SEND_VAL :
72
+ case ZEND_SEND_VAR :
73
+ case ZEND_SEND_VAR_NO_REF :
74
+ case ZEND_SEND_REF :
75
+ if (call == 0 ) {
76
+ if (opline -> op1_type & (IS_CONST |IS_CV )) {
77
+ MAKE_NOP (opline );
78
+ } else {
79
+ opline -> opcode = ZEND_FREE ;
80
+ opline -> extended_value = 0 ;
81
+ opline -> result .var = 0 ;
82
+ }
83
+ }
84
+ break ;
85
+ }
86
+ opline -- ;
87
+ }
88
+ }
89
+
90
+ static void zend_try_inline_call (zend_op_array * op_array , zend_op * fcall , zend_op * opline , zend_function * func )
91
+ {
92
+ if (func -> type == ZEND_USER_FUNCTION
93
+ && !(func -> op_array .fn_flags & (ZEND_ACC_ABSTRACT |ZEND_ACC_HAS_TYPE_HINTS ))
94
+ && fcall -> extended_value >= func -> op_array .required_num_args
95
+ && func -> op_array .opcodes [func -> op_array .num_args ].opcode == ZEND_RETURN ) {
96
+
97
+ zend_op * ret_opline = func -> op_array .opcodes + func -> op_array .num_args ;
98
+
99
+ if (ret_opline -> op1_type == IS_CONST ) {
100
+
101
+ if (fcall -> extended_value < func -> op_array .num_args ) {
102
+ /* don't inline funcions with named constants in default arguments */
103
+ uint32_t n = fcall -> extended_value ;
104
+
105
+ do {
106
+ if (Z_CONSTANT_P (RT_CONSTANT_EX (& func -> op_array , func -> op_array .opcodes [n ].op2 ))) {
107
+ return ;
108
+ }
109
+ n ++ ;
110
+ } while (n < func -> op_array .num_args );
111
+ }
112
+ if (RETURN_VALUE_USED (opline )) {
113
+ zval zv ;
114
+
115
+ ZVAL_DUP (& zv , RT_CONSTANT_EX (& func -> op_array , ret_opline -> op1 ));
116
+ opline -> opcode = ZEND_QM_ASSIGN ;
117
+ opline -> op1_type = IS_CONST ;
118
+ opline -> op1 .constant = zend_optimizer_add_literal (op_array , & zv );
119
+ SET_UNUSED (opline -> op2 );
120
+ } else {
121
+ MAKE_NOP (opline );
122
+ }
123
+
124
+ zend_delete_call_instructions (opline - 1 );
125
+ }
126
+ }
127
+ }
128
+
44
129
void zend_optimize_func_calls (zend_op_array * op_array , zend_optimizer_ctx * ctx )
45
130
{
46
131
zend_op * opline = op_array -> opcodes ;
@@ -61,12 +146,12 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
61
146
case ZEND_INIT_NS_FCALL_BY_NAME :
62
147
case ZEND_INIT_STATIC_METHOD_CALL :
63
148
case ZEND_INIT_METHOD_CALL :
149
+ case ZEND_INIT_FCALL :
64
150
call_stack [call ].func = zend_optimizer_get_called_func (
65
151
ctx -> script , op_array , opline , 0 );
66
152
/* break missing intentionally */
67
153
case ZEND_NEW :
68
154
case ZEND_INIT_DYNAMIC_CALL :
69
- case ZEND_INIT_FCALL :
70
155
case ZEND_INIT_USER_CALL :
71
156
call_stack [call ].opline = opline ;
72
157
call ++ ;
@@ -79,7 +164,9 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
79
164
if (call_stack [call ].func && call_stack [call ].opline ) {
80
165
zend_op * fcall = call_stack [call ].opline ;
81
166
82
- if (fcall -> opcode == ZEND_INIT_FCALL_BY_NAME ) {
167
+ if (fcall -> opcode == ZEND_INIT_FCALL ) {
168
+ /* nothing to do */
169
+ } else if (fcall -> opcode == ZEND_INIT_FCALL_BY_NAME ) {
83
170
fcall -> opcode = ZEND_INIT_FCALL ;
84
171
fcall -> op1 .num = zend_vm_calc_used_stack (fcall -> extended_value , call_stack [call ].func );
85
172
Z_CACHE_SLOT (op_array -> literals [fcall -> op2 .constant + 1 ]) = Z_CACHE_SLOT (op_array -> literals [fcall -> op2 .constant ]);
@@ -100,6 +187,10 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
100
187
} else {
101
188
ZEND_ASSERT (0 );
102
189
}
190
+
191
+ if (ZEND_OPTIMIZER_PASS_16 & ctx -> optimization_level ) {
192
+ zend_try_inline_call (op_array , fcall , opline , call_stack [call ].func );
193
+ }
103
194
}
104
195
call_stack [call ].func = NULL ;
105
196
call_stack [call ].opline = NULL ;
0 commit comments