]> granicus.if.org Git - php/commitdiff
JIT for ZEND_CHECK_FUNC_ARG
authorDmitry Stogov <dmitry@zend.com>
Wed, 18 Mar 2020 20:56:03 +0000 (23:56 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 18 Mar 2020 20:56:03 +0000 (23:56 +0300)
ext/opcache/Optimizer/zend_inference.c
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 b6bf6eb4742cea76a98650533df6a327da0f581d..34d62867690c6cd53b0e75b2c5e09d09e4d4955d 100644 (file)
@@ -4327,6 +4327,7 @@ int zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_
                case ZEND_FUNC_NUM_ARGS:
                case ZEND_FUNC_GET_ARGS:
                case ZEND_COPY_TMP:
+               case ZEND_CHECK_FUNC_ARG:
                        return 0;
                case ZEND_INIT_FCALL:
                        /* can't throw, because call is resolved at compile time */
index ccff9e097dd5c38c23c520a5090165fa857d5900..012b42b48c94280ce9f83755524e2b69e2de82ac 100644 (file)
@@ -2480,6 +2480,14 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
                                                        goto jit_failure;
                                                }
                                                goto done;
+                                       case ZEND_CHECK_FUNC_ARG:
+                                               if (opline->op2.num > MAX_ARG_FLAG_NUM) {
+                                                       break;
+                                               }
+                                               if (!zend_jit_check_func_arg(&dasm_state, opline, op_array)) {
+                                                       goto jit_failure;
+                                               }
+                                               goto done;
                                        case ZEND_DO_UCALL:
                                                is_terminated = 1;
                                                /* break missing intentionally */
index 504cb67065f7278f9b2d923c5385f6b31dae49a4..922f4b25ac19f472077a0b3668e580f7c50b3f5a 100644 (file)
@@ -336,6 +336,7 @@ struct _zend_jit_trace_stack_frame {
                        int8_t              return_value_used;
                        int8_t              nested;
                        int8_t              num_args;
+                       int8_t                          last_send_by_ref;
                };
                int                     return_ssa_var;
        };
index 242ab347dadbaa2859e2e6fdf8f2ccaa344e9390..ed4672d3fcd348c9faddabc236c44f0a2ced4a24 100644 (file)
@@ -1664,6 +1664,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
        frame->return_value_used = -1;
        frame->nested = 0;
        frame->num_args = -1;
+       frame->last_send_by_ref = -1;
        stack = frame->stack;
 
        if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
@@ -2232,6 +2233,17 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                        }
                                                }
                                                goto done;
+                                       case ZEND_CHECK_FUNC_ARG:
+                                               if (opline->op2.num > MAX_ARG_FLAG_NUM
+                                                && (!JIT_G(current_frame)
+                                                 || !JIT_G(current_frame)->call
+                                                 || !JIT_G(current_frame)->call->func)) {
+                                                       break;
+                                               }
+                                               if (!zend_jit_check_func_arg(&dasm_state, opline, op_array)) {
+                                                       goto jit_failure;
+                                               }
+                                               goto done;
                                        case ZEND_DO_UCALL:
                                        case ZEND_DO_ICALL:
                                        case ZEND_DO_FCALL_BY_NAME:
@@ -2861,6 +2873,7 @@ done:
                                call->func = (const zend_function*)op_array;
                                call->nested = 0;
                                call->num_args = -1; // TODO: should be possible to get the real number ???
+                               call->last_send_by_ref = -1;
                                top = zend_jit_trace_call_frame(top, op_array);
                                i = 0;
                                while (i < p->op_array->num_args) {
@@ -2908,6 +2921,7 @@ done:
                                frame->return_value_used = -1;
                                frame->nested = 0;
                                frame->num_args = -1;
+                               frame->last_send_by_ref = -1;
                                stack = frame->stack;
                                for (i = 0; i < op_array->last_var + op_array->T; i++) {
                                        /* Initialize abstract stack using SSA */
@@ -2937,6 +2951,7 @@ done:
                        call->func = p->func;
                        call->nested = 1;
                        call->num_args = find_call_num_args(p-1);
+                       call->last_send_by_ref = p->fake ? -1 : 0;
                        frame->call = call;
                        top = zend_jit_trace_call_frame(top, p->op_array);
                        if (p->func->type == ZEND_USER_FUNCTION) {
index 2cb8955ff22bac6ac5358df68551b3405911f5be..a9b0888ab1b00a1ce8ea299daf49654dd470e009 100644 (file)
@@ -8728,6 +8728,63 @@ static int zend_jit_send_var(dasm_State **Dst, const zend_op *opline, const zend
        return 1;
 }
 
+static int zend_jit_check_func_arg(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array)
+{
+       uint32_t arg_num = opline->op2.num;
+
+       if (zend_jit_trigger == ZEND_JIT_ON_HOT_TRACE
+        && JIT_G(current_frame)
+        && JIT_G(current_frame)->call
+        && JIT_G(current_frame)->call->func) {
+               if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
+                       if (JIT_G(current_frame)->call->last_send_by_ref != 1) {
+                               JIT_G(current_frame)->call->last_send_by_ref = 1;
+                               |       // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
+                               ||      if (reuse_ip) {
+                               |               or dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF
+                               ||      } else {
+                               |               mov r0, EX->call
+                               |               or dword [r0 + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF
+                               ||      }
+                       }
+               } else {
+                       if (JIT_G(current_frame)->call->last_send_by_ref != 0) {
+                               JIT_G(current_frame)->call->last_send_by_ref = 0;
+                               |       // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
+                               ||      if (reuse_ip) {
+                               |               and dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF
+                               ||      } else {
+                               |               mov r0, EX->call
+                               |               and dword [r0 + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF
+                               ||      }
+                       }
+               }
+       } else {
+               // if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+               uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
+
+               if (!reuse_ip) {
+                       zend_jit_start_reuse_ip();
+                       |       // call = EX(call);
+                       |       mov RX, EX->call
+               }
+               |       mov r0, EX:RX->func
+               |       test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
+               |       jnz     >1
+               |.cold_code
+               |1:
+               |       // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
+               |       or dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF
+               |       jmp >1
+               |.code
+               |       // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
+               |       and dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF
+               |1:
+       }
+
+       return 1;
+}
+
 static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
 {
        if (smart_branch_opcode) {