Skip to content

Commit

Permalink
Implement mechanism for finding prop_info for property slot
Browse files Browse the repository at this point in the history
Currently there is no efficient way of finding the property_info
which corresponds to a given property slot. This patch implements
such a mechanism, by storing an array of property_infos in offset
order on the class. This structure is lazily initialized when it
is needed, though we could also compute it during inheritance.

This patch only uses it to optimize visibility checks during
foreach (and get_object_vars etc). We avoid having to look up the
property by name and can directly check the accessibility.

We're also interested in having this mapping to handle some edge
cases in the typed properties implementation.
  • Loading branch information
nikic committed Jan 7, 2019
1 parent 9788344 commit 7429cb1
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Zend/zend.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ struct _zend_class_entry {
HashTable properties_info;
HashTable constants_table;

struct _zend_property_info **properties_info_table;

zend_function *constructor;
zend_function *destructor;
zend_function *clone;
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify

ce->default_properties_count = 0;
ce->default_static_members_count = 0;
ce->properties_info_table = NULL;

if (nullify_handlers) {
ce->constructor = NULL;
Expand Down
33 changes: 33 additions & 0 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,39 @@
called, we cal __call handler.
*/

ZEND_API zend_property_info **zend_build_properties_info_table(zend_class_entry *ce)
{
zend_property_info *prop;
zend_property_info **table = pemalloc(
sizeof(zend_property_info *) * ce->default_properties_count,
ce->type == ZEND_INTERNAL_CLASS
);

ZEND_ASSERT(ce->properties_info_table == NULL);
ZEND_ASSERT(ce->default_properties_count != 0);
ce->properties_info_table = table;

if (ce->parent && ce->parent->default_properties_count != 0) {
zend_property_info **parent_table = zend_get_properties_info_table(ce->parent);
memcpy(
table, parent_table,
sizeof(zend_property_info *) * ce->parent->default_properties_count
);

/* Child did not add any new properties, we are done */
if (ce->default_properties_count == ce->parent->default_properties_count) {
return table;
}
}

ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0) {
table[OBJ_PROP_TO_NUM(prop->offset)] = prop;
}
} ZEND_HASH_FOREACH_END();
return table;
}

ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */
{
if (!zobj->properties) {
Expand Down
21 changes: 21 additions & 0 deletions Zend/zend_object_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,27 @@ ZEND_API HashTable *zend_get_properties_for(zval *obj, zend_prop_purpose purpose
} \
} while (0)

ZEND_API struct _zend_property_info **zend_build_properties_info_table(zend_class_entry *ce);
ZEND_API int zend_check_property_info_access(struct _zend_property_info *prop_info);

static inline struct _zend_property_info **zend_get_properties_info_table(zend_class_entry *ce)
{
ZEND_ASSERT(ce->default_properties_count != 0);
if (ce->properties_info_table) {
return ce->properties_info_table;
}

return zend_build_properties_info_table(ce);
}

static inline struct _zend_property_info *zend_get_property_info_for_slot(zend_object *obj, zval *slot)
{
struct _zend_property_info **table = zend_get_properties_info_table(obj->ce);
intptr_t prop_num = slot - obj->properties_table;
ZEND_ASSERT(prop_num >= 0 && prop_num < obj->ce->default_properties_count);
return table[prop_num];
}

#define zend_free_trampoline(func) do { \
if ((func) == &EG(trampoline)) { \
EG(trampoline).common.function_name = NULL; \
Expand Down
7 changes: 7 additions & 0 deletions Zend/zend_opcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,10 @@ ZEND_API void destroy_zend_class(zval *zv)
_destroy_zend_class_traits_info(ce);
}

if (ce->properties_info_table) {
efree(ce->properties_info_table);
}

break;
case ZEND_INTERNAL_CLASS:
if (ce->default_properties_table) {
Expand Down Expand Up @@ -374,6 +378,9 @@ ZEND_API void destroy_zend_class(zval *zv)
if (ce->num_interfaces > 0) {
free(ce->interfaces);
}
if (ce->properties_info_table) {
free(ce->properties_info_table);
}
free(ce);
break;
}
Expand Down

0 comments on commit 7429cb1

Please sign in to comment.