diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index fdde5998db93f..db739f33f3050 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -132,6 +132,7 @@ PHPAPI zend_class_entry *reflection_property_hook_type_ptr; typedef struct _property_reference { zend_property_info *prop; zend_string *unmangled_name; + void *cache_slot[3]; } property_reference; /* Struct for parameters */ @@ -1506,6 +1507,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_string *name, reference = (property_reference*) emalloc(sizeof(property_reference)); reference->prop = prop; reference->unmangled_name = zend_string_copy(name); + memset(reference->cache_slot, 0, sizeof(reference->cache_slot)); intern->ptr = reference; intern->ref_type = REF_TYPE_PROPERTY; intern->ce = ce; @@ -5643,6 +5645,7 @@ ZEND_METHOD(ReflectionProperty, __construct) reference = (property_reference*) emalloc(sizeof(property_reference)); reference->prop = dynam_prop ? NULL : property_info; reference->unmangled_name = zend_string_copy(name); + memset(reference->cache_slot, 0, sizeof(reference->cache_slot)); intern->ptr = reference; intern->ref_type = REF_TYPE_PROPERTY; intern->ce = ce; @@ -5794,9 +5797,10 @@ ZEND_METHOD(ReflectionProperty, getValue) zval *object = NULL; zval *member_p = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &object) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_OBJECT_EX(object, 1, 0) + ZEND_PARSE_PARAMETERS_END(); GET_REFLECTION_OBJECT_PTR(ref); @@ -5819,7 +5823,23 @@ ZEND_METHOD(ReflectionProperty, getValue) RETURN_THROWS(); } - member_p = zend_read_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, 0, &rv); + if (ref->cache_slot[0] == Z_OBJCE_P(object)) { + uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1]; + + if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + zval *retval = OBJ_PROP(Z_OBJ_P(object), prop_offset); + if (EXPECTED(!Z_ISUNDEF_P(retval))) { + RETURN_COPY_DEREF(retval); + } + } + } + + zend_class_entry *old_scope = EG(fake_scope); + EG(fake_scope) = intern->ce; + member_p = Z_OBJ_P(object)->handlers->read_property(Z_OBJ_P(object), + ref->unmangled_name, BP_VAR_R, ref->cache_slot, &rv); + EG(fake_scope) = old_scope; + if (member_p != &rv) { RETURN_COPY_DEREF(member_p); } else { @@ -5873,7 +5893,10 @@ ZEND_METHOD(ReflectionProperty, setValue) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); - zend_update_property_ex(intern->ce, object, ref->unmangled_name, value); + zend_class_entry *old_scope = EG(fake_scope); + EG(fake_scope) = intern->ce; + object->handlers->write_property(object, ref->unmangled_name, value, ref->cache_slot); + EG(fake_scope) = old_scope; } } /* }}} */ @@ -5897,9 +5920,9 @@ ZEND_METHOD(ReflectionProperty, getRawValue) property_reference *ref; zval *object; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT(object) + ZEND_PARSE_PARAMETERS_END(); GET_REFLECTION_OBJECT_PTR(ref); @@ -5908,6 +5931,17 @@ ZEND_METHOD(ReflectionProperty, getRawValue) RETURN_THROWS(); } + if (ref->cache_slot[0] == Z_OBJCE_P(object)) { + uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1]; + + if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + zval *retval = OBJ_PROP(Z_OBJ_P(object), prop_offset); + if (EXPECTED(!Z_ISUNDEF_P(retval))) { + RETURN_COPY_DEREF(retval); + } + } + } + zend_property_info *prop = reflection_property_get_effective_prop(ref, intern->ce, Z_OBJ_P(object)); @@ -5918,7 +5952,12 @@ ZEND_METHOD(ReflectionProperty, getRawValue) if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_GET]) { zval rv; - zval *member_p = zend_read_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, 0, &rv); + zend_class_entry *old_scope = EG(fake_scope); + EG(fake_scope) = intern->ce; + zval *member_p = Z_OBJ_P(object)->handlers->read_property( + Z_OBJ_P(object), ref->unmangled_name, BP_VAR_R, + ref->cache_slot, &rv); + EG(fake_scope) = old_scope; if (member_p != &rv) { RETURN_COPY_DEREF(member_p); @@ -5935,11 +5974,14 @@ ZEND_METHOD(ReflectionProperty, getRawValue) } static void reflection_property_set_raw_value(zend_property_info *prop, - zend_string *unmangled_name, reflection_object *intern, + zend_string *unmangled_name, void *cache_slot[3], reflection_object *intern, zend_object *object, zval *value) { if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_SET]) { - zend_update_property_ex(intern->ce, object, unmangled_name, value); + zend_class_entry *old_scope = EG(fake_scope); + EG(fake_scope) = intern->ce; + object->handlers->write_property(object, unmangled_name, value, cache_slot); + EG(fake_scope) = old_scope; } else { zend_function *func = zend_get_property_hook_trampoline(prop, ZEND_PROPERTY_HOOK_SET, unmangled_name); zend_call_known_instance_method_with_1_params(func, object, NULL, value); @@ -5955,9 +5997,10 @@ ZEND_METHOD(ReflectionProperty, setRawValue) GET_REFLECTION_OBJECT_PTR(ref); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "oz", &object, &value) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 2) { + Z_PARAM_OBJECT(object) + Z_PARAM_ZVAL(value) + } ZEND_PARSE_PARAMETERS_END(); zend_property_info *prop = reflection_property_get_effective_prop(ref, intern->ce, Z_OBJ_P(object)); @@ -5967,7 +6010,8 @@ ZEND_METHOD(ReflectionProperty, setRawValue) RETURN_THROWS(); } - reflection_property_set_raw_value(prop, ref->unmangled_name, intern, Z_OBJ_P(object), value); + reflection_property_set_raw_value(prop, ref->unmangled_name, + ref->cache_slot, intern, Z_OBJ_P(object), value); } static zend_result reflection_property_check_lazy_compatible( @@ -6046,8 +6090,8 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization) /* Do not trigger initialization */ Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_LAZY; - reflection_property_set_raw_value(prop, ref->unmangled_name, intern, object, - value); + reflection_property_set_raw_value(prop, ref->unmangled_name, + ref->cache_slot, intern, object, value); /* Mark property as lazy again if an exception prevented update */ if (EG(exception) && prop_was_lazy && Z_TYPE_P(var_ptr) == IS_UNDEF @@ -6143,9 +6187,10 @@ ZEND_METHOD(ReflectionProperty, isInitialized) zval *object = NULL; zval *member_p = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &object) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_OBJECT_EX(object, 1, 0) + ZEND_PARSE_PARAMETERS_END(); GET_REFLECTION_OBJECT_PTR(ref); @@ -6170,9 +6215,19 @@ ZEND_METHOD(ReflectionProperty, isInitialized) RETURN_THROWS(); } + if (ref->cache_slot[0] == Z_OBJCE_P(object)) { + uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1]; + + if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + zval *value = OBJ_PROP(Z_OBJ_P(object), prop_offset); + RETURN_BOOL(!Z_ISUNDEF_P(value)); + } + } + old_scope = EG(fake_scope); EG(fake_scope) = intern->ce; - retval = Z_OBJ_HT_P(object)->has_property(Z_OBJ_P(object), ref->unmangled_name, ZEND_PROPERTY_EXISTS, NULL); + retval = Z_OBJ_HT_P(object)->has_property(Z_OBJ_P(object), + ref->unmangled_name, ZEND_PROPERTY_EXISTS, ref->cache_slot); EG(fake_scope) = old_scope; RETVAL_BOOL(retval);