From: Dmitry Stogov Date: Tue, 31 Jul 2018 09:24:53 +0000 (+0300) Subject: Simplified property name to string conversion X-Git-Tag: php-7.3.0beta1~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=57527455eb8bd09f1795804559d137cedfdf8592;p=php Simplified property name to string conversion --- diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 1bb8ee8197..8338554e4e 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -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; } /* }}} */