Skip to content

Commit e4e7b94

Browse files
committed
Only allocate new zend_type_list if types are being resolved
1 parent 4edfd87 commit e4e7b94

File tree

1 file changed

+54
-42
lines changed

1 file changed

+54
-42
lines changed

Zend/zend_inheritance.c

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,6 +1946,31 @@ static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_e
19461946
return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
19471947
}
19481948

1949+
/* If the type was resolved then either the zend_string pointer is different, or the zend_type_list is */
1950+
static inline bool zend_was_type_resolved(zend_type original_type, zend_type resolved_type)
1951+
{
1952+
return original_type.ptr != resolved_type.ptr;
1953+
}
1954+
1955+
static zend_type zend_resolve_name_type(zend_type type, const zend_class_entry *const ce)
1956+
{
1957+
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(type));
1958+
if (ZEND_TYPE_IS_RELATIVE_SELF(type)) {
1959+
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1960+
return resolved_type;
1961+
} else if (ZEND_TYPE_IS_RELATIVE_PARENT(type)) {
1962+
if (!ce->parent) {
1963+
zend_error_noreturn(E_COMPILE_ERROR,
1964+
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");
1965+
return (zend_type) ZEND_TYPE_INIT_NONE(0);
1966+
}
1967+
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->parent->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1968+
return resolved_type;
1969+
} else {
1970+
return type;
1971+
}
1972+
}
1973+
19491974
/* We cannot modify the type in-place (e.g. via a pointer) as it is written to SHM */
19501975
static zend_type zend_resolve_single_type(zend_type type, const zend_class_entry *const ce)
19511976
{
@@ -1956,62 +1981,49 @@ static zend_type zend_resolve_single_type(zend_type type, const zend_class_entry
19561981

19571982
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(type) || (ZEND_TYPE_HAS_LIST(type)));
19581983
if (ZEND_TYPE_HAS_NAME(type)) {
1959-
if (ZEND_TYPE_IS_RELATIVE_SELF(type)) {
1960-
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1961-
return resolved_type;
1962-
} else if (ZEND_TYPE_IS_RELATIVE_PARENT(type)) {
1963-
if (!ce->parent) {
1964-
zend_error_noreturn(E_COMPILE_ERROR,
1965-
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");
1966-
return (zend_type) ZEND_TYPE_INIT_NONE(0);
1967-
}
1968-
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->parent->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1969-
return resolved_type;
1970-
} else {
1971-
return type;
1972-
}
1984+
return zend_resolve_name_type(type, ce);
19731985
}
19741986

19751987
/* Intersection types cannot have relative class_types */
19761988
if (ZEND_TYPE_IS_INTERSECTION(type)) {
19771989
return type;
19781990
}
19791991

1980-
const zend_type_list *union_type_list = ZEND_TYPE_LIST(type);
1981-
zend_type *single_type;
1982-
1983-
/* TODO Only do allocation if need to resolve types, as type is stored in SHM */
1984-
zend_type_list *new_union_type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(union_type_list->num_types));
1985-
memcpy(new_union_type_list, union_type_list, ZEND_TYPE_LIST_SIZE(union_type_list->num_types));
1992+
zend_type_list *union_type_list = ZEND_TYPE_LIST(type);
1993+
bool has_resolved_type = false;
1994+
/* We don't use ZEND_TYPE_LIST_FOREACH() as we need to keep track of the array index */
1995+
for (uint32_t i = 0; i < union_type_list->num_types; i++) {
1996+
zend_type single_type = union_type_list->types[i];
19861997

1987-
ZEND_TYPE_LIST_FOREACH(new_union_type_list, single_type) {
1988-
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*single_type) || (ZEND_TYPE_IS_INTERSECTION(*single_type)));
1998+
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(single_type) || (ZEND_TYPE_IS_INTERSECTION(single_type)));
19891999

19902000
/* Intersections types cannot have self or parent */
1991-
if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
2001+
if (ZEND_TYPE_IS_INTERSECTION(single_type)) {
19922002
continue;
19932003
}
1994-
if (ZEND_TYPE_IS_RELATIVE_SELF(*single_type)) {
1995-
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(*single_type));
1996-
memmove(single_type, &resolved_type, sizeof(zend_type));
1997-
}
1998-
if (ZEND_TYPE_IS_RELATIVE_PARENT(*single_type)) {
1999-
if (!ce->parent) {
2000-
zend_error_noreturn(E_COMPILE_ERROR,
2001-
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");
2002-
return (zend_type) ZEND_TYPE_INIT_NONE(0);
2004+
2005+
zend_type resolved_type = zend_resolve_name_type(single_type, ce);
2006+
if (zend_was_type_resolved(type, resolved_type)) {
2007+
if (!has_resolved_type) {
2008+
const zend_type_list *old_union_type_list = ZEND_TYPE_LIST(type);
2009+
union_type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(old_union_type_list->num_types));
2010+
memcpy(union_type_list, old_union_type_list, ZEND_TYPE_LIST_SIZE(old_union_type_list->num_types));
2011+
has_resolved_type = true;
20032012
}
2004-
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->parent->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(*single_type));
2005-
memmove(single_type, &resolved_type, sizeof(zend_type));
2013+
union_type_list->types[i] = resolved_type;
20062014
}
2007-
} ZEND_TYPE_LIST_FOREACH_END();
2015+
}
20082016

2009-
zend_type new_type = (zend_type) ZEND_TYPE_INIT_NONE(0);
2010-
ZEND_TYPE_SET_LIST(new_type, new_union_type_list);
2011-
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_ARENA_BIT;
2012-
/* Inform that the type list is a union type */
2013-
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_UNION_BIT;
2014-
return new_type;
2017+
if (has_resolved_type) {
2018+
zend_type new_type = (zend_type) ZEND_TYPE_INIT_NONE(0);
2019+
ZEND_TYPE_SET_LIST(new_type, union_type_list);
2020+
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_ARENA_BIT;
2021+
/* Inform that the type list is a union type */
2022+
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_UNION_BIT;
2023+
return new_type;
2024+
} else {
2025+
return type;
2026+
}
20152027
}
20162028

20172029
static void zend_resolve_trait_relative_class_types(zend_function *const fn, const zend_class_entry *const ce)
@@ -2037,7 +2049,7 @@ static void zend_resolve_trait_relative_class_types(zend_function *const fn, con
20372049
for (uint32_t i = 0; i < num_args + has_return_type; i++) {
20382050
zend_type type = new_arg_infos[i].type;
20392051
zend_type resolved_type = zend_resolve_single_type(type, ce);
2040-
if (type.ptr != resolved_type.ptr) {
2052+
if (zend_was_type_resolved(type, resolved_type)) {
20412053
if (!has_resolved_type) {
20422054
new_arg_infos = zend_arena_alloc(&CG(arena), allocated_size);
20432055
memcpy(new_arg_infos, fn->common.arg_info - has_return_type, allocated_size);

0 commit comments

Comments
 (0)