]> granicus.if.org Git - php/commitdiff
Improved JIT for VERIFY_RETURN_TYPE
authorDmitry Stogov <dmitry@zend.com>
Wed, 2 Sep 2020 09:55:16 +0000 (12:55 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 2 Sep 2020 09:55:16 +0000 (12:55 +0300)
ext/opcache/jit/zend_jit_trace.c
ext/opcache/jit/zend_jit_x86.dasc

index 3203339d028fac8dfe1f0003aa918ad616906a6c..c3c7dbab225f8104b5b284b6e49d3e0d1b4d25f3 100644 (file)
@@ -1447,6 +1447,21 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
                                case ZEND_QM_ASSIGN:
                                        ADD_OP1_TRACE_GUARD();
                                        break;
+                               case ZEND_VERIFY_RETURN_TYPE:
+                                       if (opline->op1_type == IS_UNUSED) {
+                                               /* Always throws */
+                                               break;
+                                       }
+                                       if (opline->op1_type == IS_CONST) {
+                                               /* TODO Different instruction format, has return value */
+                                               break;
+                                       }
+                                       if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+                                               /* Not worth bothering with */
+                                               break;
+                                       }
+                                       ADD_OP1_TRACE_GUARD();
+                                       break;
                                case ZEND_FETCH_DIM_FUNC_ARG:
                                        if (!frame
                                         || !frame->call
@@ -4502,6 +4517,29 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                        goto jit_failure;
                                                }
                                                goto done;
+                                       case ZEND_VERIFY_RETURN_TYPE:
+                                               if (opline->op1_type == IS_UNUSED) {
+                                                       /* Always throws */
+                                                       break;
+                                               }
+                                               if (opline->op1_type == IS_CONST) {
+                                                       /* TODO Different instruction format, has return value */
+                                                       break;
+                                               }
+                                               if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+                                                       /* Not worth bothering with */
+                                                       break;
+                                               }
+                                               op1_info = OP1_INFO();
+                                               CHECK_OP1_TRACE_TYPE();
+                                               if (op1_info & MAY_BE_REF) {
+                                                       /* TODO May need reference unwrapping. */
+                                                       break;
+                                               }
+                                               if (!zend_jit_verify_return_type(&dasm_state, opline, op_array, op1_info)) {
+                                                       goto jit_failure;
+                                               }
+                                               goto done;
                                        case ZEND_INIT_METHOD_CALL:
                                        case ZEND_INIT_DYNAMIC_CALL:
                                                if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
index 39fd42e263f6cee5c46a56b77dccafdacdea8ba6..09cea053544ff8689afdd03b36ac6006e8ad6f99 100644 (file)
@@ -483,6 +483,11 @@ static void* dasm_labels[zend_lb_MAX];
 |      mov dword [zv+offsetof(zval,u1.type_info)], type
 |.endmacro
 
+|.macro GET_ZVAL_TYPE, reg, addr
+||     ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+|      mov reg, byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.v.type)]
+|.endmacro
+
 |.macro GET_ZVAL_TYPE_INFO, reg, addr
 ||     ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
 |      mov reg, dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.type_info)]
@@ -12393,53 +12398,65 @@ static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *op
        zend_arg_info *arg_info = &op_array->arg_info[-1];
        ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
        zend_jit_addr op1_addr = OP1_ADDR();
-
-       |       LOAD_ZVAL_ADDR r0, op1_addr
-
+       zend_bool needs_slow_check = 1;
+       zend_bool slow_check_in_cold = 1;
        uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
+
        if (type_mask == 0) {
-               |       jmp >7
-       } else if (is_power_of_two(type_mask)) {
-               uint32_t type_code = concrete_type(type_mask);
-               |       cmp byte [r0 + 8], type_code
-               |       jne >7
+               slow_check_in_cold = 0;
        } else {
-               |       mov edx, 1
-               |       mov cl, byte [r0 + 8]
-               |       shl edx, cl
-               |       test edx, type_mask
-               |       je >7
-       }
-       |.cold_code
-       |7:
-       |       SAVE_VALID_OPLINE opline, r1
-       if (op1_info & MAY_BE_UNDEF) {
-               |       IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >8
-               |       mov FCARG1a, opline->op1.var
-               |       EXT_CALL zend_jit_undefined_op_helper, FCARG2a
-               |       LOAD_ADDR_ZTS r0, executor_globals, uninitialized_zval
+               if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
+                       slow_check_in_cold = 0;
+               } else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
+                       needs_slow_check = 0;
+               } else if (is_power_of_two(type_mask)) {
+                       uint32_t type_code = concrete_type(type_mask);
+                       |       IF_NOT_ZVAL_TYPE op1_addr, type_code, >7
+               } else {
+                       |       mov edx, 1
+                       |       GET_ZVAL_TYPE cl, op1_addr
+                       |       shl edx, cl
+                       |       test edx, type_mask
+                       |       je >7
+               }
        }
-       |8:
-       |       mov FCARG1a, r0
-       |       mov r0, EX->run_time_cache
-       |       add r0, opline->op2.num
-       |       mov FCARG2a, EX->func
-       |.if X64
-               |       LOAD_ADDR CARG3, (ptrdiff_t)arg_info
-               |       mov CARG4, r0
-               |       EXT_CALL zend_jit_verify_return_slow, r0
-       |.else
-               |       sub r4, 8
-               |       push r0
-               |       push (ptrdiff_t)arg_info
-               |       EXT_CALL zend_jit_verify_return_slow, r0
-               |       add r4, 8
-       |.endif
-       if (!zend_jit_check_exception(Dst)) {
-               return 0;
+       if (needs_slow_check) {
+               if (slow_check_in_cold) {
+                       |.cold_code
+                       |7:
+               }
+               |       SAVE_VALID_OPLINE opline, r1
+               if (op1_info & MAY_BE_UNDEF) {
+                       |       IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >8
+                       |       mov FCARG1a, opline->op1.var
+                       |       EXT_CALL zend_jit_undefined_op_helper, FCARG2a
+                       |       LOAD_ADDR_ZTS r0, executor_globals, uninitialized_zval
+               }
+               |8:
+               |       LOAD_ZVAL_ADDR FCARG1a, op1_addr
+               |       mov FCARG2a, EX->func
+               |.if X64
+                       |       LOAD_ADDR CARG3, (ptrdiff_t)arg_info
+                       |       mov r0, EX->run_time_cache
+                       |       lea CARG4, aword [r0+opline->op2.num]
+                       |       EXT_CALL zend_jit_verify_return_slow, r0
+               |.else
+                       |       sub r4, 8
+                       |       mov r0, EX->run_time_cache
+                       |       add r0, opline->op2.num
+                       |       push r0
+                       |       push (ptrdiff_t)arg_info
+                       |       EXT_CALL zend_jit_verify_return_slow, r0
+                       |       add r4, 8
+               |.endif
+               if (!zend_jit_check_exception(Dst)) {
+                       return 0;
+               }
+               if (slow_check_in_cold) {
+                       |       jmp >9
+                       |.code
+               }
        }
-       |       jmp >9
-       |.code
        |9:
        return 1;
 }