summaryrefslogtreecommitdiff
path: root/Zend/zend_object_handlers.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-01-13 11:33:00 +0300
committerDmitry Stogov <dmitry@zend.com>2015-01-13 11:33:00 +0300
commit5a24ac88539243e9ce531fb254d89ec2944e580d (patch)
treea711aeea7a2227357c6b64257695461c3fefbb95 /Zend/zend_object_handlers.c
parent58efbf0a922affe880561a226dcbd679300ff938 (diff)
downloadphp-git-5a24ac88539243e9ce531fb254d89ec2944e580d.tar.gz
Improved access to object properties (cache property offset instead of pointer to property_info).
Diffstat (limited to 'Zend/zend_object_handlers.c')
-rw-r--r--Zend/zend_object_handlers.c150
1 files changed, 104 insertions, 46 deletions
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 474ccf57ef..2dde1d18d7 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -286,14 +286,14 @@ static zend_always_inline zend_bool is_derived_class(zend_class_entry *child_cla
}
/* }}} */
-static zend_always_inline zend_property_info *zend_get_property_info_quick(zend_class_entry *ce, zend_string *member, int silent, int allow_static, void **cache_slot) /* {{{ */
+static zend_always_inline uint32_t zend_get_property_offset(zend_class_entry *ce, zend_string *member, int silent, void **cache_slot) /* {{{ */
{
zval *zv;
zend_property_info *property_info = NULL;
uint32_t flags;
if (cache_slot && EXPECTED(ce == CACHED_PTR_EX(cache_slot))) {
- return CACHED_PTR_EX(cache_slot + 1);
+ return (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
}
if (UNEXPECTED(member->val[0] == '\0')) {
@@ -304,7 +304,7 @@ static zend_always_inline zend_property_info *zend_get_property_info_quick(zend_
zend_error_noreturn(E_ERROR, "Cannot access property started with '\\0'");
}
}
- return ZEND_WRONG_PROPERTY_INFO;
+ return ZEND_WRONG_PROPERTY_OFFSET;
}
if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0)) {
@@ -326,9 +326,7 @@ static zend_always_inline zend_property_info *zend_get_property_info_quick(zend_
if (!silent) {
zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name->val, member->val);
}
- if (!allow_static) {
- return NULL;
- }
+ return ZEND_DYNAMIC_PROPERTY_OFFSET;
}
goto exit;
}
@@ -345,34 +343,96 @@ static zend_always_inline zend_property_info *zend_get_property_info_quick(zend_
&& (zv = zend_hash_find(&EG(scope)->properties_info, member)) != NULL
&& ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE) {
property_info = (zend_property_info*)Z_PTR_P(zv);
- if (!allow_static && UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) != 0)) {
- return NULL;
+ if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) != 0)) {
+ return ZEND_DYNAMIC_PROPERTY_OFFSET;
}
} else if (UNEXPECTED(property_info == NULL)) {
exit_dynamic:
if (cache_slot) {
- CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, NULL);
+ CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*)(intptr_t)ZEND_DYNAMIC_PROPERTY_OFFSET);
}
- return NULL;
+ return ZEND_DYNAMIC_PROPERTY_OFFSET;
} else if (UNEXPECTED(property_info == ZEND_WRONG_PROPERTY_INFO)) {
/* Information was available, but we were denied access. Error out. */
if (!silent) {
zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(flags), ce->name->val, member->val);
}
- return ZEND_WRONG_PROPERTY_INFO;
+ return ZEND_WRONG_PROPERTY_OFFSET;
}
exit:
if (cache_slot) {
- CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, property_info);
+ CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*)(intptr_t)property_info->offset);
}
- return property_info;
+ return property_info->offset;
}
/* }}} */
ZEND_API zend_property_info *zend_get_property_info(zend_class_entry *ce, zend_string *member, int silent) /* {{{ */
{
- return zend_get_property_info_quick(ce, member, silent, 1, NULL);
+ zval *zv;
+ zend_property_info *property_info = NULL;
+ uint32_t flags;
+
+ if (UNEXPECTED(member->val[0] == '\0')) {
+ if (!silent) {
+ if (member->len == 0) {
+ zend_error_noreturn(E_ERROR, "Cannot access empty property");
+ } else {
+ zend_error_noreturn(E_ERROR, "Cannot access property started with '\\0'");
+ }
+ }
+ return ZEND_WRONG_PROPERTY_INFO;
+ }
+
+ if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0)) {
+ goto exit_dynamic;
+ }
+
+ zv = zend_hash_find(&ce->properties_info, member);
+ if (EXPECTED(zv != NULL)) {
+ property_info = (zend_property_info*)Z_PTR_P(zv);
+ flags = property_info->flags;
+ if (UNEXPECTED((flags & ZEND_ACC_SHADOW) != 0)) {
+ /* if it's a shadow - go to access it's private */
+ property_info = NULL;
+ } else {
+ if (EXPECTED(zend_verify_property_access(property_info, ce) != 0)) {
+ if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED))
+ || UNEXPECTED((flags & ZEND_ACC_PRIVATE))) {
+ if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0)) {
+ if (!silent) {
+ zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name->val, member->val);
+ }
+ }
+ goto exit;
+ }
+ } else {
+ /* Try to look in the scope instead */
+ property_info = ZEND_WRONG_PROPERTY_INFO;
+ }
+ }
+ }
+
+ if (EG(scope) != ce
+ && EG(scope)
+ && is_derived_class(ce, EG(scope))
+ && (zv = zend_hash_find(&EG(scope)->properties_info, member)) != NULL
+ && ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE) {
+ property_info = (zend_property_info*)Z_PTR_P(zv);
+ } else if (UNEXPECTED(property_info == NULL)) {
+exit_dynamic:
+ return NULL;
+ } else if (UNEXPECTED(property_info == ZEND_WRONG_PROPERTY_INFO)) {
+ /* Information was available, but we were denied access. Error out. */
+ if (!silent) {
+ zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(flags), ce->name->val, member->val);
+ }
+ return ZEND_WRONG_PROPERTY_INFO;
+ }
+
+exit:
+ return property_info;
}
/* }}} */
@@ -390,7 +450,7 @@ ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_inf
} else {
member = zend_string_copy(prop_info_name);
}
- property_info = zend_get_property_info_quick(zobj->ce, member, 1, 1, NULL);
+ property_info = zend_get_property_info(zobj->ce, member, 1);
zend_string_release(member);
if (property_info == NULL) {
/* undefined public property */
@@ -437,7 +497,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
zend_object *zobj;
zval tmp_member;
zval *retval;
- zend_property_info *property_info;
+ uint32_t property_offset;
zobj = Z_OBJ_P(object);
@@ -453,11 +513,11 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
#endif
/* make zend_get_property_info silent if we have getter - we may want to use it */
- property_info = zend_get_property_info_quick(zobj->ce, Z_STR_P(member), (type == BP_VAR_IS) || (zobj->ce->__get != NULL), 0, cache_slot);
+ property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (type == BP_VAR_IS) || (zobj->ce->__get != NULL), cache_slot);
- if (EXPECTED(property_info != ZEND_WRONG_PROPERTY_INFO)) {
- if (EXPECTED(property_info != NULL)) {
- retval = OBJ_PROP(zobj, property_info->offset);
+ if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
+ if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
+ retval = OBJ_PROP(zobj, property_offset);
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
goto exit;
}
@@ -523,7 +583,7 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, v
zend_object *zobj;
zval tmp_member;
zval *variable_ptr;
- zend_property_info *property_info;
+ uint32_t property_offset;
zobj = Z_OBJ_P(object);
@@ -534,11 +594,11 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, v
cache_slot = NULL;
}
- property_info = zend_get_property_info_quick(zobj->ce, Z_STR_P(member), (zobj->ce->__set != NULL), 0, cache_slot);
+ property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (zobj->ce->__set != NULL), cache_slot);
- if (EXPECTED(property_info != ZEND_WRONG_PROPERTY_INFO)) {
- if (EXPECTED(property_info != NULL)) {
- variable_ptr = OBJ_PROP(zobj, property_info->offset);
+ if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
+ if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
+ variable_ptr = OBJ_PROP(zobj, property_offset);
if (Z_TYPE_P(variable_ptr) != IS_UNDEF) {
goto found;
}
@@ -565,7 +625,7 @@ found:
}
(*guard) &= ~IN_SET;
zval_ptr_dtor(&tmp_object);
- } else if (EXPECTED(property_info != ZEND_WRONG_PROPERTY_INFO)) {
+ } else if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
goto write_std_property;
} else {
if (Z_STRVAL_P(member)[0] == '\0') {
@@ -576,7 +636,7 @@ found:
}
}
}
- } else if (EXPECTED(property_info != ZEND_WRONG_PROPERTY_INFO)) {
+ } else if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
zval tmp;
write_std_property:
@@ -589,10 +649,8 @@ write_std_property:
Z_ADDREF_P(value);
}
}
- if (EXPECTED(property_info != NULL) &&
- EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0)) {
-
- ZVAL_COPY_VALUE(OBJ_PROP(zobj, property_info->offset), value);
+ if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
+ ZVAL_COPY_VALUE(OBJ_PROP(zobj, property_offset), value);
} else {
if (!zobj->properties) {
rebuild_object_properties(zobj);
@@ -695,7 +753,7 @@ static zval *zend_std_get_property_ptr_ptr(zval *object, zval *member, int type,
zend_object *zobj;
zend_string *name;
zval *retval = NULL;
- zend_property_info *property_info;
+ uint32_t property_offset;
zobj = Z_OBJ_P(object);
if (EXPECTED(Z_TYPE_P(member) == IS_STRING)) {
@@ -708,11 +766,11 @@ static zval *zend_std_get_property_ptr_ptr(zval *object, zval *member, int type,
fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), name->val);
#endif
- property_info = zend_get_property_info_quick(zobj->ce, name, (zobj->ce->__get != NULL), 0, cache_slot);
+ property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__get != NULL), cache_slot);
- if (EXPECTED(property_info != ZEND_WRONG_PROPERTY_INFO)) {
- if (EXPECTED(property_info != NULL)) {
- retval = OBJ_PROP(zobj, property_info->offset);
+ if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
+ if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
+ retval = OBJ_PROP(zobj, property_offset);
if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
if (EXPECTED(!zobj->ce->__get) ||
UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET)) {
@@ -757,7 +815,7 @@ static void zend_std_unset_property(zval *object, zval *member, void **cache_slo
{
zend_object *zobj;
zval tmp_member;
- zend_property_info *property_info;
+ uint32_t property_offset;
zobj = Z_OBJ_P(object);
@@ -768,11 +826,11 @@ static void zend_std_unset_property(zval *object, zval *member, void **cache_slo
cache_slot = NULL;
}
- property_info = zend_get_property_info_quick(zobj->ce, Z_STR_P(member), (zobj->ce->__unset != NULL), 0, cache_slot);
+ property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (zobj->ce->__unset != NULL), cache_slot);
- if (EXPECTED(property_info != ZEND_WRONG_PROPERTY_INFO)) {
- if (EXPECTED(property_info != NULL)) {
- zval *slot = OBJ_PROP(zobj, property_info->offset);
+ if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
+ if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
+ zval *slot = OBJ_PROP(zobj, property_offset);
if (Z_TYPE_P(slot) != IS_UNDEF) {
zval_ptr_dtor(slot);
@@ -1340,7 +1398,7 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists,
int result;
zval *value = NULL;
zval tmp_member;
- zend_property_info *property_info;
+ uint32_t property_offset;
zobj = Z_OBJ_P(object);
@@ -1351,11 +1409,11 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists,
cache_slot = NULL;
}
- property_info = zend_get_property_info_quick(zobj->ce, Z_STR_P(member), 1, 0, cache_slot);
+ property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), 1, cache_slot);
- if (EXPECTED(property_info != ZEND_WRONG_PROPERTY_INFO)) {
- if (EXPECTED(property_info != NULL)) {
- value = OBJ_PROP(zobj, property_info->offset);
+ if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
+ if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
+ value = OBJ_PROP(zobj, property_offset);
if (Z_TYPE_P(value) != IS_UNDEF) {
goto found;
}