Skip to content

Commit 7429cb1

Browse files
committed
Implement mechanism for finding prop_info for property slot
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.
1 parent 9788344 commit 7429cb1

File tree

5 files changed

+64
-0
lines changed

5 files changed

+64
-0
lines changed

Zend/zend.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ struct _zend_class_entry {
133133
HashTable properties_info;
134134
HashTable constants_table;
135135

136+
struct _zend_property_info **properties_info_table;
137+
136138
zend_function *constructor;
137139
zend_function *destructor;
138140
zend_function *clone;

Zend/zend_compile.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
16131613

16141614
ce->default_properties_count = 0;
16151615
ce->default_static_members_count = 0;
1616+
ce->properties_info_table = NULL;
16161617

16171618
if (nullify_handlers) {
16181619
ce->constructor = NULL;

Zend/zend_object_handlers.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,39 @@
5858
called, we cal __call handler.
5959
*/
6060

61+
ZEND_API zend_property_info **zend_build_properties_info_table(zend_class_entry *ce)
62+
{
63+
zend_property_info *prop;
64+
zend_property_info **table = pemalloc(
65+
sizeof(zend_property_info *) * ce->default_properties_count,
66+
ce->type == ZEND_INTERNAL_CLASS
67+
);
68+
69+
ZEND_ASSERT(ce->properties_info_table == NULL);
70+
ZEND_ASSERT(ce->default_properties_count != 0);
71+
ce->properties_info_table = table;
72+
73+
if (ce->parent && ce->parent->default_properties_count != 0) {
74+
zend_property_info **parent_table = zend_get_properties_info_table(ce->parent);
75+
memcpy(
76+
table, parent_table,
77+
sizeof(zend_property_info *) * ce->parent->default_properties_count
78+
);
79+
80+
/* Child did not add any new properties, we are done */
81+
if (ce->default_properties_count == ce->parent->default_properties_count) {
82+
return table;
83+
}
84+
}
85+
86+
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
87+
if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0) {
88+
table[OBJ_PROP_TO_NUM(prop->offset)] = prop;
89+
}
90+
} ZEND_HASH_FOREACH_END();
91+
return table;
92+
}
93+
6194
ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */
6295
{
6396
if (!zobj->properties) {

Zend/zend_object_handlers.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,27 @@ ZEND_API HashTable *zend_get_properties_for(zval *obj, zend_prop_purpose purpose
246246
} \
247247
} while (0)
248248

249+
ZEND_API struct _zend_property_info **zend_build_properties_info_table(zend_class_entry *ce);
250+
ZEND_API int zend_check_property_info_access(struct _zend_property_info *prop_info);
251+
252+
static inline struct _zend_property_info **zend_get_properties_info_table(zend_class_entry *ce)
253+
{
254+
ZEND_ASSERT(ce->default_properties_count != 0);
255+
if (ce->properties_info_table) {
256+
return ce->properties_info_table;
257+
}
258+
259+
return zend_build_properties_info_table(ce);
260+
}
261+
262+
static inline struct _zend_property_info *zend_get_property_info_for_slot(zend_object *obj, zval *slot)
263+
{
264+
struct _zend_property_info **table = zend_get_properties_info_table(obj->ce);
265+
intptr_t prop_num = slot - obj->properties_table;
266+
ZEND_ASSERT(prop_num >= 0 && prop_num < obj->ce->default_properties_count);
267+
return table[prop_num];
268+
}
269+
249270
#define zend_free_trampoline(func) do { \
250271
if ((func) == &EG(trampoline)) { \
251272
EG(trampoline).common.function_name = NULL; \

Zend/zend_opcode.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,10 @@ ZEND_API void destroy_zend_class(zval *zv)
316316
_destroy_zend_class_traits_info(ce);
317317
}
318318

319+
if (ce->properties_info_table) {
320+
efree(ce->properties_info_table);
321+
}
322+
319323
break;
320324
case ZEND_INTERNAL_CLASS:
321325
if (ce->default_properties_table) {
@@ -374,6 +378,9 @@ ZEND_API void destroy_zend_class(zval *zv)
374378
if (ce->num_interfaces > 0) {
375379
free(ce->interfaces);
376380
}
381+
if (ce->properties_info_table) {
382+
free(ce->properties_info_table);
383+
}
377384
free(ce);
378385
break;
379386
}

0 commit comments

Comments
 (0)