Skip to content

Commit 1463f2b

Browse files
committed
Optimize ReflectionProperty::getValue(), ::getRawValue(), ::isInitialized(), ::setValue(), ::setRawValue()
- Pass a cache slot to the property handler - Inline the simple case of fetching a declared property - Use the new parameter parsing API This makes these methods 12% to 60% faster. Using the new parameter parsing API had the most impact, by far.
1 parent e6c570a commit 1463f2b

File tree

1 file changed

+87
-32
lines changed

1 file changed

+87
-32
lines changed

ext/reflection/php_reflection.c

Lines changed: 87 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ PHPAPI zend_class_entry *reflection_property_hook_type_ptr;
132132
typedef struct _property_reference {
133133
zend_property_info *prop;
134134
zend_string *unmangled_name;
135+
void *cache_slot[3];
135136
} property_reference;
136137

137138
/* Struct for parameters */
@@ -1506,6 +1507,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_string *name,
15061507
reference = (property_reference*) emalloc(sizeof(property_reference));
15071508
reference->prop = prop;
15081509
reference->unmangled_name = zend_string_copy(name);
1510+
memset(reference->cache_slot, 0, sizeof(reference->cache_slot));
15091511
intern->ptr = reference;
15101512
intern->ref_type = REF_TYPE_PROPERTY;
15111513
intern->ce = ce;
@@ -5643,6 +5645,7 @@ ZEND_METHOD(ReflectionProperty, __construct)
56435645
reference = (property_reference*) emalloc(sizeof(property_reference));
56445646
reference->prop = dynam_prop ? NULL : property_info;
56455647
reference->unmangled_name = zend_string_copy(name);
5648+
memset(reference->cache_slot, 0, sizeof(reference->cache_slot));
56465649
intern->ptr = reference;
56475650
intern->ref_type = REF_TYPE_PROPERTY;
56485651
intern->ce = ce;
@@ -5794,9 +5797,10 @@ ZEND_METHOD(ReflectionProperty, getValue)
57945797
zval *object = NULL;
57955798
zval *member_p = NULL;
57965799

5797-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &object) == FAILURE) {
5798-
RETURN_THROWS();
5799-
}
5800+
ZEND_PARSE_PARAMETERS_START(0, 1)
5801+
Z_PARAM_OPTIONAL
5802+
Z_PARAM_OBJECT_EX(object, 1, 0)
5803+
ZEND_PARSE_PARAMETERS_END();
58005804

58015805
GET_REFLECTION_OBJECT_PTR(ref);
58025806

@@ -5813,13 +5817,29 @@ ZEND_METHOD(ReflectionProperty, getValue)
58135817
RETURN_THROWS();
58145818
}
58155819

5816-
/* TODO: Should this always use intern->ce? */
5817-
if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
5818-
_DO_THROW("Given object is not an instance of the class this property was declared in");
5819-
RETURN_THROWS();
5820+
if (ref->cache_slot[0] == Z_OBJCE_P(object)) {
5821+
uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1];
5822+
5823+
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
5824+
zval *retval = OBJ_PROP(Z_OBJ_P(object), prop_offset);
5825+
if (EXPECTED(Z_TYPE_INFO_P(retval) != IS_UNDEF)) {
5826+
RETURN_COPY_DEREF(retval);
5827+
}
5828+
}
5829+
} else {
5830+
/* TODO: Should this always use intern->ce? */
5831+
if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
5832+
_DO_THROW("Given object is not an instance of the class this property was declared in");
5833+
RETURN_THROWS();
5834+
}
58205835
}
58215836

5822-
member_p = zend_read_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, 0, &rv);
5837+
zend_class_entry *old_scope = EG(fake_scope);
5838+
EG(fake_scope) = intern->ce;
5839+
member_p = Z_OBJ_P(object)->handlers->read_property(Z_OBJ_P(object),
5840+
ref->unmangled_name, BP_VAR_R, ref->cache_slot, &rv);
5841+
EG(fake_scope) = old_scope;
5842+
58235843
if (member_p != &rv) {
58245844
RETURN_COPY_DEREF(member_p);
58255845
} else {
@@ -5873,7 +5893,10 @@ ZEND_METHOD(ReflectionProperty, setValue)
58735893
Z_PARAM_ZVAL(value)
58745894
ZEND_PARSE_PARAMETERS_END();
58755895

5876-
zend_update_property_ex(intern->ce, object, ref->unmangled_name, value);
5896+
zend_class_entry *old_scope = EG(fake_scope);
5897+
EG(fake_scope) = intern->ce;
5898+
object->handlers->write_property(object, ref->unmangled_name, value, ref->cache_slot);
5899+
EG(fake_scope) = old_scope;
58775900
}
58785901
}
58795902
/* }}} */
@@ -5897,15 +5920,26 @@ ZEND_METHOD(ReflectionProperty, getRawValue)
58975920
property_reference *ref;
58985921
zval *object;
58995922

5900-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) {
5901-
RETURN_THROWS();
5902-
}
5923+
ZEND_PARSE_PARAMETERS_START(1, 1)
5924+
Z_PARAM_OBJECT(object)
5925+
ZEND_PARSE_PARAMETERS_END();
59035926

59045927
GET_REFLECTION_OBJECT_PTR(ref);
59055928

5906-
if (!instanceof_function(Z_OBJCE_P(object), intern->ce)) {
5907-
_DO_THROW("Given object is not an instance of the class this property was declared in");
5908-
RETURN_THROWS();
5929+
if (ref->cache_slot[0] == Z_OBJCE_P(object)) {
5930+
uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1];
5931+
5932+
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
5933+
zval *retval = OBJ_PROP(Z_OBJ_P(object), prop_offset);
5934+
if (EXPECTED(Z_TYPE_INFO_P(retval) != IS_UNDEF)) {
5935+
RETURN_COPY_DEREF(retval);
5936+
}
5937+
}
5938+
} else {
5939+
if (!instanceof_function(Z_OBJCE_P(object), intern->ce)) {
5940+
_DO_THROW("Given object is not an instance of the class this property was declared in");
5941+
RETURN_THROWS();
5942+
}
59095943
}
59105944

59115945
zend_property_info *prop = reflection_property_get_effective_prop(ref,
@@ -5918,7 +5952,12 @@ ZEND_METHOD(ReflectionProperty, getRawValue)
59185952

59195953
if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_GET]) {
59205954
zval rv;
5921-
zval *member_p = zend_read_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, 0, &rv);
5955+
zend_class_entry *old_scope = EG(fake_scope);
5956+
EG(fake_scope) = intern->ce;
5957+
zval *member_p = Z_OBJ_P(object)->handlers->read_property(
5958+
Z_OBJ_P(object), ref->unmangled_name, BP_VAR_R,
5959+
ref->cache_slot, &rv);
5960+
EG(fake_scope) = old_scope;
59225961

59235962
if (member_p != &rv) {
59245963
RETURN_COPY_DEREF(member_p);
@@ -5935,11 +5974,14 @@ ZEND_METHOD(ReflectionProperty, getRawValue)
59355974
}
59365975

59375976
static void reflection_property_set_raw_value(zend_property_info *prop,
5938-
zend_string *unmangled_name, reflection_object *intern,
5977+
zend_string *unmangled_name, void *cache_slot[3], reflection_object *intern,
59395978
zend_object *object, zval *value)
59405979
{
59415980
if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
5942-
zend_update_property_ex(intern->ce, object, unmangled_name, value);
5981+
zend_class_entry *old_scope = EG(fake_scope);
5982+
EG(fake_scope) = intern->ce;
5983+
object->handlers->write_property(object, unmangled_name, value, cache_slot);
5984+
EG(fake_scope) = old_scope;
59435985
} else {
59445986
zend_function *func = zend_get_property_hook_trampoline(prop, ZEND_PROPERTY_HOOK_SET, unmangled_name);
59455987
zend_call_known_instance_method_with_1_params(func, object, NULL, value);
@@ -5955,9 +5997,10 @@ ZEND_METHOD(ReflectionProperty, setRawValue)
59555997

59565998
GET_REFLECTION_OBJECT_PTR(ref);
59575999

5958-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oz", &object, &value) == FAILURE) {
5959-
RETURN_THROWS();
5960-
}
6000+
ZEND_PARSE_PARAMETERS_START(2, 2) {
6001+
Z_PARAM_OBJECT(object)
6002+
Z_PARAM_ZVAL(value)
6003+
} ZEND_PARSE_PARAMETERS_END();
59616004

59626005
zend_property_info *prop = reflection_property_get_effective_prop(ref,
59636006
intern->ce, Z_OBJ_P(object));
@@ -5967,7 +6010,8 @@ ZEND_METHOD(ReflectionProperty, setRawValue)
59676010
RETURN_THROWS();
59686011
}
59696012

5970-
reflection_property_set_raw_value(prop, ref->unmangled_name, intern, Z_OBJ_P(object), value);
6013+
reflection_property_set_raw_value(prop, ref->unmangled_name,
6014+
ref->cache_slot, intern, Z_OBJ_P(object), value);
59716015
}
59726016

59736017
static zend_result reflection_property_check_lazy_compatible(
@@ -6046,8 +6090,8 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
60466090
/* Do not trigger initialization */
60476091
Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_LAZY;
60486092

6049-
reflection_property_set_raw_value(prop, ref->unmangled_name, intern, object,
6050-
value);
6093+
reflection_property_set_raw_value(prop, ref->unmangled_name,
6094+
ref->cache_slot, intern, object, value);
60516095

60526096
/* Mark property as lazy again if an exception prevented update */
60536097
if (EG(exception) && prop_was_lazy && Z_TYPE_P(var_ptr) == IS_UNDEF
@@ -6143,9 +6187,10 @@ ZEND_METHOD(ReflectionProperty, isInitialized)
61436187
zval *object = NULL;
61446188
zval *member_p = NULL;
61456189

6146-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &object) == FAILURE) {
6147-
RETURN_THROWS();
6148-
}
6190+
ZEND_PARSE_PARAMETERS_START(0, 1)
6191+
Z_PARAM_OPTIONAL
6192+
Z_PARAM_OBJECT_EX(object, 1, 0)
6193+
ZEND_PARSE_PARAMETERS_END();
61496194

61506195
GET_REFLECTION_OBJECT_PTR(ref);
61516196

@@ -6164,15 +6209,25 @@ ZEND_METHOD(ReflectionProperty, isInitialized)
61646209
RETURN_THROWS();
61656210
}
61666211

6167-
/* TODO: Should this always use intern->ce? */
6168-
if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
6169-
_DO_THROW("Given object is not an instance of the class this property was declared in");
6170-
RETURN_THROWS();
6212+
if (ref->cache_slot[0] == Z_OBJCE_P(object)) {
6213+
uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1];
6214+
6215+
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
6216+
zval *value = OBJ_PROP(Z_OBJ_P(object), prop_offset);
6217+
RETURN_BOOL(Z_TYPE_INFO_P(value) != IS_UNDEF);
6218+
}
6219+
} else {
6220+
/* TODO: Should this always use intern->ce? */
6221+
if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
6222+
_DO_THROW("Given object is not an instance of the class this property was declared in");
6223+
RETURN_THROWS();
6224+
}
61716225
}
61726226

61736227
old_scope = EG(fake_scope);
61746228
EG(fake_scope) = intern->ce;
6175-
retval = Z_OBJ_HT_P(object)->has_property(Z_OBJ_P(object), ref->unmangled_name, ZEND_PROPERTY_EXISTS, NULL);
6229+
retval = Z_OBJ_HT_P(object)->has_property(Z_OBJ_P(object),
6230+
ref->unmangled_name, ZEND_PROPERTY_EXISTS, ref->cache_slot);
61766231
EG(fake_scope) = old_scope;
61776232

61786233
RETVAL_BOOL(retval);

0 commit comments

Comments
 (0)