]> granicus.if.org Git - php/commitdiff
Simplified property name to string conversion
authorDmitry Stogov <dmitry@zend.com>
Tue, 31 Jul 2018 09:24:53 +0000 (12:24 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 31 Jul 2018 09:24:53 +0000 (12:24 +0300)
Zend/zend_object_handlers.c

index 1bb8ee81973104ba44a4b9a2cea55bb1c770f1c4..8338554e4e7035dd3b14ca06f9cc9c58e5d05ddf 100644 (file)
@@ -173,12 +173,13 @@ ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp) /* {{{ *
 }
 /* }}} */
 
-static void zend_std_call_getter(zend_object *zobj, zval *member, zval *retval) /* {{{ */
+static void zend_std_call_getter(zend_object *zobj, zend_string *prop_name, zval *retval) /* {{{ */
 {
        zend_class_entry *ce = zobj->ce;
        zend_class_entry *orig_fake_scope = EG(fake_scope);
        zend_fcall_info fci;
        zend_fcall_info_cache fcic;
+       zval member;
 
        EG(fake_scope) = NULL;
 
@@ -188,11 +189,13 @@ static void zend_std_call_getter(zend_object *zobj, zval *member, zval *retval)
           it should return whether the call was successful or not
        */
 
+       ZVAL_STR(&member, prop_name);
+
        fci.size = sizeof(fci);
        fci.object = zobj;
        fci.retval = retval;
        fci.param_count = 1;
-       fci.params = member;
+       fci.params = &member;
        fci.no_separation = 1;
        ZVAL_UNDEF(&fci.function_name); /* Unused */
 
@@ -206,7 +209,7 @@ static void zend_std_call_getter(zend_object *zobj, zval *member, zval *retval)
 }
 /* }}} */
 
-static void zend_std_call_setter(zend_object *zobj, zval *member, zval *value) /* {{{ */
+static void zend_std_call_setter(zend_object *zobj, zend_string *prop_name, zval *value) /* {{{ */
 {
        zend_class_entry *ce = zobj->ce;
        zend_class_entry *orig_fake_scope = EG(fake_scope);
@@ -221,7 +224,7 @@ static void zend_std_call_setter(zend_object *zobj, zval *member, zval *value) /
             value to be set
        */
 
-       ZVAL_COPY_VALUE(&args[0], member);
+       ZVAL_STR(&args[0], prop_name);
        ZVAL_COPY_VALUE(&args[1], value);
        ZVAL_UNDEF(&ret);
 
@@ -244,13 +247,13 @@ static void zend_std_call_setter(zend_object *zobj, zval *member, zval *value) /
 }
 /* }}} */
 
-static void zend_std_call_unsetter(zend_object *zobj, zval *member) /* {{{ */
+static void zend_std_call_unsetter(zend_object *zobj, zend_string *prop_name) /* {{{ */
 {
        zend_class_entry *ce = zobj->ce;
        zend_class_entry *orig_fake_scope = EG(fake_scope);
        zend_fcall_info fci;
        zend_fcall_info_cache fcic;
-       zval ret;
+       zval ret, member;
 
        EG(fake_scope) = NULL;
 
@@ -258,13 +261,14 @@ static void zend_std_call_unsetter(zend_object *zobj, zval *member) /* {{{ */
              property name
        */
 
+       ZVAL_STR(&member, prop_name);
        ZVAL_UNDEF(&ret);
 
        fci.size = sizeof(fci);
        fci.object = zobj;
        fci.retval = &ret;
        fci.param_count = 1;
-       fci.params = member;
+       fci.params = &member;
        fci.no_separation = 1;
        ZVAL_UNDEF(&fci.function_name); /* Unused */
 
@@ -279,12 +283,13 @@ static void zend_std_call_unsetter(zend_object *zobj, zval *member) /* {{{ */
 }
 /* }}} */
 
-static void zend_std_call_issetter(zend_object *zobj, zval *member, zval *retval) /* {{{ */
+static void zend_std_call_issetter(zend_object *zobj, zend_string *prop_name, zval *retval) /* {{{ */
 {
        zend_class_entry *ce = zobj->ce;
        zend_class_entry *orig_fake_scope = EG(fake_scope);
        zend_fcall_info fci;
        zend_fcall_info_cache fcic;
+       zval member;
 
        EG(fake_scope) = NULL;
 
@@ -294,11 +299,13 @@ static void zend_std_call_issetter(zend_object *zobj, zval *member, zval *retval
           it should return whether the property is set or not
        */
 
+       ZVAL_STR(&member, prop_name);
+
        fci.size = sizeof(fci);
        fci.object = zobj;
        fci.retval = retval;
        fci.param_count = 1;
-       fci.params = member;
+       fci.params = &member;
        fci.no_separation = 1;
        ZVAL_UNDEF(&fci.function_name); /* Unused */
 
@@ -603,26 +610,20 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe
 ZEND_API zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */
 {
        zend_object *zobj;
-       zval tmp_member;
+       zend_string *name, *tmp_name;
        zval *retval;
        uintptr_t property_offset;
        uint32_t *guard = NULL;
 
        zobj = Z_OBJ_P(object);
-
-       ZVAL_UNDEF(&tmp_member);
-       if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
-               ZVAL_STR(&tmp_member, zval_get_string_func(member));
-               member = &tmp_member;
-               cache_slot = NULL;
-       }
+       name = zval_get_tmp_string(member, &tmp_name);
 
 #if DEBUG_OBJECT_HANDLERS
-       fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
+       fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), ZSTR_VAL(name));
 #endif
 
        /* make zend_get_property_info silent if we have getter - we may want to use it */
-       property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (type == BP_VAR_IS) || (zobj->ce->__get != NULL), cache_slot);
+       property_offset = zend_get_property_offset(zobj->ce, name, (type == BP_VAR_IS) || (zobj->ce->__get != NULL), cache_slot);
 
        if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
                retval = OBJ_PROP(zobj, property_offset);
@@ -638,17 +639,17 @@ ZEND_API zval *zend_std_read_property(zval *object, zval *member, int type, void
                                        Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
 
                                        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
-                                       (EXPECTED(p->key == Z_STR_P(member)) ||
-                                        (EXPECTED(p->h == ZSTR_H(Z_STR_P(member))) &&
+                                       (EXPECTED(p->key == name) ||
+                                        (EXPECTED(p->h == ZSTR_H(name)) &&
                                          EXPECTED(p->key != NULL) &&
-                                         EXPECTED(zend_string_equal_content(p->key, Z_STR_P(member)))))) {
+                                         EXPECTED(zend_string_equal_content(p->key, name))))) {
                                                retval = &p->val;
                                                goto exit;
                                        }
                                }
                                CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
                        }
-                       retval = zend_hash_find(zobj->properties, Z_STR_P(member));
+                       retval = zend_hash_find(zobj->properties, name);
                        if (EXPECTED(retval)) {
                                if (cache_slot) {
                                        uintptr_t idx = (char*)retval - (char*)zobj->properties->arData;
@@ -665,18 +666,17 @@ ZEND_API zval *zend_std_read_property(zval *object, zval *member, int type, void
        /* magic isset */
        if ((type == BP_VAR_IS) && zobj->ce->__isset) {
                zval tmp_result;
-               guard = zend_get_property_guard(zobj, Z_STR_P(member));
+               guard = zend_get_property_guard(zobj, name);
 
                if (!((*guard) & IN_ISSET)) {
-                       if (Z_TYPE(tmp_member) == IS_UNDEF) {
-                               ZVAL_COPY(&tmp_member, member);
-                               member = &tmp_member;
+                       if (!tmp_name && !ZSTR_IS_INTERNED(name)) {
+                               tmp_name = zend_string_copy(name);
                        }
                        GC_ADDREF(zobj);
                        ZVAL_UNDEF(&tmp_result);
 
                        *guard |= IN_ISSET;
-                       zend_std_call_issetter(zobj, member, &tmp_result);
+                       zend_std_call_issetter(zobj, name, &tmp_result);
                        *guard &= ~IN_ISSET;
 
                        if (!zend_is_true(&tmp_result)) {
@@ -696,14 +696,14 @@ ZEND_API zval *zend_std_read_property(zval *object, zval *member, int type, void
                }
        } else if (zobj->ce->__get) {
                /* magic get */
-               guard = zend_get_property_guard(zobj, Z_STR_P(member));
+               guard = zend_get_property_guard(zobj, name);
                if (!((*guard) & IN_GET)) {
                        /* have getter - try with it! */
 call_getter_addref:
                        GC_ADDREF(zobj);
 call_getter:
                        *guard |= IN_GET; /* prevent circular getting */
-                       zend_std_call_getter(zobj, member, rv);
+                       zend_std_call_getter(zobj, name, rv);
                        *guard &= ~IN_GET;
 
                        if (Z_TYPE_P(rv) != IS_UNDEF) {
@@ -711,7 +711,7 @@ call_getter:
                                if (!Z_ISREF_P(rv) &&
                                    (type == BP_VAR_W || type == BP_VAR_RW  || type == BP_VAR_UNSET)) {
                                        if (UNEXPECTED(Z_TYPE_P(rv) != IS_OBJECT)) {
-                                               zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member));
+                                               zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
                                        }
                                }
                        } else {
@@ -719,7 +719,7 @@ call_getter:
                        }
                        OBJ_RELEASE(zobj);
                        goto exit;
-               } else if (Z_STRVAL_P(member)[0] == '\0' && Z_STRLEN_P(member) != 0) {
+               } else if (ZSTR_VAL(name)[0] == '\0' && ZSTR_LEN(name) != 0) {
                        zend_throw_error(NULL, "Cannot access property started with '\\0'");
                        retval = &EG(uninitialized_zval);
                        goto exit;
@@ -727,14 +727,12 @@ call_getter:
        }
 
        if ((type != BP_VAR_IS)) {
-               zend_error(E_NOTICE,"Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member));
+               zend_error(E_NOTICE,"Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
        }
        retval = &EG(uninitialized_zval);
 
 exit:
-       if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
-               zval_ptr_dtor(&tmp_member);
-       }
+       zend_tmp_string_release(tmp_name);
 
        return retval;
 }
@@ -743,20 +741,14 @@ exit:
 ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */
 {
        zend_object *zobj;
-       zval tmp_member;
+       zend_string *name, *tmp_name;
        zval *variable_ptr;
        uintptr_t property_offset;
 
        zobj = Z_OBJ_P(object);
+       name = zval_get_tmp_string(member, &tmp_name);
 
-       ZVAL_UNDEF(&tmp_member);
-       if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
-               ZVAL_STR(&tmp_member, zval_get_string_func(member));
-               member = &tmp_member;
-               cache_slot = NULL;
-       }
-
-       property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (zobj->ce->__set != NULL), cache_slot);
+       property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__set != NULL), cache_slot);
 
        if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
                variable_ptr = OBJ_PROP(zobj, property_offset);
@@ -771,7 +763,7 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, v
                                }
                                zobj->properties = zend_array_dup(zobj->properties);
                        }
-                       if ((variable_ptr = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) {
+                       if ((variable_ptr = zend_hash_find(zobj->properties, name)) != NULL) {
 found:
                                zend_assign_to_variable(variable_ptr, value, IS_CV);
                                goto exit;
@@ -783,18 +775,18 @@ found:
 
        /* magic set */
        if (zobj->ce->__set) {
-               uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
+               uint32_t *guard = zend_get_property_guard(zobj, name);
 
            if (!((*guard) & IN_SET)) {
                        GC_ADDREF(zobj);
                        (*guard) |= IN_SET; /* prevent circular setting */
-                       zend_std_call_setter(zobj, member, value);
+                       zend_std_call_setter(zobj, name, value);
                        (*guard) &= ~IN_SET;
                        OBJ_RELEASE(zobj);
                } else if (EXPECTED(!IS_WRONG_PROPERTY_OFFSET(property_offset))) {
                        goto write_std_property;
                } else {
-                       if (Z_STRVAL_P(member)[0] == '\0' && Z_STRLEN_P(member) != 0) {
+                       if (ZSTR_VAL(name)[0] == '\0' && ZSTR_LEN(name) != 0) {
                                zend_throw_error(NULL, "Cannot access property started with '\\0'");
                                goto exit;
                        }
@@ -818,14 +810,12 @@ write_std_property:
                        if (!zobj->properties) {
                                rebuild_object_properties(zobj);
                        }
-                       zend_hash_add_new(zobj->properties, Z_STR_P(member), value);
+                       zend_hash_add_new(zobj->properties, name, value);
                }
        }
 
 exit:
-       if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
-               zval_ptr_dtor(&tmp_member);
-       }
+       zend_tmp_string_release(tmp_name);
 }
 /* }}} */
 
@@ -993,19 +983,13 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zval *object, zval *member, int typ
 ZEND_API void zend_std_unset_property(zval *object, zval *member, void **cache_slot) /* {{{ */
 {
        zend_object *zobj;
-       zval tmp_member;
+       zend_string *name, *tmp_name;
        uintptr_t property_offset;
 
        zobj = Z_OBJ_P(object);
+       name = zval_get_tmp_string(member, &tmp_name);
 
-       ZVAL_UNDEF(&tmp_member);
-       if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
-               ZVAL_STR(&tmp_member, zval_get_string_func(member));
-               member = &tmp_member;
-               cache_slot = NULL;
-       }
-
-       property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (zobj->ce->__unset != NULL), cache_slot);
+       property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__unset != NULL), cache_slot);
 
        if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
                zval *slot = OBJ_PROP(zobj, property_offset);
@@ -1026,7 +1010,7 @@ ZEND_API void zend_std_unset_property(zval *object, zval *member, void **cache_s
                        }
                        zobj->properties = zend_array_dup(zobj->properties);
                }
-               if (EXPECTED(zend_hash_del(zobj->properties, Z_STR_P(member)) != FAILURE)) {
+               if (EXPECTED(zend_hash_del(zobj->properties, name) != FAILURE)) {
                        goto exit;
                }
        } else if (UNEXPECTED(EG(exception))) {
@@ -1035,14 +1019,14 @@ ZEND_API void zend_std_unset_property(zval *object, zval *member, void **cache_s
 
        /* magic unset */
        if (zobj->ce->__unset) {
-               uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
+               uint32_t *guard = zend_get_property_guard(zobj, name);
                if (!((*guard) & IN_UNSET)) {
                        /* have unseter - try with it! */
                        (*guard) |= IN_UNSET; /* prevent circular unsetting */
-                       zend_std_call_unsetter(zobj, member);
+                       zend_std_call_unsetter(zobj, name);
                        (*guard) &= ~IN_UNSET;
                } else {
-                       if (Z_STRVAL_P(member)[0] == '\0' && Z_STRLEN_P(member) != 0) {
+                       if (ZSTR_VAL(name)[0] == '\0' && ZSTR_LEN(name) != 0) {
                                zend_throw_error(NULL, "Cannot access property started with '\\0'");
                                goto exit;
                        }
@@ -1050,9 +1034,7 @@ ZEND_API void zend_std_unset_property(zval *object, zval *member, void **cache_s
        }
 
 exit:
-       if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
-               zval_ptr_dtor(&tmp_member);
-       }
+       zend_tmp_string_release(tmp_name);
 }
 /* }}} */
 
@@ -1603,19 +1585,13 @@ ZEND_API int zend_std_has_property(zval *object, zval *member, int has_set_exist
        zend_object *zobj;
        int result;
        zval *value = NULL;
-       zval tmp_member;
+       zend_string *name, *tmp_name;
        uintptr_t property_offset;
 
        zobj = Z_OBJ_P(object);
+       name = zval_get_tmp_string(member, &tmp_name);
 
-       ZVAL_UNDEF(&tmp_member);
-       if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
-               ZVAL_STR(&tmp_member, zval_get_string_func(member));
-               member = &tmp_member;
-               cache_slot = NULL;
-       }
-
-       property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), 1, cache_slot);
+       property_offset = zend_get_property_offset(zobj->ce, name, 1, cache_slot);
 
        if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
                value = OBJ_PROP(zobj, property_offset);
@@ -1631,35 +1607,32 @@ ZEND_API int zend_std_has_property(zval *object, zval *member, int has_set_exist
                                        Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
 
                                        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
-                                       (EXPECTED(p->key == Z_STR_P(member)) ||
-                                        (EXPECTED(p->h == ZSTR_H(Z_STR_P(member))) &&
+                                       (EXPECTED(p->key == name) ||
+                                        (EXPECTED(p->h == ZSTR_H(name)) &&
                                          EXPECTED(p->key != NULL) &&
-                                         EXPECTED(zend_string_equal_content(p->key, Z_STR_P(member)))))) {
+                                         EXPECTED(zend_string_equal_content(p->key, name))))) {
                                                value = &p->val;
                                                goto found;
                                        }
                                }
                                CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
                        }
-                       value = zend_hash_find(zobj->properties, Z_STR_P(member));
+                       value = zend_hash_find(zobj->properties, name);
                        if (value) {
                                if (cache_slot) {
                                        uintptr_t idx = (char*)value - (char*)zobj->properties->arData;
                                        CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
                                }
 found:
-                               switch (has_set_exists) {
-                                       case ZEND_PROPERTY_ISSET:
-                                               ZVAL_DEREF(value);
-                                               result = (Z_TYPE_P(value) != IS_NULL);
-                                               break;
-                                       case ZEND_PROPERTY_EXISTS:
-                                               result = 1;
-                                               break;
-                                       case ZEND_PROPERTY_NOT_EMPTY:
-                                       default:
-                                               result = zend_is_true(value);
-                                               break;
+                               if (has_set_exists == ZEND_PROPERTY_NOT_EMPTY) {
+                                       result = zend_is_true(value);
+                               } else if (has_set_exists < ZEND_PROPERTY_NOT_EMPTY) {
+                                       ZEND_ASSERT(has_set_exists == ZEND_PROPERTY_ISSET);
+                                       ZVAL_DEREF(value);
+                                       result = (Z_TYPE_P(value) != IS_NULL);
+                               } else {
+                                       ZEND_ASSERT(has_set_exists == ZEND_PROPERTY_EXISTS);
+                                       result = 1;
                                }
                                goto exit;
                        }
@@ -1671,25 +1644,24 @@ found:
 
        result = 0;
        if ((has_set_exists != ZEND_PROPERTY_EXISTS) && zobj->ce->__isset) {
-               uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
+               uint32_t *guard = zend_get_property_guard(zobj, name);
 
                if (!((*guard) & IN_ISSET)) {
                        zval rv;
 
                        /* have issetter - try with it! */
-                       if (Z_TYPE(tmp_member) == IS_UNDEF) {
-                               ZVAL_COPY(&tmp_member, member);
-                               member = &tmp_member;
+                       if (!tmp_name && !ZSTR_IS_INTERNED(name)) {
+                               tmp_name = zend_string_copy(name);
                        }
                        GC_ADDREF(zobj);
                        (*guard) |= IN_ISSET; /* prevent circular getting */
-                       zend_std_call_issetter(zobj, member, &rv);
+                       zend_std_call_issetter(zobj, name, &rv);
                        result = zend_is_true(&rv);
                        zval_ptr_dtor(&rv);
                        if (has_set_exists == ZEND_PROPERTY_NOT_EMPTY && result) {
                                if (EXPECTED(!EG(exception)) && zobj->ce->__get && !((*guard) & IN_GET)) {
                                        (*guard) |= IN_GET;
-                                       zend_std_call_getter(zobj, member, &rv);
+                                       zend_std_call_getter(zobj, name, &rv);
                                        (*guard) &= ~IN_GET;
                                        result = i_zend_is_true(&rv);
                                        zval_ptr_dtor(&rv);
@@ -1703,9 +1675,7 @@ found:
        }
 
 exit:
-       if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
-               zval_ptr_dtor(&tmp_member);
-       }
+       zend_tmp_string_release(tmp_name);
        return result;
 }
 /* }}} */