|
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