Skip to content

Instantly share code, notes, and snippets.

@dstogov
Created April 26, 2016 20:43
Show Gist options
  • Save dstogov/22813388180fd4c1d7b0ead35715b067 to your computer and use it in GitHub Desktop.
Save dstogov/22813388180fd4c1d7b0ead35715b067 to your computer and use it in GitHub Desktop.
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 9abe387..d0c5106 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -486,31 +486,58 @@ ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_inf
/* }}} */
static void zend_property_guard_dtor(zval *el) /* {{{ */ {
- efree_size(Z_PTR_P(el), sizeof(zend_ulong));
+ uint32_t *ptr = (uint32_t*)Z_PTR_P(el);
+ if (EXPECTED(!(((zend_uintptr_t)ptr) & 1))) {
+ efree_size(ptr, sizeof(uint32_t));
+ }
}
/* }}} */
-static zend_long *zend_get_property_guard(zend_object *zobj, zend_string *member) /* {{{ */
+static uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *member) /* {{{ */
{
HashTable *guards;
- zend_long stub, *guard;
+ zval *zv;
+ uint32_t *ptr;
ZEND_ASSERT(GC_FLAGS(zobj) & IS_OBJ_USE_GUARDS);
- if (GC_FLAGS(zobj) & IS_OBJ_HAS_GUARDS) {
- guards = Z_PTR(zobj->properties_table[zobj->ce->default_properties_count]);
+ zv = zobj->properties_table + zobj->ce->default_properties_count;
+ if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) {
+ zend_string *str = Z_STR_P(zv);
+ if (EXPECTED(str == member) ||
+ /* hash values are always pred-calculated here */
+ (EXPECTED(ZSTR_H(str) == ZSTR_H(member)) &&
+ EXPECTED(ZSTR_LEN(str) == ZSTR_LEN(member)) &&
+ EXPECTED(memcmp(ZSTR_VAL(str), ZSTR_VAL(member), ZSTR_LEN(member)) == 0))) {
+ return &zv->u2.property_guard;
+ } else if (EXPECTED(zv->u2.property_guard == 0)) {
+ zend_string_release(Z_STR_P(zv));
+ ZVAL_STR_COPY(zv, member);
+ return &zv->u2.property_guard;
+ } else {
+ ALLOC_HASHTABLE(guards);
+ zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0);
+ /* mark pointer as "special" using low bit */
+ zend_hash_add_new_ptr(guards, member, (void*)(((zend_uintptr_t)&zv->u2.property_guard) | 1));
+ ZVAL_ARR(zv, guards);
+ }
+ } else if (EXPECTED(Z_TYPE_P(zv) == IS_ARRAY)) {
+ guards = Z_ARRVAL_P(zv);
ZEND_ASSERT(guards != NULL);
- if ((guard = (zend_long *)zend_hash_find_ptr(guards, member)) != NULL) {
- return guard;
+ zv = zend_hash_find(guards, member);
+ if (zv != NULL) {
+ return (uint32_t*)(((zend_uintptr_t)Z_PTR_P(zv)) & ~1);
}
} else {
- ALLOC_HASHTABLE(guards);
- zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0);
- Z_PTR(zobj->properties_table[zobj->ce->default_properties_count]) = guards;
+ ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF);
GC_FLAGS(zobj) |= IS_OBJ_HAS_GUARDS;
- }
-
- stub = 0;
- return (zend_long *)zend_hash_add_mem(guards, member, &stub, sizeof(zend_ulong));
+ ZVAL_STR_COPY(zv, member);
+ zv->u2.property_guard = 0;
+ return &zv->u2.property_guard;
+ }
+ /* we have to allocate uint32_t separately because ht->arData may be reallocated */
+ ptr = (uint32_t*)emalloc(sizeof(uint32_t));
+ *ptr = 0;
+ return (uint32_t*)zend_hash_add_new_ptr(guards, member, ptr);
}
/* }}} */
@@ -555,7 +582,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
/* magic isset */
if ((type == BP_VAR_IS) && zobj->ce->__isset) {
zval tmp_object, tmp_result;
- zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member));
+ uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
if (!((*guard) & IN_ISSET)) {
ZVAL_COPY(&tmp_object, object);
@@ -579,7 +606,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
/* magic get */
if (zobj->ce->__get) {
- zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member));
+ uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
if (!((*guard) & IN_GET)) {
zval tmp_object;
@@ -674,7 +701,7 @@ found:
/* magic set */
if (zobj->ce->__set) {
- zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member));
+ uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
if (!((*guard) & IN_SET)) {
zval tmp_object;
@@ -944,7 +971,7 @@ static void zend_std_unset_property(zval *object, zval *member, void **cache_slo
/* magic unset */
if (zobj->ce->__unset) {
- zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member));
+ uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
if (!((*guard) & IN_UNSET)) {
zval tmp_object;
@@ -1507,7 +1534,7 @@ found:
result = 0;
if ((has_set_exists != 2) && zobj->ce->__isset) {
- zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member));
+ uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
if (!((*guard) & IN_ISSET)) {
zval rv;
diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c
index 793d1ac..0f05233 100644
--- a/Zend/zend_objects.c
+++ b/Zend/zend_objects.c
@@ -46,7 +46,6 @@ ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce)
}
if (UNEXPECTED(ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
GC_FLAGS(object) |= IS_OBJ_USE_GUARDS;
- Z_PTR_P(p) = NULL;
ZVAL_UNDEF(p);
}
}
@@ -71,11 +70,17 @@ ZEND_API void zend_object_std_dtor(zend_object *object)
} while (p != end);
}
if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_HAS_GUARDS)) {
- HashTable *guards = Z_PTR_P(p);
+ if (EXPECTED(Z_TYPE_P(p) == IS_STRING)) {
+ zend_string_release(Z_STR_P(p));
+ } else {
+ HashTable *guards;
- ZEND_ASSERT(guards != NULL);
- zend_hash_destroy(guards);
- FREE_HASHTABLE(guards);
+ ZEND_ASSERT(Z_TYPE_P(p) == IS_ARRAY);
+ guards = Z_ARRVAL_P(p);
+ ZEND_ASSERT(guards != NULL);
+ zend_hash_destroy(guards);
+ FREE_HASHTABLE(guards);
+ }
}
}
diff --git a/Zend/zend_types.h b/Zend/zend_types.h
index 9545b53..b775bd7 100644
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@ -138,6 +138,7 @@ struct _zval_struct {
uint32_t fe_pos; /* foreach position */
uint32_t fe_iter_idx; /* foreach iterator index */
uint32_t access_flags; /* class constant access flags */
+ uint32_t property_guard; /* single property guard */
} u2;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment