|
38 | 38 | typedef struct _optimizer_call_info {
|
39 | 39 | zend_function *func;
|
40 | 40 | zend_op *opline;
|
| 41 | + zend_op *last_check_func_arg_opline; |
41 | 42 | bool is_prototype;
|
42 | 43 | bool try_inline;
|
43 | 44 | uint32_t func_arg_num;
|
@@ -252,6 +253,14 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
252 | 253 | if (call_stack[call - 1].func_arg_num != (uint32_t)-1
|
253 | 254 | && has_known_send_mode(&call_stack[call - 1], call_stack[call - 1].func_arg_num)) {
|
254 | 255 | if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, call_stack[call - 1].func_arg_num)) {
|
| 256 | + /* There's no TMP specialization for FETCH_OBJ_W/FETCH_DIM_W. Avoid |
| 257 | + * converting it and error at runtime in the FUNC_ARG variant. */ |
| 258 | + if ((opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) |
| 259 | + && (opline->op1_type == IS_TMP_VAR || call_stack[call - 1].last_check_func_arg_opline == NULL)) { |
| 260 | + /* Don't remove the associated CHECK_FUNC_ARG opcode. */ |
| 261 | + call_stack[call - 1].last_check_func_arg_opline = NULL; |
| 262 | + break; |
| 263 | + } |
255 | 264 | if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) {
|
256 | 265 | opline->opcode -= 9;
|
257 | 266 | } else {
|
@@ -298,11 +307,21 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
298 | 307 |
|
299 | 308 | if (has_known_send_mode(&call_stack[call - 1], opline->op2.num)) {
|
300 | 309 | call_stack[call - 1].func_arg_num = opline->op2.num;
|
301 |
| - MAKE_NOP(opline); |
| 310 | + call_stack[call - 1].last_check_func_arg_opline = opline; |
302 | 311 | }
|
303 | 312 | break;
|
304 |
| - case ZEND_SEND_VAR_EX: |
305 | 313 | case ZEND_SEND_FUNC_ARG:
|
| 314 | + /* Don't transform SEND_FUNC_ARG if any FETCH opcodes weren't transformed. */ |
| 315 | + if (call_stack[call - 1].last_check_func_arg_opline == NULL) { |
| 316 | + if (opline->op2_type == IS_CONST) { |
| 317 | + call_stack[call - 1].try_inline = 0; |
| 318 | + } |
| 319 | + break; |
| 320 | + } |
| 321 | + MAKE_NOP(call_stack[call - 1].last_check_func_arg_opline); |
| 322 | + call_stack[call - 1].last_check_func_arg_opline = NULL; |
| 323 | + ZEND_FALLTHROUGH; |
| 324 | + case ZEND_SEND_VAR_EX: |
306 | 325 | if (opline->op2_type == IS_CONST) {
|
307 | 326 | call_stack[call - 1].try_inline = 0;
|
308 | 327 | break;
|
|
0 commit comments