|
31 | 31 | typedef struct _optimizer_call_info { |
32 | 32 | zend_function *func; |
33 | 33 | zend_op *opline; |
| 34 | + zend_op *last_check_func_arg_opline; |
34 | 35 | bool is_prototype; |
35 | 36 | bool try_inline; |
36 | 37 | uint32_t func_arg_num; |
@@ -235,6 +236,14 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) |
235 | 236 | if (call_stack[call - 1].func_arg_num != (uint32_t)-1 |
236 | 237 | && has_known_send_mode(&call_stack[call - 1], call_stack[call - 1].func_arg_num)) { |
237 | 238 | if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, call_stack[call - 1].func_arg_num)) { |
| 239 | + /* There's no TMP specialization for FETCH_OBJ_W/FETCH_DIM_W. Avoid |
| 240 | + * converting it and error at runtime in the FUNC_ARG variant. */ |
| 241 | + if ((opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) |
| 242 | + && (opline->op1_type == IS_TMP_VAR || call_stack[call - 1].last_check_func_arg_opline == NULL)) { |
| 243 | + /* Don't remove the associated CHECK_FUNC_ARG opcode. */ |
| 244 | + call_stack[call - 1].last_check_func_arg_opline = NULL; |
| 245 | + break; |
| 246 | + } |
238 | 247 | if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) { |
239 | 248 | opline->opcode -= 9; |
240 | 249 | } else { |
@@ -278,11 +287,21 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) |
278 | 287 |
|
279 | 288 | if (has_known_send_mode(&call_stack[call - 1], opline->op2.num)) { |
280 | 289 | call_stack[call - 1].func_arg_num = opline->op2.num; |
281 | | - MAKE_NOP(opline); |
| 290 | + call_stack[call - 1].last_check_func_arg_opline = opline; |
282 | 291 | } |
283 | 292 | break; |
284 | | - case ZEND_SEND_VAR_EX: |
285 | 293 | case ZEND_SEND_FUNC_ARG: |
| 294 | + /* Don't transform SEND_FUNC_ARG if any FETCH opcodes weren't transformed. */ |
| 295 | + if (call_stack[call - 1].last_check_func_arg_opline == NULL) { |
| 296 | + if (opline->op2_type == IS_CONST) { |
| 297 | + call_stack[call - 1].try_inline = 0; |
| 298 | + } |
| 299 | + break; |
| 300 | + } |
| 301 | + MAKE_NOP(call_stack[call - 1].last_check_func_arg_opline); |
| 302 | + call_stack[call - 1].last_check_func_arg_opline = NULL; |
| 303 | + ZEND_FALLTHROUGH; |
| 304 | + case ZEND_SEND_VAR_EX: |
286 | 305 | if (opline->op2_type == IS_CONST) { |
287 | 306 | call_stack[call - 1].try_inline = 0; |
288 | 307 | break; |
|
0 commit comments