]> granicus.if.org Git - php/commitdiff
JIT: Handle typed refs in assign dim
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 23 Oct 2019 08:56:50 +0000 (10:56 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 23 Oct 2019 09:25:10 +0000 (11:25 +0200)
Zend/zend_execute.c
Zend/zend_execute.h
ext/opcache/jit/zend_jit_disasm_x86.c
ext/opcache/jit/zend_jit_helpers.c
ext/opcache/jit/zend_jit_x86.dasc

index 6875ac5e8a5502457989365901ec386d6e8f4e85..8813ec3d872ed099b77c969faeaf14c7e5d0f622 100644 (file)
@@ -612,8 +612,6 @@ static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_err
                zend_get_unmangled_property_name(prop->name));
 }
 
-static zend_never_inline zend_bool zend_verify_ref_array_assignable(zend_reference *ref);
-
 /* this should modify object only if it's empty */
 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_error(zval *object, zval *property OPLINE_DC EXECUTE_DATA_DC)
 {
@@ -2531,9 +2529,8 @@ static zend_always_inline zend_bool check_type_array_assignable(zend_type type)
        return ZEND_TYPE_IS_MASK(type) && (ZEND_TYPE_MASK(type) & (MAY_BE_ITERABLE|MAY_BE_ARRAY));
 }
 
-/* Checks whether an array can be assigned to the reference. Returns conflicting property if
- * assignment is not possible, NULL otherwise. */
-static zend_never_inline zend_bool zend_verify_ref_array_assignable(zend_reference *ref) {
+/* Checks whether an array can be assigned to the reference. Throws error if not assignable. */
+ZEND_API zend_bool zend_verify_ref_array_assignable(zend_reference *ref) {
        zend_property_info *prop;
        ZEND_ASSERT(ZEND_REF_HAS_TYPE_SOURCES(ref));
        ZEND_REF_FOREACH_TYPE_SOURCES(ref, prop) {
index 2342bbaba42686f83db5a2e2690d5b98ea214c8a..8636399d3bc54577c55315693522f9643005110a 100644 (file)
@@ -64,6 +64,7 @@ ZEND_API zend_bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, z
 ZEND_API ZEND_COLD void zend_verify_arg_error(
                const zend_function *zf, const zend_arg_info *arg_info,
                int arg_num, void **cache_slot, zval *value);
+ZEND_API zend_bool zend_verify_ref_array_assignable(zend_reference *ref);
 
 #define ZEND_REF_TYPE_SOURCES(ref) \
        (ref)->sources
index 790c62af8f87cd5d28bbe34020ffaf5c8c27649d..70708729b49eda07f8074ad01ab1f9554d820bfe 100644 (file)
@@ -444,6 +444,7 @@ static int zend_jit_disasm_init(void)
        REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
        REGISTER_HELPER(zend_jit_only_vars_by_reference);
        REGISTER_HELPER(zend_jit_invalid_array_access);
+       REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
        REGISTER_HELPER(zend_runtime_jit);
        REGISTER_HELPER(zend_jit_hot_func);
 #undef  REGISTER_HELPER
index d2c848af775364f5acd9657fe62904f7032948fa..da96660a10bc3ae701f09886273f9c94010839ba 100644 (file)
@@ -1465,3 +1465,15 @@ static void ZEND_FASTCALL zend_jit_invalid_array_access(zval *container)
        const char *type = Z_ISUNDEF_P(container) ? "null" : zend_zval_type_name(container);
        zend_error(E_WARNING, "Trying to access array offset on value of type %s", type);
 }
+
+static zval * ZEND_FASTCALL zend_jit_prepare_assign_dim_ref(zval *ref) {
+       zval *val = Z_REFVAL_P(ref);
+       if (Z_TYPE_P(val) <= IS_FALSE) {
+               if (ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(ref))
+                               && !zend_verify_ref_array_assignable(Z_REF_P(ref))) {
+                       return NULL;
+               }
+               ZVAL_ARR(val, zend_new_array(8));
+       }
+       return val;
+}
index 06357b74070469557ef41240234ba1e4ec5f260a..d1eba4d47b1fd20a6b16e2e55902a3c75b813657 100644 (file)
@@ -4610,7 +4610,21 @@ static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const ze
 
        if (op1_info & MAY_BE_REF) {
                |       LOAD_ZVAL_ADDR FCARG1a, op1_addr
-               |       ZVAL_DEREF FCARG1a, op1_info
+               |       IF_NOT_Z_TYPE FCARG1a, IS_REFERENCE, >1
+               |       GET_Z_PTR FCARG2a, FCARG1a
+               |       IF_NOT_TYPE byte [FCARG2a + offsetof(zend_reference, val) + offsetof(zval, u1.v.type)], IS_ARRAY, >2
+               |       lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
+               |       jmp >3
+               |.cold_code
+               |2:
+               |       SAVE_VALID_OPLINE opline
+               |       EXT_CALL zend_jit_prepare_assign_dim_ref, r0
+               |       test r0, r0
+               |       jz ->exception_handler_undef
+               |       mov FCARG1a, r0
+               |       jmp >1
+               |.code
+               |1:
                op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
        }
 
@@ -4618,6 +4632,7 @@ static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const ze
                if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
                        |       IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
                }
+               |3:
                |       SEPARATE_ARRAY op1_addr, op1_info, 1
        } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
                if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
@@ -4821,7 +4836,21 @@ static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, const
 
        if (op1_info & MAY_BE_REF) {
                |       LOAD_ZVAL_ADDR FCARG1a, op1_addr
-               |       ZVAL_DEREF FCARG1a, op1_info
+               |       IF_NOT_Z_TYPE FCARG1a, IS_REFERENCE, >1
+               |       GET_Z_PTR FCARG2a, FCARG1a
+               |       IF_NOT_TYPE byte [FCARG2a + offsetof(zend_reference, val) + offsetof(zval, u1.v.type)], IS_ARRAY, >2
+               |       lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
+               |       jmp >3
+               |.cold_code
+               |2:
+               |       SAVE_VALID_OPLINE opline
+               |       EXT_CALL zend_jit_prepare_assign_dim_ref, r0
+               |       test r0, r0
+               |       jz ->exception_handler_undef
+               |       mov FCARG1a, r0
+               |       jmp >1
+               |.code
+               |1:
                op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
        }
 
@@ -4829,6 +4858,7 @@ static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, const
                if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
                        |       IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
                }
+               |3:
                |       SEPARATE_ARRAY op1_addr, op1_info, 1
        }
        if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {