]> granicus.if.org Git - php/commitdiff
Eliminate some EX_CALL_INFO() checks
authorDmitry Stogov <dmitry@zend.com>
Tue, 1 Sep 2020 13:26:29 +0000 (16:26 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 1 Sep 2020 13:26:29 +0000 (16:26 +0300)
ext/opcache/jit/zend_jit.c
ext/opcache/jit/zend_jit_internal.h
ext/opcache/jit/zend_jit_trace.c
ext/opcache/jit/zend_jit_x86.dasc

index 5254a395187c00e650bd6a994e75a999fe582815..a89b21f875afadf8a71e6eb8fd1d16fd92c4ac4a 100644 (file)
@@ -2740,9 +2740,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
                                                                        }
                                                                }
                                                        }
-                                                   if (!zend_jit_leave_func(&dasm_state, op_array, NULL, NULL, 1)) {
+                                                       if (!zend_jit_leave_func(&dasm_state, op_array, NULL, NULL,
+                                                                       (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, 1)) {
                                                                goto jit_failure;
-                                                   }
+                                                       }
                                                }
                                                goto done;
                                        case ZEND_BOOL:
index f471321991fbdc17c1559e7e47d6c52fd0485478..1f4b36cb62797e9ccdeedf5113ab57668268e235 100644 (file)
@@ -379,17 +379,18 @@ struct _zend_jit_trace_stack_frame {
        zend_jit_trace_stack        stack[1];
 };
 
-#define TRACE_FRAME_SHIFT_NUM_ARGS           16
-#define TRACE_FRAME_MAX_NUM_ARGS             32767
+#define TRACE_FRAME_SHIFT_NUM_ARGS            16
+#define TRACE_FRAME_MAX_NUM_ARGS              32767
 
-#define TRACE_FRAME_MASK_NUM_ARGS            0xffff0000
-#define TRACE_FRAME_MASK_NESTED              0x00000001
-#define TRACE_FRAME_MASK_LAST_SEND_BY_REF    0x00000002
-#define TRACE_FRAME_MASK_LAST_SEND_BY_VAL    0x00000004
-#define TRACE_FRAME_MASK_RETURN_VALUE_USED   0x00000008
-#define TRACE_FRAME_MASK_RETURN_VALUE_UNUSED 0x00000010
-#define TRACE_FRAME_MASK_THIS_CHECKED        0x00000020
-#define TRACE_FRAME_MASK_UNKNOWN_RETURN      0x00000040
+#define TRACE_FRAME_MASK_NUM_ARGS             0xffff0000
+#define TRACE_FRAME_MASK_NESTED               0x00000001
+#define TRACE_FRAME_MASK_LAST_SEND_BY_REF     0x00000002
+#define TRACE_FRAME_MASK_LAST_SEND_BY_VAL     0x00000004
+#define TRACE_FRAME_MASK_RETURN_VALUE_USED    0x00000008
+#define TRACE_FRAME_MASK_RETURN_VALUE_UNUSED  0x00000010
+#define TRACE_FRAME_MASK_THIS_CHECKED         0x00000020
+#define TRACE_FRAME_MASK_UNKNOWN_RETURN       0x00000040
+#define TRACE_FRAME_MASK_NO_NEED_RELEASE_THIS 0x00000080
 
 
 #define TRACE_FRAME_INIT(frame, _func, _flags, num_args) do { \
@@ -421,6 +422,8 @@ struct _zend_jit_trace_stack_frame {
        ((frame)->_info & TRACE_FRAME_MASK_THIS_CHECKED)
 #define TRACE_FRAME_IS_UNKNOWN_RETURN(frame) \
        ((frame)->_info & TRACE_FRAME_MASK_UNKNOWN_RETURN)
+#define TRACE_FRAME_NO_NEED_REKEASE_THIS(frame) \
+       ((frame)->_info & TRACE_FRAME_MASK_NO_NEED_RELEASE_THIS)
 
 #define TRACE_FRAME_SET_RETURN_SSA_VAR(frame, var) do { \
                (frame)->_info = var; \
@@ -444,6 +447,9 @@ struct _zend_jit_trace_stack_frame {
 #define TRACE_FRAME_SET_THIS_CHECKED(frame) do { \
                (frame)->_info |= TRACE_FRAME_MASK_THIS_CHECKED; \
        } while (0)
+#define TRACE_FRAME_SET_NO_NEED_RELEASE_THIS(frame) do { \
+               (frame)->_info |= TRACE_FRAME_MASK_NO_NEED_RELEASE_THIS; \
+       } while (0)
 
 ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_trace_helper(ZEND_OPCODE_HANDLER_ARGS);
 ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_ret_trace_helper(ZEND_OPCODE_HANDLER_ARGS);
index d8ee688f0f5aae70aac5bf507c8bb62127c582b5..4b88a9d03ea90f25fdff65bc7e7f8dbfd4adf61f 100644 (file)
@@ -4058,7 +4058,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                                        }
                                                                }
                                                        }
-                                                       if (!zend_jit_leave_func(&dasm_state, op_array, p + 1, &zend_jit_traces[ZEND_JIT_TRACE_NUM], may_throw)) {
+                                                       if (!zend_jit_leave_func(&dasm_state, op_array, p + 1, &zend_jit_traces[ZEND_JIT_TRACE_NUM],
+                                                                       (op_array_ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, may_throw)) {
                                                                goto jit_failure;
                                                        }
                                                }
@@ -4876,6 +4877,17 @@ done:
                        if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
                                TRACE_FRAME_SET_LAST_SEND_BY_VAL(call);
                        }
+                       if (init_opline
+                        && init_opline->opcode != ZEND_NEW
+                        && (init_opline->opcode != ZEND_INIT_METHOD_CALL
+                         || init_opline->op1_type == IS_UNDEF)
+                        && (init_opline->opcode != ZEND_INIT_USER_CALL
+                         || init_opline->op2_type == IS_CONST) /* no closure */
+                        && (init_opline->opcode != ZEND_INIT_DYNAMIC_CALL
+                         || init_opline->op2_type == IS_CONST) /* no closure */
+                       ) {
+                               TRACE_FRAME_SET_NO_NEED_RELEASE_THIS(call);
+                       }
                        frame->call = call;
                        top = zend_jit_trace_call_frame(top, p->op_array);
                        if (p->func) {
index e6a46ad09fb8c87bd927f1ac721c5dea6a69bc8a..16a5922344bc93caf4c929b03e2510bc2a1a8b26 100644 (file)
@@ -10194,66 +10194,88 @@ static int zend_jit_free_op(dasm_State **Dst, const zend_op *opline, uint32_t in
        return 1;
 }
 
-static int zend_jit_leave_func(dasm_State **Dst, const zend_op_array *op_array, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info, int may_throw)
-{
-       /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
-       |       mov FCARG1d, dword [FP + offsetof(zend_execute_data, This.u1.type_info)]
-       |       test FCARG1d, (ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_FAKE_CLOSURE)
-       if (trace && trace->op != ZEND_JIT_TRACE_END) {
-               |       jnz >1
-               |.cold_code
-               |1:
-               if (!GCC_GLOBAL_REGS) {
-                       |       mov FCARG2a, FP
-               }
-               |       EXT_CALL zend_jit_leave_func_helper, r0
+static int zend_jit_leave_func(dasm_State **Dst, const zend_op_array *op_array, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info, int indirect_var_access, int may_throw)
+{
+       zend_bool may_be_top_frame =
+               JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
+               !JIT_G(current_frame) ||
+               !TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
+       zend_bool may_need_call_helper =
+               indirect_var_access || /* may have symbol table */
+               !op_array->function_name || /* may have symbol table */
+               may_be_top_frame ||
+               (op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
+               JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
+               !JIT_G(current_frame) ||
+               TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
+               (uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
+       zend_bool may_need_release_this =
+               !(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
+               op_array->scope &&
+               !(op_array->fn_flags & ZEND_ACC_STATIC) &&
+               (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
+                !JIT_G(current_frame) ||
+                !TRACE_FRAME_NO_NEED_REKEASE_THIS(JIT_G(current_frame)));
+
+       if (may_need_call_helper || may_need_release_this) {
+               |       mov FCARG1d, dword [FP + offsetof(zend_execute_data, This.u1.type_info)]
+       }
+       if (may_need_call_helper) {
+               /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
+               |       test FCARG1d, (ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_FAKE_CLOSURE)
+               if (trace && trace->op != ZEND_JIT_TRACE_END) {
+                       |       jnz >1
+                       |.cold_code
+                       |1:
+                       if (!GCC_GLOBAL_REGS) {
+                               |       mov FCARG2a, FP
+                       }
+                       |       EXT_CALL zend_jit_leave_func_helper, r0
+
+                       if (may_be_top_frame) {
+                               // TODO: try to avoid this check ???
+                               if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+                                       |       cmp IP, zend_jit_halt_op
+                                       |       je ->trace_halt
+                               } else if (GCC_GLOBAL_REGS) {
+                                       |       test IP, IP
+                                       |       je ->trace_halt
+                               } else {
+                                       |       test eax, eax
+                                       |       jl ->trace_halt
+                               }
+                       }
 
-               if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
-                   !JIT_G(current_frame) ||
-                   !TRACE_FRAME_IS_NESTED(JIT_G(current_frame))) {
-                       // TODO: try to avoid this check ???
-                       if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
-                               |       cmp IP, zend_jit_halt_op
-                               |       je ->trace_halt
-                       } else if (GCC_GLOBAL_REGS) {
-                               |       test IP, IP
-                               |       je ->trace_halt
-                       } else {
-                               |       test eax, eax
-                               |       jl ->trace_halt
+                       if (!GCC_GLOBAL_REGS) {
+                               |       // execute_data = EG(current_execute_data)
+                               |       MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r0
                        }
+                       |       jmp >8
+                       |.code
+               } else {
+                       |       jnz ->leave_function_handler
                }
+       }
 
-               if (!GCC_GLOBAL_REGS) {
-                       |       // execute_data = EG(current_execute_data)
-                       |       MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r0
-               }
-               |       jmp >8
-               |.code
-       } else {
-               |       jnz ->leave_function_handler
-       }
-
-       if ((op_array->scope && !(op_array->fn_flags & ZEND_ACC_STATIC)) ||
-           (op_array->fn_flags & ZEND_ACC_CLOSURE)) {
-               if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
-                       |       // OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
-                       |       mov FCARG1a, EX->func
-                       |       sub FCARG1a, sizeof(zend_object)
-                       |       OBJ_RELEASE ZREG_FCARG1a, >4
-               } else if (op_array->scope && !(op_array->fn_flags & ZEND_ACC_STATIC)) {
-                       |       // if (call_info & ZEND_CALL_RELEASE_THIS)
-                       |       test FCARG1d, ZEND_CALL_RELEASE_THIS
-                       |       je >4
-                       |       // zend_object *object = Z_OBJ(execute_data->This);
-                       |       mov FCARG1a, EX->This.value.obj
-                       |       // OBJ_RELEASE(object);
-                       |       OBJ_RELEASE ZREG_FCARG1a, >4
-                       // TODO: avoid EG(excption) check for $this->foo() calls
-                       may_throw = 1;
-               }
+       if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
+               |       // OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
+               |       mov FCARG1a, EX->func
+               |       sub FCARG1a, sizeof(zend_object)
+               |       OBJ_RELEASE ZREG_FCARG1a, >4
                |4:
+       } else if (may_need_release_this) {
+               |       // if (call_info & ZEND_CALL_RELEASE_THIS)
+               |       test FCARG1d, ZEND_CALL_RELEASE_THIS
+               |       je >4
+               |       // zend_object *object = Z_OBJ(execute_data->This);
+               |       mov FCARG1a, EX->This.value.obj
+               |       // OBJ_RELEASE(object);
+               |       OBJ_RELEASE ZREG_FCARG1a, >4
+               |4:
+               // TODO: avoid EG(excption) check for $this->foo() calls
+               may_throw = 1;
        }
+
        |       // EG(vm_stack_top) = (zval*)execute_data;
        |       MEM_OP2_1_ZTS mov, aword, executor_globals, vm_stack_top, FP, r0
        |       // execute_data = EX(prev_execute_data);