/* the same as above, but "src" may overlap with "tmp_reg1" */
|.macro ZVAL_COPY_VALUE, dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2
+| ZVAL_COPY_VALUE_V dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2
+|| if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) &&
+|| !(src_info & MAY_BE_GUARD) &&
+|| has_concrete_type(src_info & MAY_BE_ANY)) {
+|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
+|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
+|| zend_uchar type = concrete_type(src_info);
+| SET_ZVAL_TYPE_INFO dst_addr, type
+|| }
+|| }
+|| } else {
+| GET_ZVAL_TYPE_INFO Rd(tmp_reg1), src_addr
+| SET_ZVAL_TYPE_INFO dst_addr, Rd(tmp_reg1)
+|| }
+|.endmacro
+
+|.macro ZVAL_COPY_VALUE_V, dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2
|| if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
|| if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
|| if (Z_MODE(src_addr) == IS_REG) {
| .endif
|| }
|| }
-|| if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) &&
-|| !(src_info & MAY_BE_GUARD) &&
-|| has_concrete_type(src_info & MAY_BE_ANY)) {
-|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
-|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
-|| zend_uchar type = concrete_type(src_info);
-| SET_ZVAL_TYPE_INFO dst_addr, type
-|| }
-|| }
-|| } else {
-| GET_ZVAL_TYPE_INFO Rd(tmp_reg1), src_addr
-| SET_ZVAL_TYPE_INFO dst_addr, Rd(tmp_reg1)
-|| }
|.endmacro
|.macro ZVAL_COPY_VALUE_2, dst_addr, dst_info, res_addr, src_addr, src_info, tmp_reg1, tmp_reg2
| SET_ZVAL_PTR res_addr, FCARG1a
| SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT
} else {
- if (!zend_jit_zval_copy_deref(Dst, res_addr, prop_addr, ZREG_R2)) {
- return 0;
+ uint32_t res_info = RES_INFO();
+
+ if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
+ uint32_t flags = 0;
+ uint32_t old_info;
+ zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
+ int32_t exit_point;
+ const void *exit_addr;
+ zend_uchar type;
+ zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
+
+ if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !use_this) {
+ flags = ZEND_JIT_EXIT_FREE_OP1;
+ }
+
+ | LOAD_ZVAL_ADDR r0, prop_addr
+
+ old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
+ SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN);
+ SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0);
+ exit_point = zend_jit_trace_get_exit_point(opline, opline+1, NULL, flags);
+ SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
+ exit_addr = zend_jit_trace_get_exit_addr(exit_point);
+ if (!exit_addr) {
+ return 0;
+ }
+
+ res_info &= ~MAY_BE_GUARD;
+ ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
+ type = concrete_type(res_info);
+
+ | // ZVAL_DEREF()
+ | IF_NOT_TYPE dl, IS_REFERENCE, >1
+ | GET_Z_PTR r0, r0
+ | add r0, offsetof(zend_reference, val)
+ if (type < IS_STRING) {
+ |1:
+ | IF_NOT_ZVAL_TYPE val_addr, type, &exit_addr
+ } else {
+ | GET_ZVAL_TYPE_INFO edx, val_addr
+ |1:
+ | IF_NOT_TYPE dl, type, &exit_addr
+ }
+ | // ZVAL_COPY
+ | ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_R2, ZREG_R1
+ if (type < IS_STRING) {
+ | SET_ZVAL_TYPE_INFO res_addr, type
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, edx
+ | TRY_ADDREF res_info, dh, r1
+ }
+ } else {
+ if (!zend_jit_zval_copy_deref(Dst, res_addr, prop_addr, ZREG_R2)) {
+ return 0;
+ }
}
}