]> granicus.if.org Git - php/commitdiff
Tracing JIT support for PHP references in array related instructions
authorDmitry Stogov <dmitry@zend.com>
Tue, 16 Jun 2020 14:59:04 +0000 (17:59 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 16 Jun 2020 14:59:04 +0000 (17:59 +0300)
ext/opcache/jit/zend_jit.c
ext/opcache/jit/zend_jit_trace.c
ext/opcache/jit/zend_jit_x86.dasc

index 286ad6644c57a3506202d788d4ba0e9dff6911c2..31e421424a01e5adc1f2800d9f11a68e1f0f64c1 100644 (file)
@@ -2393,7 +2393,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
                                                        break;
                                                }
                                                if (!zend_jit_assign_dim_op(&dasm_state, opline, op_array,
-                                                               OP1_INFO(), OP1_DEF_INFO(), OP2_INFO(),
+                                                               OP1_INFO(), OP1_DEF_INFO(), OP1_REG_ADDR(), OP2_INFO(),
                                                                OP1_DATA_INFO(), OP1_DATA_RANGE(),
                                                                zend_may_throw(opline, ssa_op, op_array, ssa))) {
                                                        goto jit_failure;
@@ -2407,7 +2407,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
                                                        break;
                                                }
                                                if (!zend_jit_assign_dim(&dasm_state, opline, op_array,
-                                                               OP1_INFO(), OP2_INFO(), OP1_DATA_INFO(),
+                                                               OP1_INFO(), OP1_REG_ADDR(), OP2_INFO(), OP1_DATA_INFO(),
                                                                zend_may_throw(opline, ssa_op, op_array, ssa))) {
                                                        goto jit_failure;
                                                }
@@ -2721,7 +2721,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
                                                        break;
                                                }
                                                if (!zend_jit_fetch_dim_read(&dasm_state, opline, op_array,
-                                                               OP1_INFO(), OP2_INFO(), RES_INFO(),
+                                                               OP1_INFO(), OP1_REG_ADDR(), OP2_INFO(), RES_INFO(),
                                                                zend_may_throw(opline, ssa_op, op_array, ssa))) {
                                                        goto jit_failure;
                                                }
@@ -2750,7 +2750,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
                                                        target_label = target_label2 = (uint32_t)-1;
                                                }
                                                if (!zend_jit_isset_isempty_dim(&dasm_state, opline, op_array,
-                                                               OP1_INFO(), OP2_INFO(),
+                                                               OP1_INFO(), OP1_REG_ADDR(), OP2_INFO(),
                                                                zend_may_throw(opline, ssa_op, op_array, ssa),
                                                                smart_branch_opcode, target_label, target_label2,
                                                                NULL)) {
index 7f32a02c4ac81a688b976039e4b6554b58b7ab3c..a8d42cddfec6d4ed1baf6bf9955bc3fceea215bc 100644 (file)
@@ -2847,6 +2847,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                        uint8_t op1_type = p->op1_type;
                        uint8_t op2_type = p->op2_type;
                        uint8_t op3_type = p->op3_type;
+                       uint8_t orig_op1_type = op1_type;
 
                        opline = p->opline;
                        if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
@@ -3152,14 +3153,22 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                        break;
                                                }
                                                op1_info = OP1_INFO();
-                                               CHECK_OP1_TRACE_TYPE();
+                                               op1_addr = OP1_REG_ADDR();
+                                               if (orig_op1_type != IS_UNKNOWN
+                                                && (orig_op1_type & IS_TRACE_REFERENCE)) {
+                                                       if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr)) {
+                                                               goto jit_failure;
+                                                       }
+                                               } else {
+                                                       CHECK_OP1_TRACE_TYPE();
+                                               }
                                                op2_info = OP2_INFO();
                                                CHECK_OP2_TRACE_TYPE();
                                                op1_data_info = OP1_DATA_INFO();
                                                CHECK_OP1_DATA_TRACE_TYPE();
                                                op1_def_info = OP1_DEF_INFO();
                                                if (!zend_jit_assign_dim_op(&dasm_state, opline, op_array,
-                                                               op1_info, op1_def_info, op2_info,
+                                                               op1_info, op1_def_info, op1_addr, op2_info,
                                                                op1_data_info, OP1_DATA_RANGE(),
                                                                zend_may_throw(opline, ssa_op, op_array, ssa))) {
                                                        goto jit_failure;
@@ -3170,13 +3179,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                        break;
                                                }
                                                op1_info = OP1_INFO();
-                                               CHECK_OP1_TRACE_TYPE();
+                                               op1_addr = OP1_REG_ADDR();
+                                               if (orig_op1_type != IS_UNKNOWN
+                                                && (orig_op1_type & IS_TRACE_REFERENCE)) {
+                                                       if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr)) {
+                                                               goto jit_failure;
+                                                       }
+                                               } else {
+                                                       CHECK_OP1_TRACE_TYPE();
+                                               }
                                                op2_info = OP2_INFO();
                                                CHECK_OP2_TRACE_TYPE();
                                                op1_data_info = OP1_DATA_INFO();
                                                CHECK_OP1_DATA_TRACE_TYPE();
                                                if (!zend_jit_assign_dim(&dasm_state, opline, op_array,
-                                                               op1_info, op2_info, op1_data_info,
+                                                               op1_info, op1_addr, op2_info, op1_data_info,
                                                                zend_may_throw(opline, ssa_op, op_array, ssa))) {
                                                        goto jit_failure;
                                                }
@@ -3596,12 +3613,20 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                        case ZEND_FETCH_DIM_R:
                                        case ZEND_FETCH_DIM_IS:
                                                op1_info = OP1_INFO();
-                                               CHECK_OP1_TRACE_TYPE();
+                                               op1_addr = OP1_REG_ADDR();
+                                               if (orig_op1_type != IS_UNKNOWN
+                                                && (orig_op1_type & IS_TRACE_REFERENCE)) {
+                                                       if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr)) {
+                                                               goto jit_failure;
+                                                       }
+                                               } else {
+                                                       CHECK_OP1_TRACE_TYPE();
+                                               }
                                                op2_info = OP2_INFO();
                                                CHECK_OP2_TRACE_TYPE();
                                                res_info = RES_INFO();
                                                if (!zend_jit_fetch_dim_read(&dasm_state, opline, op_array,
-                                                               op1_info, op2_info, res_info,
+                                                               op1_info, op1_addr, op2_info, res_info,
                                                                (
                                                                        (op1_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
                                                                        (op2_info & (MAY_BE_ANY - (MAY_BE_LONG|MAY_BE_STRING))) != 0 ||
@@ -3615,14 +3640,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                        goto jit_failure;
                                                }
                                                goto done;
-                                               goto done;
                                        case ZEND_ISSET_ISEMPTY_DIM_OBJ:
                                                if ((opline->extended_value & ZEND_ISEMPTY)) {
                                                        // TODO: support for empty() ???
                                                        break;
                                                }
                                                op1_info = OP1_INFO();
-                                               CHECK_OP1_TRACE_TYPE();
+                                               op1_addr = OP1_REG_ADDR();
+                                               if (orig_op1_type != IS_UNKNOWN
+                                                && (orig_op1_type & IS_TRACE_REFERENCE)) {
+                                                       if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr)) {
+                                                               goto jit_failure;
+                                                       }
+                                               } else {
+                                                       CHECK_OP1_TRACE_TYPE();
+                                               }
                                                op2_info = OP2_INFO();
                                                CHECK_OP2_TRACE_TYPE();
                                                if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
@@ -3644,7 +3676,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                        exit_addr = NULL;
                                                }
                                                if (!zend_jit_isset_isempty_dim(&dasm_state, opline, op_array,
-                                                               op1_info, op2_info,
+                                                               op1_info, op1_addr, op2_info,
                                                                zend_may_throw(opline, ssa_op, op_array, ssa),
                                                                smart_branch_opcode, -1, -1,
                                                                exit_addr)) {
index fb634378f2c549ecc870648149dc85d263ff5fd7..115f932909e20acdc1a2118bf77e019e576dce6a 100644 (file)
@@ -5378,13 +5378,12 @@ static int zend_jit_assign_to_variable(dasm_State    **Dst,
        return 1;
 }
 
-static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op2_info, uint32_t val_info, int may_throw)
+static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t val_info, int may_throw)
 {
-       zend_jit_addr op1_addr, op2_addr, op3_addr, res_addr;
+       zend_jit_addr op2_addr, op3_addr, res_addr;
 
        ZEND_ASSERT(opline->op1_type == IS_CV);
 
-       op1_addr = OP1_ADDR();
        op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
        op3_addr = OP1_DATA_ADDR();
        if (opline->result_type == IS_UNUSED) {
@@ -5586,13 +5585,12 @@ static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const ze
        return 1;
 }
 
-static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op1_def_info, uint32_t op2_info, uint32_t op1_data_info, zend_ssa_range *op1_data_range, int may_throw)
+static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op1_def_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t op1_data_info, zend_ssa_range *op1_data_range, int may_throw)
 {
-       zend_jit_addr op1_addr, op2_addr, op3_addr, var_addr;
+       zend_jit_addr op2_addr, op3_addr, var_addr;
 
        ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
 
-       op1_addr = OP1_ADDR();
        op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
        op3_addr = OP1_DATA_ADDR();
 
@@ -10064,12 +10062,12 @@ static int zend_jit_zval_copy_deref(dasm_State **Dst, zend_jit_addr res_addr, ze
        return 1;
 }
 
-static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op2_info, uint32_t res_info, int may_throw)
+static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t res_info, int may_throw)
 {
-       zend_jit_addr op1_addr, orig_op1_addr, op2_addr, res_addr;
+       zend_jit_addr orig_op1_addr, op2_addr, res_addr;
        const void *exit_addr = NULL;
 
-       op1_addr = orig_op1_addr = OP1_ADDR();
+       orig_op1_addr = OP1_ADDR();
        op2_addr = OP2_ADDR();
        res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
 
@@ -10263,14 +10261,13 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons
        return 1;
 }
 
-static int zend_jit_isset_isempty_dim(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op2_info, int may_throw, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
+static int zend_jit_isset_isempty_dim(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, int may_throw, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
 {
-       zend_jit_addr op1_addr, op2_addr, res_addr;
+       zend_jit_addr op2_addr, res_addr;
 
        // TODO: support for empty() ???
        ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
 
-       op1_addr = OP1_ADDR();
        op2_addr = OP2_ADDR();
        res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
 
@@ -11349,6 +11346,52 @@ static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *op
        return 1;
 }
 
+static zend_bool zend_jit_fetch_reference(dasm_State **Dst, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr)
+{
+       zend_jit_addr var_addr = *var_addr_ptr;
+       uint32_t var_info = *var_info_ptr;
+       int32_t exit_point = zend_jit_trace_get_exit_point(opline, opline, NULL, ZEND_JIT_EXIT_TO_VM);
+       const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
+
+       if (!exit_addr) {
+               return 0;
+       }
+
+       |       IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, &exit_addr
+       |       GET_ZVAL_PTR FCARG1a, var_addr
+       |       add FCARG1a, offsetof(zend_reference, val)
+
+       var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+       *var_addr_ptr = var_addr;
+
+       var_type &= ~IS_TRACE_REFERENCE;
+       if (var_type != IS_UNKNOWN
+        && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
+               exit_point = zend_jit_trace_get_exit_point(opline, opline, NULL, 0);
+               exit_addr = zend_jit_trace_get_exit_addr(exit_point);
+
+               if (!exit_addr) {
+                       return 0;
+               }
+
+               |       IF_NOT_Z_TYPE FCARG1a, var_type, &exit_addr
+
+               //var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
+               ZEND_ASSERT(var_info & (1 << var_type));
+               if (var_type < IS_STRING) {
+                       var_info = (1 << var_type);
+               } else if (var_type != IS_ARRAY) {
+                       var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
+               } else {
+                       var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
+               }
+
+               *var_info_ptr = var_info;
+       }
+
+       return 1;
+}
+
 static zend_bool zend_jit_may_reuse_reg(const zend_op *opline, const zend_ssa_op *ssa_op, zend_ssa *ssa, int def_var, int use_var)
 {
        if ((ssa->var_info[def_var].type & ~MAY_BE_GUARD) != (ssa->var_info[use_var].type & ~MAY_BE_GUARD)) {